開発レポジトリが既にウェブに公開されています。レポジトリへのリンクはmemcachedのダウンロードページに載っています。
バイナリプロトコルの形式
プロトコルのパケット形式は24バイトの固定長フレーム、そしてその後ろにキーと値のUnstructured Dataが続きます。実際の形式は以下になります(プロトコル仕様書から引用):
ご覧の通り、パケット形式はかなり簡素な仕様となっています。この形式で気になる、16バイトも占領しているHEADERですが、HEADERはRequest用とResponse用の2種類が存在します。HEADERにはパケットの有効性を示すマジックバイト、コマンドの種類、キーの長さ、値の長さなどの情報が含まれ、以下の形式になっています:
各々の要素に関して詳しく知りたい場合は、memcachedのバイナリプロトコルの開発ツリーをチェックアウトしてdocsフォルダ内のprotocol_binary.txtという仕様書をご覧ください。
HEADERを見て気になる点
HEADERの形式を見て私が思ったことは、キーの限界値が巨大!ということです。現在のmemcachedの仕様ではキーの長さは250バイトまでという制限がありますが、バイナリプロトコルではキーのサイズが2バイトで表現される仕様になっています。したがって、理論上、最大65536バイト(216)までのキーが扱えることになります。250文字以上のキーを扱うユースケースはそう頻繁にないでしょうが、バイナリプロトコルがリリースされると巨大なキーも扱うことが可能になります。
バイナリプロトコルは次世代の1.3シリーズからサポートされます。
外部エンジン対応
実験的に、memcachedのストレージ層をプラガブルにするという改造を私が去年行ってみました。
この改造をMySQLのBrian Akerに見せたら、コードをmemcachedのメーリングリストに投げられ、試みが本家で気に入られロードマップに載せてもらいました。現在は同じmemcachedの開発メンバーのTrond Norbyeと共同開発(仕様策定から実装・テスト)でプロジェクトを進めています。海外との共同開発は時差が大変ですが、意気投合してプラガブルアーキテクチャのプロトタイプを公開することができました。レポジトリへはmemcachedのダウンロードページからいけます。
外部エンジン対応の必要性
世の中に多数存在するmemcachedのfork(派生)の理由は、パフォーマンスを多少犠牲にしてでも、データを永続的に保存したい・冗長性を実現したいなどの理由が述べられます。現に私もmemcachedの開発に関わる以前は、ミクシィのR&Dでmemcachedを再発明しようとしていた時期がありました。
外部エンジンのロードメカニズムでは、memcachedがネットワークやイベントハンドリングなどの複雑な処理を吸収してくれます。したがって、今まで力技やフルスクラッチでストレージエンジンをmemcachedと連携させていた苦労がなくなり、楽に色々なエンジンを試すことが可能になります。
簡素なAPI設計が成功の鍵
このプロジェクトで我々がもっとも重要視したことはAPIの設計です。ファンクションの数が多すぎるとエンジンデベロッパーに面倒な思いをさせてしまったり、複雑すぎるとエンジンを実装する敷居が高まってしまうという懸念があります。そこで第一バージョンのインターフェイスは13個のファンクションに留めました。詳しい内容は、長くなりすぎるので省略しますが、以下がエンジンに要求されるオペレーションです:
- エンジン情報(バージョンなど)
- エンジンの初期化
- エンジンのシャットダウン
- エンジンの統計情報
- 容量的に特定のレコードを保存する事が可能かの評価
- item(レコード)構造体のメモリ確保
- item(レコード)のメモリ解放
- レコードの削除
- レコードの保存
- レコードの回収
- レコードのタイムスタンプを更新
- 数値演算系の処理
- データのFLUSH
詳しい仕様に興味のある方はengineプロジェクトのコードをチェックアウトしてengine.hというファイルを覗いてみてください。
現状のアーキテクチャを見直す
memcachedを外部ストレージ対応にさせる点で難しいことは、ネットワークやイベントハンドリングを行うコード(コアサーバ)と、メモリストレージ系のコードが密着していることです。この現象をtightly coupledともいいます。現状のメモリストレージのコードをコアサーバから独立させられないと、外部エンジンのスマートな対応を行うことができません。したがって、我々は設計したAPIを基にmemcachedを以下のようにリファクタしました:
リファクタ後にバージョン1.2.5やバイナリプロトコル対応のビルド相手にベンチマークを取ってみたところ、パフォーマンスに影響がないことを確認しました。
外部エンジンのロードをサポートする過程で、concurrency controlをmemcachedに任せるソリューションが最も楽でしたが、エンジンにとってパフォーマンスの真髄はconcurrency controlにあるため、マルチスレッド対応は完全にエンジンが責任をもって行う設計にしました。
これらのハックによりmemcachedの可能性が広がればと思います。
まとめ
memcachedのタイムアウトの仕組みや、内部的にどうデータを削除しているかなどに加え、バイナリプロトコルや外部エンジン対応といったmemcachedの最新動向をご紹介しました。これらの最新機能が世に出るのはバージョン1.3からで、まだまだ先の話ですが、是非ご期待ください。
さて、今回が本連載で私の最後の出番です。ここまでお付き合いしてくださって誠にありがとうございます!
次回からは長野がmemcachedの運用ノウハウや互換アプリケーションなどを紹介します。