分散KVSの使い方

今流行のkey-value storageの利点と欠点など。小さいデータをたくさん扱うタイプで、単純なkey-value型のデータモデルを持つ分散KVSについて。
Webアプリをとりまく最近のKVS事情、雑感を読んで、ちゃんと整理して把握しておかないといけないな、と思ったので少し整理。
それは違うぞーという事があったらコメントくださいm(_ _)m

※2009-11-17 追記:現在、KVSという用語の意味は定義されておらず、使う人によって揺れています。ここで言うところの分散KVSは、Dynamo や kumofs や ROMA など を想定しています。

分散KVSの利点

  • スケールアウトできる
  • 簡単にサーバーを追加して性能を上げられる
  • 単体の性能が高い
  • スキーマレス

最初は少ない台数で安く、後からサーバーを足してスケールアウト!という運用ができる。アプリケーションに影響せずに、ストレージ側の都合だけで性能を向上させることができる。
負荷が想定していた以上に高くなってもサーバーを足すだけで何とかなるし、何より高いサーバーを買う必要がない。分散KVSを特徴付けるポイントは スケーラビリティが高い という点だと思う。


それから単体の性能が高いのもポイント。
RDBでもスケールするようにスキーマを設計していくと、JOINは使わないとか、shardingした全部のサーバーを横断するクエリは発行しないとか、だんだん貧弱なクエリしか使えなくなってくる*1
するとKVSに比べてサーバー1台の性能が低いのが気になってくる。RDBで1万QPS程度の性能しか出ないところを、KVSだと10万QPSくらい処理できたりするので、ただひたすらにkeyとvalueを低遅延かつ高スループットで取り出したいユースケースだと、KVSの方が嬉しい*2


こうして見ると、RDBをチューニングすれば足りるとか、あるいは高いハードやソフトを買うお金もあるし、最初から性能が予測しやすいからスケーラビリティもそれほど重要じゃないという場合は、分散KVSは不要。高いハードウェアを買ってきて、コア数に併せてOracle RACのライセンス料を払えば済む。
分散KVSは、負荷がサッパリ予測できない上にお金も無いWebサービスやオンラインゲーム向けだと思う。

分散KVSの欠点

分散KVSはデータモデルが貧弱すぎる。範囲検索もできなければ絞り込みもできない。
本当に連想配列としてしか使わない用途(キャッシュとか)なら何も考えずに分散KVSを使えば良いのだけど、そうでなければ基本的にはRDBと組み合わせて使うことになる。


具体的には、インデックスをRDBに置いて、データ本体を分散KVSに置く。スキーマ不定のデータをRDBに永続化する方法の比較の「friendfeedアプローチ」の図を見るとイメージが湧く。「データテーブル」の部分を分散KVSに置き換える*3


ここで、この方法でデータを格納しているときに、例えばRDBからインデックスを引いたら100件ヒットしたとする。次にその100件分のデータ本体を分散KVSから取り出そうとすると、全部のサーバーにクエリが飛ぶ(サーバーの台数が100台よりも十分少ないとき)。
これは分散KVSのほとんどの実装は、ハッシュ関数を使ってデータを分散させていることに起因する。できるだけすべてのサーバーにまんべんなく散らばるように設計されているため、多くのデータを一度に取り出そうとすると、多くのサーバーに散らばったデータを集めてくる必要がある。
1台のRDBサーバーにデータが全部集約されていれば、100件分のデータを取り出そうとしても1台のサーバーから取り出せばいい。データがソートされていればHDDをシークする必要もないため、高速に取り出せる。
つまり、関係性のある複数のデータを同時に取り出したい場合は、分散KVSはRDBに比べてサーバー1台あたりの効率が悪い。


分散KVSでも効率を上げたいなら、必要になるデータをあらかじめ作っておくのが基本で、例えば新しいデータを保存するときに検索済みの100件分のデータが入ったkeyも作っておく。ただこれが有効なのは検索する条件があらかじめ分かっている場合で、条件が不定だと難しい。それからトランザクションが使えないので、検索済みのkeyは非同期に作ることになる。厳密な一貫性が必要になるケースでは使えない。


分散KVSはこの効率の問題を、スケーラビリティに任せて力押しで解決する。100台でダメなら1,000台にすればいいじゃない!
そろそろ消費電力やラックの容量の問題が語られてもいいのかな、と思う。
分散KVSの中でも単体性能のチューニングは大事で、それによってサーバーの台数が10台になるか20台になるかに直接影響してくる。


ここで言うところの分散KVSには、BigTableやCassandraなどの、いわゆるMulti dimensional sorted storeは含めていない。
これらの分散データストアはkey-valueよりも高級なデータモデルを持ち、単純なKVSの効率上の問題を解決しようとしている。

*1:JOINや分散トランザクションはスケールしないとしても、使いたければ使えるのはRDBの優れた特徴だと思う。新参者には実装するだけで大変大変。

*2:JavaとかErlangとかRubyで実装されたKVSだと、単体性能が高いメリットは無いかもしれない…などと

*3:シリアライズ形式にはJSONよりもMessagePackがオススメ^^; YAPC::Asia 2009 Key Value Store with O/R Mapper