TokyoCabinet のデータサイズは 64GB 付近で性能劣化

当ブログでサービスを提供している AmazonSearch ですが、子ども部屋の確保が最大の理由で、自宅サーバから sakura VPS 2G へ一ヶ月ほど前に移行を行いました。移行手順は以前もご紹介した、ブログをさくら VPS へ移行手順に準じて行いました。

AmazonSearch は内部計算が複雑なため、さくら VPS では QPS(queries per second)が 5-6 程度しかでません。したがって、高速化を図るためレスポンス結果を TokyoTyrant(TokyoCabinet)にキャッシュする仕様で実装を行っています。先日まで安定運用できていたのですが、RDB(casket-a.tch) のデータサイズが 64GB 付近に近づいた時点で性能が急激に劣化して高負荷でレスポンスが返せない事象が発生しました。ちょうど 2012/6/2 15:30 付近からです。

[tts@localhost tts_cache]$ ll
合計 64439492
-rw-r--r-- 1 tts tts 64001497584  6月  2 15:57 casket-a.tch
-rw-r--r-- 1 tts tts  1920080351  6月  2 15:57 log
-rw-r--r-- 1 tts tts           5  6月  2 15:56 pid
drwxr-xr-x 2 tts tts        4096  6月  2 15:26 ulog

load-6h.png

- スポンサーリンク -

ちなみに、自宅サーバ時代は SSD で高速であったため定期的に RDB を完全に破棄&再構築(つまり casket-a.tch を削除して ttserver を再起動)していたので問題は発生しませんでしたが、さくら VPS では HDD 性能が問題で RDB を破棄すると diskio が高騰してロードアベレージが 30-50 と停止しているにも等しい状態になるため、事実上キャッシュ破棄ができずにいました。

しかし 2G タイプはディスク容量が 200GB しかないため、ディスク容量の問題からプログラムの改修を行っていた矢先にこの問題が発生し、昨日は対応に追われていたところでした。

まず Tokyo Cabinet の 64GB 問題ですが、「TokyoCabinet 64GBの壁|CyberX:エンジニアブログ」で同じ話題を取り扱っていました。同様の問題はぐぐっても検索結果に出てこないので、知名度が低い問題のようです。

原因としては64bit環境で容量64GB以上のTokyoCabinetのデータファイルを扱うには、
HDBTLARGEオプションを指定する必要があるようです。

改めて Tokyo Cabinet の仕様書を読んでみると、こんな感じで記述されています。
Fundamental Specifications of Tokyo Cabinet Version 1 (Japanese)

The function `tchdbsetxmsiz' is used in order to set the size of the extra mapped memory of a hash database object.

bool tchdbsetxmsiz(TCHDB *hdb, int64_t xmsiz);
`hdb' specifies the hash database object which is not opened.
`xmsiz' specifies the size of the extra mapped memory. If it is not more than 0, the extra mapped memory is disabled. The default size is 67108864.
If successful, the return value is true, else, it is false.
Note that the mapping parameters should be set before the database is opened.

64GB と書かれてなくて、67108864 KB と書かれていますが、確かにデフォルトではハッシュDBは 64GB の制限があると書かれています。単位が KB だったのと、英語だったので、気がつかない&全然読んでませんでした。すいません!
対応策の #opts オプションについてもちゃんと書かれていました。

Fundamental Specifications of Tokyo Cabinet Version 1 (Japanese)

オプションとは、レコードの格納方法を指定するフラグの集合のことです。`HDBTLARGE' と `HDBTDEFLATE' と `HDBTBZIP' と `HDBTTCBS' と `HDBTEXCODEC' の論理和で指定します。`HDBTLARGE' を指定すると、バケットの個々の要素を8バイト(64ビット)で扱います。バケット配列のサイズが2倍になるかわりに、データベースのサイズの上限を8EBに引き上げます。`HDBTDEFLATE' を指定すると、レコードをDeflateアルゴリズムで圧縮してから記録します。大きいサイズ(だいたい256バイト以上)のレコードを圧縮して格納する場合に有利です。`HDBTBZIP' を指定すると、レコードをBZIP2アルゴリズムで圧縮して格納します。Deflateよりは遅いですが、圧縮率は有利です。`HDBTTCBS' を指定すると、レコードをBWT、MTF、Elias Gamma符号で圧縮して格納します。小さいサイズ(256バイト未満)のレコードを圧縮して格納する場合に有利です。`HDBTEXCODEC' は外部の圧縮伸長アルゴリズムを使うためのオプションです。具体的なアルゴリズムは隠しAPIの関数 `tchdbsetcodecfunc' で指定します。


この問題は Tokyo Cabinet 作者 mikio 氏のブログでも Kyoto Cabinet の設計思想の説明で断片的に取り扱われています。

開発メモ: 京都収納棚:DBMの率直な壱実装

TCでは通常モードで14バイト、ラージモードで22バイトのヘッダ領域をレコード毎に必要としていました。通常モードとラージモードの違いはレコードのアドレッシングのために4バイトの領域を使うか8バイトの領域を使うかの違いです。4バイトだと2^32=4GBまでの値を表せ、それにデフォルトアラインメントの16バイトを掛けた64GBまでのデータベースを扱えることになります。8バイトだと2^63=8EBまでのデータベースを扱えます。

開発メモ: ハッシュDBのレコードのフォーマット

レコードのアドレッシングをノーマルモードで4バイト、ラージモードで8バイトとして使い分けるのが面倒くさい気もしてきた。DBサイズの限界は4GBにアラインメントを掛けたものになるので、つまりデフォルトのチューニング(ノーマルモードで16バイトアラインメント)の場合は64GB以上のデータベースは扱えない。よって、それ以上の規模になりそうならラージモードにするかアラインメントを上げるかしなければならない。しかし、そのようなチューニングをちゃんとやってくれる注意深いユーザの割合はそれほど高くない。平均的なユーザは仕様書を隅から隅まで読んだりはしないのだ。

今回僕がとった対応方法は、さくら VPS 2G プランがそもそも disk 容量 200GB だったので全く別の方法ですが、それはまた別のエントリで解説します。とりあえず、いまから Key-Value やるなら Tokyo Cabinet じゃなく kyoto Cabinet を使っておいた方が良いのでしょうね。

- スポンサーリンク -