Webアプリをとりまく最近のKVS事情、雑感

RDB復権はしばらくないと思う

最近目にしたのは、「これからRDBが十分速くなっていくので、memcachedに代わってRDBがまた使われるようになる」という意見。これはしばらくの間は無いんじゃないかと思う。全データがオンメモリだったとしても、KVSはRDBより一桁以上速い(Memcachedで100,000req/sec出せるマシンで、MySQLのpkeyによる単純なSELECTをした場合、10,000req/sec出るかどうか)。SQLパーサやらなんやらを捨てない限りこの速さには対抗できない。RDBには、1コネクション1スレッドというモデルが持つ、接続数がスケールしないという制約もある。
また、memcacheプロトコルは、get_multiが使える。get_multiを効果的に活用した場合、RDBとの差はさらに広がると思う。

RDBで大丈夫なアプリも

Viewキャッシュが効果的なアプリ(blogタイプ)と、そうでないアプリ(SNSタイプ)で、RDBの遅さを許容できるかどうかが左右される。ちなみにLang-8は後者。以下後者のタイプを前提に話を進めます。

KVSなクラウドDBは?

GAEのBigtable, AmazonのSimpleDBあたりが利用できるけれども、レイテンシがかなり大きいとか。一クエリ10msとか普通にかかるらしく、これは許容しがたい。。当分はクラウド利用を諦めて、手元でサーバをセットアップして使うしかないのか。。

KVSストレージ

ストレージ側は今後いろいろ出てきそう。memcachedプロトコルが使え、耐障害性を持つ分散KVS、kumofsオープンソースで公開されるようなのでかなり楽しみ。

レンジクエリ?

KVS上でレンジクエリは利用できるのか? いろいろアイデアがあるようだが、今すぐにプロダクトへ採用できる状況ではなさそう。クエリの制約も大きく、SQLを代替できるものではない。
レンジクエリが使えない場合、インデックス構造自体をKVS上の1レコードとして持つ必要がある。これで案外いける。各レコードへの参照を並べるだけのListなので、アプリ側で適切に分割した場合、レコードサイズが1MB(Memcachedの制約)を超えることはまずない(例:Lang-8のフレンドリストや、個人ごとの最新日記リスト)
1MB以上になりそうな場合は、レコード末尾に続きのインデックスへの参照を置き、数珠つなぎに引っ張り出す等、アプリ側で工夫する。(泥臭い。。)

排他ロック

KVSをメインストレージに採用する場合、書き込みの競合によるデータ欠損を防ぐため、レコード単位でのmutexが必要。拙作KVS支援ライブラリ、SimpleResourceでは、ライブラリ側の機能として提供した。

スキーマレス

スキーマレスが普通になっていく。スキーマレスのメリットは非常に大きいSimpleResourceや、SimpleResource上で再構築したLang-8でも、すべてのレコードはスキーマレスにした。

RDBが部分的に補助

どうしてもKVSでは処理できない検索クエリだけRDBで処理するというスタイル。RDB上のデータはただのインデックスという位置づけであり、マスタデータではない。Lang-8の場合は任意のパラメータによる日記・プロフィール検索等でこのスタイルを使っている


トランザクション

諦める。関連する複数のレコードのうち一部だけ書き換えられても破綻しないように、アプリ側で工夫する。

バッチ処理

フルスキャンしなければいけないので、今までより圧倒的にIOコストが高い。関数型言語をうまく使ってMapReduceのようなことを手軽に(低いIOコストで)できないか考え中。