PostgreSQL日記

アクセスカウンタ

zoom RSS 鋭意開発中!pgpool-IIのオンメモリクエリキャッシュ機能

<<   作成日時 : 2011/12/17 09:44  

ブログ気持玉 0 / トラックバック 0 / コメント 0

皆さん大変お久しぶりです。
今回の記事はPostgreSQL Advent Calendar 2011への参加企画ということでお送りします。「Advent Calendar」とは、本来12/1から12/25のクリスマでの日めくりカレンダーですが、そこから派生して、特定のお題(もちろんここではPostgreSQL)に関して順番に記事を書いていくというものです。

さて私のお題ですが、pgpool-IIという、PostgreSQL用のクラスタソフトに関するお話です。

オンメモリクエリキャッシュとは


pgpool-IIは、オープンソースで公開されており、誰でも、どんな目的にも無償で利用できます。pgpool-IIの機能は、レプリケーションや負荷分散など非常にたくさんあるのですが、今回ご説明するのは現在開発中の新機能「オンメモリクエリキャッシュ」で、簡単に言うと検索クエリを実行した結果をメモリ上に保管しておいて、後で同じクエリが来た時に再利用することによって処理を高速化するというものです。

たとえば、手元の75万件、2.8GBほどのテーブルの行数を SELECT count(*) FROM ... を使って検索すると4秒近く(正確には3923ミリ秒)かかるのですが、これがクエリキャッシュにヒットすると、0.13ミリ秒と、何と3万倍以上のスピードアップになります(ちなみに、私の環境ではDBがSSD上に置かれているのでこの程度ですが、磁気ディスクならもっと差が広がります)。この違いは、2次記憶装置から検索するのか、メモリからデータを持ってくるのか、の違いだけで説明できません。手元のマシンにはメモリが8GB搭載されており、同じクエリを続けて実行するとほとんどすべてのテーブルのデータがカーネルのメモリキャッシュから読み出されることになるのですが、それでも280ミリ秒ほどもかかります。これはPostgreSQLがSELECT count(*)を処理する際にテーブルの行をすべて読みだす必要があるからで、75万回分のCPU処理に280ミリ秒かかっているわけです。

クエリキャッシュの欠点


一方で、クエリキャッシュには欠点もあります。まず当たり前ですが、一回目のクエリの実行時にはキャッシュがないので実行は速くなりません。むしろ、キャッシュへの登録などがオーバヘッドにより、遅くなります。次に、キャッシュは適当なタイミングで消去で削除されなければなりません。よくある手法は、DBの更新時にキャッシュを削除するというものです。よって、更新の多いシステムではクエリキャッシュはあまり効果がなく、オーバヘッドだけが目立ってしまうことになります。

MySQLのクエリキャッシュ


クエリキャッシュを備えたDBMSというと、MySQLが有名です。MySQLでは、クエリ結果をキャッシュし、次に前回と同じクエリ文字列を使用する問い合わせが来た時にキャッシュから結果を返すという方法を取っています。キャッシュを消すタイミングは、テーブルの更新です。テーブルが更新されたら、それを使っているキャッシュはすべて削除します。pgpool-IIでも、キャッシュの登録、キャッシュの削除は同様の方法を取ることにしました。

MySQLとの一番大きな違いは、キャッシュの管理をDBMSではなく、pgpool-IIというミドルウェアで行っていることです。MySQではキャッシュが効く場合でも、MySQL自体にアクセスがいくので、軽いはとは言え負荷がかかります。一方pgpool-IIでは、キャッシュが効く場合にはPostgreSQLはアクセスされず
、負荷が0です。DB負荷で悩んでいるシステムではこれは嬉しいはずです。

クエリキャッシュの動作を実際に試してみる



では、実際にpgpool-IIのクエリキャッシュを試してみましょう。pgpool-IIはWindows以外なら大抵のプッラットホームで動きます。ただし、pgpool-IIが接続するPostgreSQLを用意しておく必要があります。バージョンは8.0位から後なら大丈夫です。PostgreSQLはWindowsで動いているものでも構いません。ここでは、Linux上の PostgreSQL 9.1.2 で検証しています。

ソースコードはPosgreSQLコミュニティのgitサーバで管理されており、"shortlog"セクションの一番上の右にある「snapshot」のリンクからtar ballがダウンロードできます。展開したら、"./configure"、"make", "make install"でインストールできます。標準のインストール先は /usr/local/bin ですが、configure 時に "--prefix" オプションでインストール先が指定できます。簡単に試すだけなら、自分のホームディレクトリを指定してもよいでしょう。また、pgpoolの実行にはroot権限は必要ありません。

次に、設定ファイル /usr/local/etc/pgpool.confを作成します。

cd /usr/local/etc
cp pgpool.conf.sample pgpool.conf


pgpool.confの項目は多数ありますが、クエリキャッシュの機能を試すだけなら以下の設定で十分です。
ここで、"host1"はPostgreSQLが動いているホスト名です。PostgreSQLと同じホストでpgpool-IIを動かす場合は、空文字にしてください。memqcache_oiddirは標準で /var/log/pgpool/oiddir ですが、pgpool-IIの起動ユーザが書き込めるところならどこでも構いません。

backend_hostname0 = 'host1'
backend_port0 = 5432
memory_cache_enabled = on
memqcache_oiddir = '/var/log/pgpool/oiddir'
pid_file_name = '/tmp/pgpool.pid'
log_per_node_statement = on

早速pgpoolを起動してみましょう。

/usr/local/bin/pgpool -n >/tmp/log 2>&1 &

うまく起動できれば、/tmp/logに
2011-12-13 08:48:42 LOG: pid 31194: pgpool-II successfully started. version 3.2alpha1 (hatsuiboshi)

