📗
【データ指向アプリケーション要約】第6章 パーティショニング
5章の「レプリケーション」は同じデータを複数のマシンにコピーして、障害に強くしたり、読み取りを分散したりする話だった。
6章「パーティショニング」はそもそもデータそのものを分割して複数のマシンに置くイメージ。
これからパーティショニングの要点を押さえてまとめていく。
そもそもなんでパーティショニングするのか?
1. 大量のデータを収納したい
- 1台のサーバーに収まりきらないレベルのデータ量がある場合、分割しないと物理的に無理
- データベースの容量を拡張するとき、一台にどんどん大きいディスクを積むよりも、複数マシンに分散したほうが管理が楽だったりする
2. 高いスループットを目指したい
- 書き込みや読み取りの処理を、1台だけに集中させると負荷がヤバい
- データをうまく分割しておけば、それぞれのマシンが同時並行で処理できるから、全体の処理性能が上がる
3. レイテンシや地理的な要因を考慮
- 世界中のユーザーがいる場合、各地域ごとにパーティションを置いて、近いところにアクセスさせると速くなることもある
どうやって分割するのか?
分割の仕方はいろいろあるが、大まかにはキーとなるデータに基づいて振り分ける。
1. ハッシュパーティショニング
- データのキー(例えばユーザーIDとか)をハッシュ関数にかけて、得られた数値を元に「どのサーバーに置くか」決める方法
- たとえば「キーをMD5とかSHA-1でハッシュして、その結果の値 % パーティション数」で割り振るイメージ
メリット
- 均等に分散しやすくて、特定のサーバーだけデータが偏りにくい(=ホットスポットができにくい)
デメリット
- サーバー台数が増えたり減ったりすると、ハッシュの再計算が必要になったり、データの再配置が面倒
- 「連続したデータ範囲」を扱いたいときは不向き
2. レンジパーティショニング
- 例えば「ユーザーIDが1〜10000まではサーバーA、10001〜20000まではサーバーB」みたいに、キーの範囲ごとに割り振る方法
メリット
- 範囲指定のクエリ(「IDが100〜200のユーザー教えて」とか)は、その範囲に対応するサーバーにだけ問い合わせすればOKだから効率的
- データを人間が直感的に把握しやすい(「Aサーバーには1〜10000ね」みたいな)
デメリット
- 特定の範囲だけめっちゃアクセスされる(ホットスポット)が発生しやすい。
- 例えばユーザーIDが新しくなるほどアクセスが多いサービスだと、常に最新ID付近のサーバーが大忙しになるかもしれない
- レンジの見直しが必要になると、データ移動が発生して面倒
3. ディレクトリベースパーティショニング
- もう少し複雑に、「カスタムのテーブル」みたいなのを用意して、キーごとにどのサーバーにあるかを記録しておくやり方
- マスターテーブルが「このユーザーIDはサーバーXにあるよ!」と教えてくれるような構造
メリット
- 柔軟にパーティション決定ルールを変えられる
- 例えば「VIPユーザーだけ専用のサーバーに置く」みたいな特殊ルールも作りやすい
デメリット
- マスターテーブルの管理が大変。そこが障害起こすと場所が分からなくなって詰む
- 仕組みが複雑化するので、パフォーマンスと管理コストのトレードオフがある
パーティショニングでよくある悩み
1. ホットスポット
- 一部のパーティションだけにアクセスが集中すると、そのサーバーがオーバーヒートしてまう
- レンジパーティショニングで「新しいIDだけ超頻繁にアクセスされる」みたいなのが典型
2. 再パーティショニング(リバランス)が面倒
- ノード(サーバー)を増やしたり減らしたりすると、古いデータやルールを別のノードに移動しなきゃいけない
- このとき大量のデータが移動するから、サービスに影響出たりする
3. 複数パーティションをまたぐクエリが厄介
- 例えば「全ユーザーの平均年齢を計算して」とか、「特定の条件に当てはまるレコードを全部検索」みたいなのは、全部のパーティションに問い合わせる必要が出る
- 結果を集めて集計するのに手間がかかる
4. アプリケーションロジックが複雑化する
- どのパーティションにデータがあるか、アプリ側が把握して問い合わせしないといけないケースもある
- 「パーティショニングキー」を適切に設計するのがポイント
実際どうやって使うのか?
-
大規模サービスだと、すでにビルトインでパーティション機能を持ってるデータベースやNoSQLを使うことが多い
- たとえば、CassandraとかMongoDBとか、いろいろ自動でやってくれるのもある
- 自前でやる場合は、ハッシュパーティションやレンジパーティションの仕組みを考えて、データ配置や再配置の仕組みをガチガチに設計する必要がある
- そして、多くの場合はレプリケーションと組み合わせて、各パーティション内のデータも複数コピーしておく
- 要は「データを分割して分散配置しつつ、さらにコピーも持つ」ってこと
まとめ
- パーティショニング(シャーディング)は、データを物理的に分割して複数のマシンに配置することで、「大量データを扱う」「高いスループットを出す」って目的に役立つ
- やり方はいろいろ(ハッシュ、レンジ、ディレクトリベースなど)。どれも一長一短があって、アプリやアクセスパターン次第なところ
- 大変なところはホットスポットとか再パーティションとか。大規模になればなるほど気をつけないと運用が地獄になりがち
- 結局、レプリケーションとパーティショニングはセットで考えられることが多い。障害対策(レプリケーション)とスケールアウト(パーティショニング)を組み合わせる、ってイメージ
「データを小分けにして複数のサーバーでさばく」っていう基本を抑えておくだけでも設計の捉え方が少し変わった気がする。
Discussion