mysqlのネタ話

初めまして、adwaysの孟です。

今日紹介したいのは、自分がプライベートで研究したちょっと面白い裏技です。
mysql普段の使い方みんな知ってますので、パスします~


今日の話題:mysqlとキャッシュサーバの連動

mysqlとキャッシュサーバのやりとり大体アプリケーション側でトリガーして、mysqlからcacheへ更新するパターンと、
cronかscriptで定期的にmysqlからpullしてキャッシュをウォーミングアップするパターンですね、(ほかもいろんなパターンあると思いますが。。。

アプリケーション側でトリガーするパターンだと、キャッシュへの更新タイミング一番早いですが、
アプリのロジックにキャッシュ更新ルールも一緒に書かないといけないです。
キャッシュの更新や削除など考える要素増えるので、プロジェクトの複雑度上がり、メンテナンスが面倒になります。
シンプルisベストですからね。

スクリプトからキャッシュサーバへのウォーミングアップするパターンもよく使われてるんです、
ウォーミングアップscriptの数が限られてるので、メンテしやすいがメリットです!
DBからデータ一括pullしてキャッシュへごにょごにょ更新するなんか便利ですね。
けど、欠点もいくつかあります。
① script動くタイミングが一定してますので、サーバの負荷が呼吸のように波が出てきます。
mysqlからpullしないとデータ更新されないので、データ量多いDBからすると、キャッシュサーバへの更新遅延が発生しやすくなります。
③ scriptがcronで動くかwhile(1)で動くか、scriptの実行管理がしなければいけません。面倒~


メンテナンスもしやすい、効率もいい、管理も手間かからない案世の中ないの?
あります!

mysqlのテーブルtriggerから直接キャッシュサーバへ更新すればいい」

mysqlのデータ更新された瞬間、キャッシュサーバへの更新も完了、これより早い方法がない。
キャッシュ更新ルール全部mysql中で管理できるので、メンテナンスしやすい、管理も便利ですね。
実際どこで使ったら便利か、例を用意しました。


例1:ユーザテーブルに、hogeという経験値上がりました。memcachedへ更新する。
select memc_set(concat("user_",NEW.id,"_hoge"),  NEW.hoge);
※ user_{ユーザID}_{属性} の形式でkeyを組み合わせて、値を書きます
※ memc_set(key,val,second)でも使えます。second秒後無効になります。 

例2:ユーザAとユーザB友達になりました。memcachedへ更新する。
select memc_set(concat("user_",NEW.id,"_",NEW.friend_id), 1);
※ user_{ユーザID}_{ユーザID} の形式で、キャッシュサーバにリレーションを作ります

例3:ユーザのhogeアイテム使い切った、memcachedに関連するデータを削除する。
select memc_del(concat("user_",NEW.id,"_hoge");
※ use_{ユーザID}_hogeというキーを削除します。

例4:ユーザの友達リストを表示しながら、このユーザの友達の友達数も一緒に取ります。
select *, (memc_get(concat("user_",friend_id,"_friendnum"))) as friendnum from user_friend
※ use_{ユーザID}_friendnumをselect中でfunctionとして取得します。
memcachedから事前に用意した友達数を読み取れるので、subqueryごとcountより当然速いですね!

こんな感じで使えます。
どうですか?
普段の3階層構造を一気に2階層まで減らしました。(DB->APP->CACHE => DB->CACHE)
最新状態のデータを取りたい場合、DBの代わりにmemcachedからでも安心して取れるようになったので、dbのselect requestが減り、ロックの発生率も当然減ります。
データがinsertや削除された同時に関連するmemcachedデータカウントアップやダウンができますので嬉しいです。(select countが重いですからね)
極端の性能を追求してる方、是非この方法を使ってみてください~

ただ、注意しなければならないこともあります。memcached壊れた時、リカバリー用のscriptで再度memcachedへのウォーミングアップする必要があります。まぁ、キャッシューサーバ使うことなら必須項目ですね。
 

memc_set,memc_get,memc_delのmysql functionのソースも用意しました。興味ある方是非開発環境で試してみてください。(memcachedサーバのIP直接ソースに書いてます、環境に合わせて調整してください)
推奨環境:centos 5/6(64bit), mysql 5.1以上、gcc, libmemcached, mysql-devel

ソースダウンロード:

※ build.sh (コンパイル用shell
※ memc_set.c
※ memc_get.c
※ memc_del.c

(※自分のプライベート研究なので、本番への導入ご検討してる方は自己責任になります、ご注意してください)。


次回の場合、nginxの裏技も紹介したいと思います~
ベンチマークツールすら追いつかない超爆速+冗長性も持つ、nginxのリバースプロキシで直接memcachedのデータを配信する方法)

以上!