kumofsはなぜスケールするか

先日、分散Key-valueストア kumofs公開しました
多く方から反響とフィードバックをいただいています。ありがとうございます。


今回は、kumofs はなぜスケールするのか、なぜスケールすると言えるのかーということについて紹介したいと思います。

ところでスケーラビリティとは何か?

スケーラビリティとは、利用者や仕事の増大に適応できる能力・度合い とされています(端的!)*1Scalability を日本語にすると、拡張性訳されるようです。

ただ一口でスケーラビリティと言っても、様々な側面があります。ITシステムでは主には処理性能と運用に関することを指す場合が多いと思いますが*2、その中にも様々な側面があります。

なぜスケーラビリティが必要か

スケーラビリティは システムなどが持つべき望ましい特性 であって、高いに越したことはありません。しかし、高いスケーラビリティはタダで実現できるものでもないので、スケーラビリティが「どのくらい」必要なのか、ということも考えておく必要があります。

高いスケーラビリティが必要になる理由には、例えば以下のようなものがあると思います:

負荷がとても高くなる
システムの負荷が高いとき、「チューニング」によって耐えられることもありますが、それでも負荷が10倍や20倍になったら耐えられません。チューニングでは早く限界に達してしまうため、チューニングのスケーラビリティはそれほど高くないと言えます。より高い負荷に耐えられる能力 が重要になります。
最初は負荷が低い
最初はデータが少なかったり、ユーザーが少なかったりします。最初から大規模なシステムを導入すると、無駄にコストがかかってしまいます。初期投資を抑えるためには、小規模でも高速に動作する能力 が重要です。
負荷の予測が難しい
システムにかかる負荷を事前に予測するのは、かなり難しい問題です。特に、不特定多数のユーザーからアクセスされるサービスだと大変です。必要になったときに すばやく性能を追加できる能力 が重要です。
稼働中に拡張が必要になる
いつ負荷が上がってくるかというと、システムが稼働している間に負荷が上がってきます。性能を追加できるのも重要ですが、その間にシステムが止まるのは困ります。できるだけサービスの動作を妨げずに性能を追加できる能力 が重要です。
規模に比例しない運用コスト
スケーラビリティを制約する原因は、ソフトウェアだけではありません。100台のサーバを管理するのに、1台のサーバを管理するのに必要な手間の100倍の手間かかっていたら、1人では到底管理できません。100人集めると100倍仕事ができるほど人間のスケーラビリティは高くないようなので(笑)、そのうちに運用コストの方がボトルネックになってきます。小さい運用コストで大規模化できる能力 が重要になります。

ここで挙げた能力は、どれもスケーラビリティの種類の1つだと言えます。どの能力を欠いていても、システムの拡張性を制限してしまう可能性があります。
性能以外のスケーラビリティは見落とされがちだと思いますが、運用や人間のスケーラビリティも無視できない要素だと思います。

kumofsのスケーラビリティ

kumofsは、先に挙げた能力がどれも高くなるように設計しています。

性能

kumofsは、サーバを追加するとほぼ線形に性能が向上していきます。今のところ、60台まではスムーズに性能が向上していくことを確認しています(これ以上は試したことがありません^^;)。
このスケーラビリティを得るためにkumofsでは、データを保存する担当のサーバを決める方法に、ハッシュ関数を使っています。データを保存したり取り出したりするときには、キーにハッシュ関数を適用して得られた値から、どのサーバが担当するかを計算します。


データを分散させる別の方法には、「範囲」を使う方法があります。例えばユーザーIDが0〜100のデータはサーバAに、ユーザーIDが101〜200のデータはサーバBに、といった具合で分散させます。
この「範囲」を使う方法だと、データの傾向に偏りがあったときに、負荷も偏ってしまうことがあります。例えば先のユーザーIDの例で、ユーザIDが0のデータに対するアクセスが多かったり、ユーザIDが0のデータが多かったりすると、サーバAの負荷がサーバBより高くなってしまいます。
負荷が偏ると、サーバBより先にサーバAがボトルネックなってしまったりするため、性能が伸びにくくなり、スケーラビリティが悪くなります。

小規模〜大規模

kumofsは、最小では2台で運用でき、2台でも十分に高い性能を発揮します。(一応1台でも構築できますが、耐障害性がないのでオススメしません)
以下のグラフは、1台で運用したときのkumofsの性能と、キャッシュサーバのmemcachedの性能を比較したものです。kumofsはサーバの台数が少なくても、memcachedにも劣らない速度で効率よく動作します。

動的な拡張

kumofsは、システムを動かしたままサーバを追加することができます。サーバを追加すると自動的にデータが再分配されるので、新しいサーバを接続したら、すぐに性能を向上させることができます。
これを実現するために、double-hash-space と命名したアルゴリズムを実装しています。新しいサーバを追加してデータを再分配している最中でも、読み書きを正常通りに行えるようにする仕組みです。double-hash-spaceについては紹介済みだったと思ったら、ブログではまだ書いていなかったので、また今度紹介したいと思います。

サービスの運用を妨げないインフラの拡張

kumofsは、サーバを追加しても、追加している作業中でも、kumofsを利用しているアプリケーションには一切影響しないように設計しています。アプリケーションを再起動したり再設定することなく、いつでもサーバを追加できます。

これには kumo-gateway が大きな役割を果たしています。kumofs-gatewayは、アプリケーションからのI/O要求をkumo-serverに転送するプログラムで、memcachedプロトコル(のサブセット)を実装しています。このkumo-gatewayをアプリケーションを動かすホスト上で起動しておくと、アプリケーションからは「localhostで動いているmemcachedサーバー」のように見えます。これはkumo-serverをいくら追加しても変わりません。つまり、kumo-gatewayは、アプリケーションからサーバの構成を隠蔽しています。

サーバの追加中でもkumo-gatewayが隠蔽してくれるので、アプリケーションには一切影響を与えずに、いつでもサーバを追加することができます。

運用

kumofsには、kumoctl(構成を取得・変更する)やkumotop(負荷をモニタリングする)といった管理ツールを用意しています。これらの管理ツールはどれも、多くのサーバを一括して扱えるように実装しています。サーバの台数が10台になっても20台になっても操作方法が変わらないので、規模が大きくなっても運用の手間が増えません。

kumotopを使うと、↓このように複数のサーバの負荷を同時に監視することができます。

スケーラビリティと耐障害性

スケーラビリティと耐障害性は切り離せない問題です。
サーバの台数を増やしていくほど、どれか1台のサーバが故障する確率が高くなっていきます。サーバの台数が多くなると、毎日どこかのサーバが故障するような状態に近づいていきます。このため、レプリケーションなどの耐障害性を高める機能を追加しないと、まともに動き続けられなくなってしまいます。
kumofsは、レプリケーションやConsistent Hashing、Virtual Nodeなどを使って、サーバが故障してもアプリケーションには影響しないようにしています。
kumofsの耐障害性については、また今度詳しく紹介したいと思います(たぶん^^;)。『雲の世界の向こうをつかむ クラウドの技術』 のコラムに少し書いてあるので、ぜひどうぞ。


※追記:続きを書きました:kumofsはなぜ落ちないか

*1:[http://en.wikipedia.org/wiki/Scalability:title=Wikipedia:Scalability]

*2:ハードウェアの世界では、どれくらい微細化して集積できるか、という意味でもスケーラビリティという単語を使うと聞いたことがあります。