Kyoto Tycoonのご紹介 FAL Labs info@fallabs.com
概要 軽量データベースサーバ RDBMSのような関係演算やSQLをサポートし ない代わりに、パフォーマンスとスケーラビリ ティを向上 毎秒数万クエリでも安定動作 いわゆるKey-Value Storeの一種 各種KVSは大規模Webサービスでの需要で発達 memcached (LiveJournal), Cassandra (facebook) Dynamo (Amazon), BigTable (Google), hBase (Yahoo) UNIX DBMのネットワーク化 軽量DBライブラリKyoto Cabinetを内蔵 Tokyo CabinetとTokyo Tyrantの再実装 mixi、GREE、NetVibes等で採用実績
機能 永続化キャッシュサーバ キャッシューサーバmemcachedの代替 オンメモリで高速に動作。メモリ使用量は 60%に削減 各レコードが指定時刻で自動削除 クライアントライブラリ主導の分散処理 永続化と高可用性 オンメモリDBだけでなく、ファイルDBが選 択可能 再起動時にもデータが消えない ホットバックアップ、更新ログ、レプリケー ション 複数サーバでデータを冗長化して迅速かつ 確実に障害対応 付加機能 トランザクションとカーソル 複数操作の一括適用や、レコードの順序操作 が可能 スクリプト言語拡張 Lua言語を内蔵し、任意の処理をサーバ側で 実行可能
インターフェイス プロトコル HTTPを採用し、どの言語とも連携可能 RPC方式とRESTful方式をサポート keep-alive接続により高速化 一部コマンドはバイナリプロトコルもサポート プラガブルサーバにより任意のプロトコルも実 装可能 API = プロトコルの隠蔽 C++言語用のAPIは標準添付 コマンドラインツールも標準添付 他言語対応は有志に委任 Perl版、PHP版、Ruby版、node.js版が存在 それ以外の言語では標準HTTPクライアントを 利用 RESTful方式を用いればライブラリ開発は容 易 memcachedモジュールも利用可能
HTTPの例 RPC方式でレコードを格納 RPC方式でレコードを検索 RESTful方式でレコードを格納 RESTful方式でレコードを検索 POST /rpc/set HTTP/1.1 Content-Length: 22 Content-Type: text/tab-separated-values key japan value tokyo HTTP/1.1 200 OK Content-Length: 0 RPC方式でレコードを検索 POST /rpc/get HTTP/1.1 Content-Length: 10 Content-Type: text/tab-separated-values key japan HTTP/1.1 200 OK Content-Length: 12 value tokyo RESTful方式でレコードを格納 PUT /japan HTTP/1.1 Content-Length: 5 Content-Type: application/octet-stream tokyo HTTP/1.1 201 Created Content-Length: 0 RESTful方式でレコードを検索 GET /japan HTTP/1.1 HTTP/1.1 200 OK Content-Length: 5 Content-Type: application/octet-stream tokyo
クライアント実装例 import time import urllib import http.client class KyotoTycoon: def open(self, host = "127.0.0.1", port = 1978): self.ua = http.client.HTTPConnection(host, port) def close(self): self.ua.close() def set(self, key, value, xt = None): if isinstance(key, str): key = key.encode("UTF-8") if isinstance(value, str): value = value.encode("UTF-8") key = "/" + urllib.parse.quote(key) headers = {} if xt != None: xt = int(time.time()) + xt headers["X-Kt-Xt"] = str(xt) self.ua.request("PUT", key, value, headers) res = self.ua.getresponse() body = res.read() return res.status == 201 def remove(self, key): self.ua.request("DELETE", key) return res.status == 204 def get(self, key): self.ua.request("GET", key) if res.status != 200: return None return body kt = KyotoTycoon() kt.open("localhost", 1978) kt.set("japan", "tokyo", 60) print(kt.get("japan")) kt.remove("japan") kt.close() require 'uri' require 'net/http' class KyotoTycoon def open(host = "127.0.0.1", port = 1978) @ua = Net::HTTP::new(host, port) @ua.start end def close @ua.finish def set(key, value, xt = nil) key = "/" + URI::encode(key) req = Net::HTTP::Put::new(key) if xt xt = Time::now.to_i + xt req.add_field("X-Kt-Xt", xt) res = @ua.request(req, value) res.code.to_i == 201 def remove(key) req = Net::HTTP::Delete::new(key) res = @ua.request(req) res.code.to_i == 204 def get(key) req = Net::HTTP::Get::new(key) return nil if res.code.to_i != 200 res.body kt = KyotoTycoon::new kt.open("localhost", 1978) kt.set("japan", "tokyo", 60) printf("%s\n", kt.get("japan")) kt.remove("japan") kt.close
レプリケーションの構成例 マスタサーバ (アクティブ) マスタサーバ (スタンバイ) データベース データベース クライアント 更新ログ ロードバランス 双方向レプリケーション (デュアルマスタ) スレーブサーバ スレーブサーバ スレーブサーバ スレーブサーバ データベース データベース データベース データベース 一方向レプリケーション (マスタ・スレーブ)
参考資料 公式サイト Kyoto Cabinet http://fallabs.com/kyotocabinet/ Kyoto Tycoon http://fallabs.com/kyototycoon/ クライアントライブラリ Perl版: http://search.cpan.org/~tokuhirom/Cache- KyotoTycoon-0.09/ PHP版: http://openpear.org/package/Net_KyotoTycoon Ruby版: https://github.com/uu59/kyototycoon-ruby node.js版: https://github.com/swdyh/node-kyoto- tycoon ブログ記事 memcachedとの比較 http://fallabs.com/mikio/tech/promenade.cgi?id=1 07 レプリケーション設定方法 http://fallabs.com/mikio/tech/promenade.cgi?id=1 08 バイナリプロトコルの詳細 http://fallabs.com/mikio/tech/promenade.cgi?id=1 10