Redis Cluster、もはやベイパーウェアではない
原文は Salvatore Sanfilippo により に公開されました。 このブログを購読する
gitの履歴の中でRedis Clusterについて見つけられる最初のコミットは2011年3月29日付けのものだが、これは「コピー&コミット」によるマージだ。クラスターブランチの履歴は失われている。当時はAPIやシステムの他部分との連携に関する初期のアイデアを形にするための、作業途中のコミットがごちゃごちゃと積み重なったひどい状態だったからだ。
つまり、これはおよそ4年にわたるプロジェクトということになる。Redisプロジェクト全体の歴史の約3分の2に相当する。それにもかかわらず、Clusterサポートを備えた最初のバージョンであるRedis 3.0.0の、最初のリリース候補をリリースするのがようやく今日になったのだ。
紆余曲折の道のり
なぜこれほど時間がかかったのか、その理由は明快だ。私がClusterプロジェクトをかなりの急ぎ足で始めたのは、自動的にスケールする手段がなければRedisはまったく役に立たなくなるように見えた時期だったからだ。しかしそれはClusterに着手するには早すぎた。単純に、Redis自体がまだ未熟で、まだ「シングルインスタンス」として語れる確固たるストーリーを持っていなかったからだ。
タイミングを誤ってプロジェクトを始めてしまったのは確かだが、少なくともコミュニティから寄せられる要望を無視するという罠には陥らなかった。そのため、より根本的な機能にリソースを割くために、Clusterプロジェクトは何度となく中断された。永続化、レプリケーション、レイテンシ、イントロスペクションといった機能は、Clusterよりもはるかに多くの手がかけられた。単純に、それらの方がユーザーベースにとって重要だったからだ。
プロジェクトのもう一つの制約は、開始当時の私は分散プログラミングについてまったく分かっていなかったことだ。最初の設計はひどい出来で、プロダクトとしての要件である「低レイテンシ、リニアなスケーラビリティ、小規模クラスタでのオーバーヘッドの小ささ」だけはうまく捉えていたものの、詳細はすべて間違っていた。必要以上に複雑で、使われていたアルゴリズムは安全ではなく、といった具合だった。
少しずつ前進しながら、私は分散プログラミングの基礎を学び始め、Redis Clusterを再設計し、同じ考え方を新しいバージョンのSentinelにも適用した。両方のシステムで使われている分散プログラミングのアルゴリズムは今でも原始的なままだ。どちらも非同期レプリケーションで結果整合性(eventual consistency)のシステムであり、合意形成(コンセンサス)のような非自明な問題に対処する必要がなかったからだ。しかし、少なくともCPストアを書くことに比べれば単純な問題に取り組む場合であっても、自分が何をしているのかを理解していなければ、出来上がったシステムはまったく誤ったものになりかねない。
こうした問題を抱えながらも、私はプロジェクトに取り組み続け、修正し、実装を直し、成熟させようとしてきた。なぜなら、Redisコミュニティ全体に、小さな部屋の中の象のように横たわる、ごく単純な事実があったからだ。それは、人々が自らの労力で、何度も何度も、しかも多くの場合まったく壊れたやり方で、次の二つのことを行っていたという事実だ。
- データセットをN台のノードにシャーディングすること。
- 特定の障害を乗り切るための、応答性の高いフェイルオーバー手順。
問題の「2」はあまりにも深刻で、ある時点で私はClusterが完成する前にRedis Sentinelプロジェクトを立ち上げることにした。できるだけ早くHA(高可用性)システムを提供するためであり、しかもそれは「1」を必要とせず「2」だけを必要とする大多数のユースケースにとって、Redis Clusterよりも適したものだったからだ。
ようやく、この取り組みの最初の現実的な成果が見え始めている。そして今、私たちはリリース候補を手にした。これは普及を促し、残ったバグを修正し、より漸進的な方法でシステムを改善していくために不可欠なマイルストーンだ。
実際には何をするのか?
Redis Clusterは基本的にデータのシャーディング戦略であり、クラスタ稼働中にキーをあるノードから別のノードへリシャーディングする機能と、特定の種類の障害をシステムが切り抜けられるようにするフェイルオーバー手順を備えたものだ。
分散データベースの観点から見ると、Redis Clusterはパーティション発生時に限定的な可用性と、弱い一貫性を提供する。基本的に、それはCPでもAPでもない。言い換えれば、Redis Clusterは、現実世界でのある種の特性を得るために、分散システムで理論上可能な限界までは到達していない。
一貫性モデルは有名な「結果整合性(eventual consistency)」モデルだ。基本的に、パーティションによってノード間の同期がずれても、パーティションが解消すれば、あるキーを担当するすべてのノードがその値について合意することが保証される。
ただし、マージ戦略は「最後のフェイルオーバーが勝つ(last failover wins)」であるため、ネットワークパーティション中に受け付けた書き込みは失われる可能性がある。典型的な例は、マスターがクライアントからの書き込みを受けつつ、少数派側のパーティションに分断された場合に何が起こるかだ。パーティションが解消したとき、多数派側でスレーブが昇格してそのマスターを置き換えていたなら、旧マスターが受け付けた書き込みは失われる。
これは裏を返せば、Redis Clusterは値のマージを試みるためにデータ構造内にメタデータを持つ必要がなく、Redisがサポートする多彩なコマンドやデータ構造がそのままRedis Clusterでもサポートされることを意味する。つまり、追加のメモリオーバーヘッドもなく、APIの制限もなく、値に含められる要素数の制限もないが、その代わりパーティション時の安全性は低くなる。
Redis Clusterのように設計されたシステムでは、ノード間で乖離が起きるのは望ましくないことは自明であり、そのためシステムは2つのノードが乖離する確率(および乖離の量)を制限することで、欠点を緩和しようとしている。これはいくつかの方法で実現されている。
- パーティションの少数派側は利用不能になる。
- レプリケーションは、通常クライアントへの応答とスレーブへのレプリケーションストリームが同時に送信されるように設計されている。
- マスターをフェイルオーバーする際に複数のスレーブが利用可能な場合、システムは障害が発生したマスターとの乖離がより少ないと思われるスレーブを選ぼうとする。
これらの戦略はシステムの理論的な特性を変えるものではないが、一般的なRedis Clusterの障害モードに対して、より現実的な保護を加えるものだ。
RedisのAPIやユースケースにとって、この設計は理にかなっていると私は考えているが、過去には多くの人が同意しなかった。しかし私の考えでは、設計者は誰でも好きなようにシステムを設計する自由があり、ただ一つのルールは「真実を語ること」だ。だからこそRedis Clusterは、その限界や障害モードを公式ドキュメントで明確に文書化している。
システムが有用かどうかを決めるのは、ユーザーと目の前のユースケースだ。私の実感では、6年間もの間、クラスタリングのサポートがまったくないにもかかわらずユーザーがRedisを使い続けてきたのは、ユースケースがそれを可能にし、Redisが特定の問題を解決するのに非常に適した特有の機能と性能を提供していたからだ。Redis Clusterが、そうした多くのユーザーの生活をより良くしてくれることを願っている。
これからの道のり
ようやく私たちは出荷可能な最小限のプロダクト(MVP)を手にした。ユーザーが真剣にテストを開始し、場合によってはすでに採用できるほど十分に安定したものだ。採用が進めば進むほど、私たちはそれを改善できる。これはRedisやSentinelでの経験から分かっていることだ。ここからは、ソフトウェアを使える段階から成熟した段階へと進める漸進的なプロセスが始まる。ユーザーの声に耳を傾け、バグを修正し、テストでより多くのコードをカバーする、といった具合に。
同時に、私はRedis Clusterの次期バージョンについても考え始めている。v1を、現時点では追加できなかった多くの有用な機能で改善するのだ。例えば、マルチデータセンターのサポート、コマンドリプレイによる少数派パーティションでの書き込み安全性の向上、自動的なノードバランシング(現在は、一部のノードが空すぎたり他がパンパンだったりする場合に手動でリシャーディングする必要がある)、その他多くのことだ。
さらに、Redis Clusterはキャッシュ専用に設計された特別な実行モードの恩恵を受けられると考えている。そのモードでは、少数派パーティションでも利用可能であり続けるために、ノードが自分が担当していないハッシュスロットへの書き込みも受け付ける。
実装や設計を改善し修正する時間はいつでもある。しかし、ソフトウェアをどうあるべきかという理想にこだわりすぎると、必要以上に長い間ベイパーウェアのカテゴリーに留めてしまうリスクがある。解き放つ時が来たのだ。Redis Clusterを楽しんでほしい!
Redis Cluster RC1は、GitHubの「3.0.0-rc1」タグとしても、またhttp://redis.io/downloadのRedis.ioダウンロードページにあるtarballとしても入手可能だ。
記事をランダムに読む
コメント
ログインしてコメントする