マイグレーションしたらsparkの処理速度が3倍になった
チャットワークとは
- 説明不要
- 国内最大手
データマイグレーション
システムマイグレーションに付随
- メッセージングシステム部分の大刷新
- 並列分散システム化
- トランザクションに依存しない
- HBase(RDBMS to NoSQL)
- ScalaMatsuriでシステムマイグレーションのお話をした
アーキテクチャ
- akka(spallowforwarder readAPI writeAPI updater)
- kafka
- HBase
今回の話は、AuroraからHBaseへのマイグレーション
17億メッセージデータ
- 新たに「ルームで何番目の発言か」をフィールド上で算出(計算)
工数書けない
Spark
- MR
- エキスパートの存在と安定性が理由でSparkをとった
- SparkからHBaseへのバルクロードが可能
- 大量データアップロードはバルクロード一択
- EMR
- Spark実行環境
- 試験用環境
- Auroraのバイナリログを読むためのmysql-binlog-connector-java
- concourse
- jenkinsみたいなもの
柔軟で安全なマイグレーションのために
戦略
- 基本マイグレーション
- 全件のマイグレーション
- 差分マイグレーション
- 前回以後の差分をマイグレーション
基本 + 差分のコンボ
Spark
- HBase-Sparkで書き込み
- binlogからメッセージテーブルへ
- 直接イベントとして取得する
- 定期 or 手動でスナップショットをとる
- 復元してマイグレーションと差分検証する。Productionへの負荷はない
- Auroraのbinlogを使うときは復元するときにrotateする
- rotate以外にも本番とその復元DBとでやりたいことに差がでないか検証する
- EMRを使うと、スケールアップ/スケールアウトが簡単 札束で殴ればなんとかなる
安心安全なマイグレーションのために
- メトリクスをしっかりとる
- DBの急激な変化に気をつける
- マイグレーションできてもDBの異常は検知する
Sparkアプリケーションの高速化
- Sparkの仕様への理解
- shuffleは高コストなので避ける
- RDDのPartitionを意識する
- Custom Partitioner
- RDD#mapPartitionsメソッド
- Partionerの保持
- RDDでゴリゴリやるのが適してた
データの特性の把握
- 基本マイグレーションPartition戦略最適化
- データがどのノードにあるのかを意識する
- ナイーブな実装 one Partition one Room
- データのソートとカウントすればRoom単位の処理になる
- 粒度が細かい→Auroraの読み込みスループットが上がらない
- one partition n room
- 複数のルームがはいる
- roomIdでgroup byするとシャッフルが発生する→無駄
- one partition n room
- ソートとカウントしたあとで、データをregion単位でrepartitionする
- HBaseContext.scala:791 repartitionAndSortWithinPartitions
- 分散配置のルールに従って移動する必要がある
- SparkのパーティショニングをHBaseと揃える
- 1ノードにつき1RegionServer
- 1 partitionあたり1 regionにするとshuffleするけど軽い
- (RDDの型がPair型じゃないといけないので、Valueに適当なダミーを割り当てる必要がある)
負荷の偏りをかいけつする
- 基本マイグレーションの高速化はそれなりでよい
- データ分布に基づくケアでバランスを取る
事前パーティショニングが検証時に活躍
- HBase/Auroraの突き合わせ
- Aurora HBaseのデータが同じパーティションに配置されるようなCustomPartitionerを最適化
そのほかこまいこと
- HBaseはpre-splitしていること
- Region数が少ないとSparkクラスタサイズを大きく出来ない
- ルーム分布のケースなので必ずしも汎用的じゃない
まとめ
- Shuffleを減らす or 軽くする
- Partitionの単位を工夫
- Custom Partitionerの全体ロジックを検討
各ワーカーの負荷を均等に
binlogによるストリーミングマイグレーションとかはやりたかった
トラブル
- copyがタイムアウトでひたすらリトライ→権限付与で解決
- HBaseのレアなバグ
- 大きいデータを使うと踏む
- 1.2.1で修正されていたバグ