というメッセージが出ているはずです。早速pgpool-IIに接続してテーブルを登録、データを入れてみましょう。

psql test
[t-ishii@localhost test]$ psql -p 9999 test
psql (9.1.2)
Type "help" for help.

test=# create table t1(i int);
CREATE TABLE
test=# insert into t1 values(1);
INSERT 0 1

では次に今登録したデータを検索してみます。

test=# select * from t1;
i
---
1
(1 row)

このとき、pgpool-IIはこの検索結果をキャッシュに登録して次回の利用に備えているはずです。ログで確認してみます。

2011-12-13 08:51:55 LOG: pid 31227: DB node id: 0 backend pid: 31306 statement: select * from t1;
2011-12-13 08:51:55 LOG: pid 31227: pool_hash_insert: hash_key:119249 md5:48cdd1d127d1c23d049197d6ad9a2032 block:0 item:3

ログの一番最後にこのような行があるはずです。上の行は、log_per_node_statementの設定があるので、ユーザが入力したSQLをpgpool-IIが表示しています。
下の行は、デバッグ用の出力で、検索結果をキャッシュに登録したことを示しています。
ではもう一度同じSQLを実行し、ログを確認してください。

2011-12-13 09:04:42 LOG: pid 31227: query result fetched from cache. statement: select * from t1;

今度はこのようなログに変わり、キャッシュから検索結果を取得していることがわかります。
ちなみに、1回目のSELECTと2回目のSELECTの間が空き過ぎると、キャッシュが無効になってしまいます。これは、pgpool.confで

memqcache_expire=60

が指定されているからで、ここでは60秒を経過したキャッシュを無効としています(memqcache_expireを0にすればキャッシュのタイムアウト機能は無効になります)。

なお、キャッシュを使うかどうかの判定は、機械的にSELECT文の文字列だけで判断しているので、大文字小文字が違ったり、空白の数が違うとキャッシュが効きません。毎回SELECT文をパースすれば融通を利かすこともできるのですが、それでは「スピード命」のキャッシュの意味がなくなってしまい、本末転倒です。

キャッシュに関する統計情報


キャッシュの管理で重要なのは、前述のようにキャッシュのヒット率です。show pool_statusコマンドを使ってキャッシュのヒット状況を見ることができます。

psql
:
:
show pool_status;
:
:

memqcache_no_cache_hits | 12 | Number of SELECTs not hitting query cache
memqcache_cache_hits | 1 | Number of SELECTs hitting query cache
:
:

ここで、「memqcache_no_cache_hits 」は、キャッシュにヒットしなかったSELECT文の回数、「memqcache_cache_hits 」はキャッシュにヒットした回数を表しています。

キャッシュしてはいけないSELECT結果


どんなSELECT結果でもキャッシュして良いわけではありません。たとえば、

SELECT current_timestamp;

はキャッシュできません。キャッシュしてしまったら、いつも同じ時刻が返るようになってしまいます:-)一般に、実行のたびに結果が異なるような関数を含むSELECT結果はキャッシュできません。そのため、pgpool-IIでは、「immutable」でない関数を含むSELECT文はキャッシュの対象から外しています。また、一時テーブルを使うSELECTはキャッシュできません。

アボートしたトランザクションに含まれるSELECT結果もキャッシュできません。そこで、明示的なトランザクション実行中はSELECT結果を一時的なバッファにためておき、トランザクションがコミットした時にはじめてキャッシュに登録するようにしています。

キャッシュのアクセス権


PostgreSQLでは、権限設定により、テーブルを検索できるユーザを制限できます。しかし、キャッシュした後はアクセス権のことまではわからないので、キャッシュ経由で本来アクセスできないはずのテーブルがアクセスできてしまう可能性があります。そこでSELECT文の他にユーザ名を覚えておき、同じユーザでなければキャッシュを使えないようにしています。これはちょっともったいないのですが、キャッシュ利用が多いと想定されるWebシステムでは、同じユーザを使うことが多いので、あまり問題にならないと考えています。

memcachedを使ってみる


pgpool-IIのオンメモリクエリキャッシュは、デフォルトで共有メモリを使いますが、 memcached を使うこともできます。memcachedは広く使われている分散型のメモリキャッシュサーバです。pgpool-IIで、共有メモリではなくmemcchedを使うメリットは、1) 共有メモリでは足りないような大量のメモリをキャッシュとして使いたい 2)1台のmemcachedを複数のpgpool-IIがキャッシュサーバとして共有して使うことにより、より効率的なキャッシュ利用ができる、ということにあります。

memcachedを利用するためには、memcachedのインストールはもちろん必要ですが、memcachedにアクセスするためのlibmemcachedというライブラリが必要です。pgpool-IIはデフォルトではmemcachedを利用できるようになっていないので、configureからやり直しましょう。rpmでlibmemcachedが利用できるシステムでは、以下のようにします。

./configure --with-memcached=/usr

そして、make, make installしてください。後は、pgpoo.confの

memqcache_method = 'shmem'



memqcache_method = 'memcached'

に書き換え、pgpool-IIを再起動します。後は使い方は共有メモリの時と同じです。

今後の予定


pgpool-IIのオンメモリクエリキャッシュは開発途上であり、現時点(2011/12)では、JDBCドライバから利用できないなどの制限事項がありますが、制限事項はなるべくなくし、更にメモリキャッシュの有効/無効をテーブル単位で可能にするなど、改良を重ね、2012年の6月くらいまでにはpgpool-II 3.2としてリリースしたいと考えています。


テーマ

注目テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
本 文
鋭意開発中!pgpool-IIのオンメモリクエリキャッシュ機能 PostgreSQL日記/BIGLOBEウェブリブログ
文字サイズ:       閉じる