PySpaアドベントカレンダー 22日目
はじめに
このエントリはPySpaアドベントカレンダーの22日目のエントリです。
PHPとかJavaがクソとか言うエントリではありませんのでご注意願います。
PySpaについて
まあ言うことはありません。ロビーでイリーガルな話やヒドいい話などをする合宿です。
コードとか二の次であってみんなの闇を共有する合宿です。
多分逮捕者がでてもおかしくないです。
最近作ってるもの
せっかくなので最近作ってるもの話をしておきます。
dismage
dismage - MySQL Protocol Server
要は MySQL Protocol を話す Server です。WSGI ライクなインターフェイスを持っています。
isucon 用に作りはじめたのがきっかけです。内部は libdrizzle で作られています。
全て非同期のAPIを使って実装されていますが、毎度のことながら greenlet でその辺を隠蔽してあるので使う人何も意識することはありません。
ほぼ C で書いてあるのでパフォーマンスはそれなりに出ます。
パフォーマンスをあげるためキャッシュなどをする場合、Web アプリケーション側に手が入ってしまったりするのですが(Middleware使えばいいのですが) それらをDB側の方へ追いやることができます。
サンプルコード
from dismage import *
from dismage import patch
patch.patch_all()
def app(cmd, cmd_data, start_result):
print("cmd:%s data:%s start_response:%s" % (cmd, cmd_data, start_result))
if cmd == COMMAND_INIT_DB or "COMMIT" in cmd_data:
return
columns = [(COLUMN_TYPE_VARCHAR, 10, 'name'), (COLUMN_TYPE_INT24, 8, 'age')]
start_result(columns=columns)
return [('john', 30), ('smith', 28)]
listen(port=3307)
run(app)
- cmd には COMMAND の種別が入ってくる
- cmd_data には SQL 本文が入ってくる
- start_result には SELECT 文で返す際の行の定義を設定する
上記の例だと以下のSQLを実行して結果を返しているようなイメージになります。
SELECT name, age FROM x;
SELECT 場合のみ start_result に返す行の定義を設定しますが、その他の場合には設定しなくてよいです。
返り値もNoneで返せばOKです。
非同期対応
socket にパッチがあたってるので pure python な 通信は非同期通信が行われます。
例えば内部キャッシュに無いデータを本来の MySQL へ問い合わせる(中継するイメージ)場合 pymysql などを使えば非同期で MySQL へ問い合わされます。
応用
まだ開発中ですが応用の用途としては以下のようなものがあります。
- テスト用の MySQL Sever として使う
- 複数の DB に同時に書き込む
- SQL を解析して自前で sharding する
- SQL を解析して一部の SQL を Hive に流す
- SQL を解析して一部の SQL を Impala に流す
- INSERT 文を解析して KVS にデータを入れる
- INSERT 文を解析して fluentd にデータを入れる
ドライバーによっては SQL かどうか判断していないので好きなデータを送信して処理することもできると思います。
(URL を送ってアクセスした結果を返すなどなど)
また WSGI Middleware のようなものも書けるので Middlwareで SQL の方言を直したり、フィルターをかけたりといったこともできます。
お手伝いしてくれる人など募集してます。
(特にlibdrizzleの認証とこに詳しい人)