redis-cli でメモリ使用量の多いキーを探すには `--memkeys` を使う
redis-cli
には --bigkeys
というオプションがあり、要素数の大きいキーや、型ごとのキー数の割合、平均サイズなどを集計してくれる。また --memkeys
というオプションもあり、こちらは要素数ではなく実際のメモリ使用量をベースに集計する。いずれも調査時などに自分でスクリプトで集計しなくても良いので便利。
--memkeys
はおそらく 5.0.4 で導入された オプションで、MEMORY USAGE コマンドの結果を集計してくれる。実際にどのキーがメモリを多く使っているかなどの調査には --bigkeys
ではなくこちらを使ったほうがよい。
--memkeys
は redis-cli, the Redis command line interface – Redis などの Web のドキュメントには記載が見つからず (cli のヘルプには記載があるが)、たどり着くまでに時間がかかったのでメモ。
出力のサンプルと見方
集計結果はこんな感じで出力される。
# bigkeys の例。memkeys も似たようなフォーマットで、要素数の代わりにメモリ使用量が出力される。
$ redis-cli --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
[00.00%] Biggest string found so far 'key-419' with 3 bytes
[05.14%] Biggest list found so far 'mylist' with 100004 items
[35.77%] Biggest string found so far 'counter:__rand_int__' with 6 bytes
[73.91%] Biggest hash found so far 'myobject' with 3 fields
-------- summary -------
Sampled 506 keys in the keyspace!
Total key length in bytes is 3452 (avg len 6.82)
Biggest string found 'counter:__rand_int__' has 6 bytes
Biggest list found 'mylist' has 100004 items
Biggest hash found 'myobject' has 3 fields
504 strings with 1403 bytes (99.60% of keys, avg size 2.78)
1 lists with 100004 items (00.20% of keys, avg size 100004.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
1 hashs with 3 fields (00.20% of keys, avg size 3.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)
# memkeys の場合はこんな感じですべて `with xxx bytes` 表記になる。
0 hashs with 0 bytes (00.00% of keys, avg size 0.00)
0 lists with 0 bytes (00.00% of keys, avg size 0.00)
0 strings with 0 bytes (00.00% of keys, avg size 0.00)
0 streams with 0 bytes (00.00% of keys, avg size 0.00)
0 sets with 0 bytes (00.00% of keys, avg size 0.00)
0 zsets with 0 bytes (00.00% of keys, avg size 0.00)
基本的には見たとおりだが、注意が必要なのは avg size
。この項目はその行で何を集計しているかに依存していて、常に平均のバイト数などが表示されているわけではない。例えば以下の --bigkeys
での hash 型の集計結果について、hash キーのフィールド数の平均が 3 という意味になる。(hash キーの平均メモリ使用量が 3 バイトと言う意味ではない)
1 hashs with 3 fields (00.20% of keys, avg size 3.00)
実装の詳細
実装は このへん。おおまかには SCAN で全キーを走査し、それぞれのキーの要素数やサイズなどを取得し集計している。
- まずキーの総数を DBSIZE コマンドで 取得
- SCAN でキーを走査しながら、それぞれについて要素数やメモリ使用量を取得 する
- それぞれ最大のキーと、これまでに走査した要素数、サイズの累計を計算していく
--memkeys
の場合、MEMORY USAGE コマンドの結果を 集計する--bigkeys
の場合、キーの型によって それぞれ以下のコマンドを使う- 例えば hash の場合
HLEN
の値を取得する
- 例えば hash の場合
# type, コマンド、単位
typeinfo type_string = { "string", "STRLEN", "bytes" };
typeinfo type_list = { "list", "LLEN", "items" };
typeinfo type_set = { "set", "SCARD", "members" };
typeinfo type_hash = { "hash", "HLEN", "fields" };
typeinfo type_zset = { "zset", "ZCARD", "members" };
typeinfo type_stream = { "stream", "XLEN", "entries" };
typeinfo type_other = { "other", NULL, "?" };
- 収集したデータを出力する
- キーの型ごとに最大の要素数・メモリ使用量だったキーを 表示する
- キーの型ごとにキー数、要素数・メモリ資料用、キー数の全体に占める割合、平均サイズを 出力する
--bigkeys
の場合、キーの型によって出力されるものが違う。例えば hash ならフィールド数など (上記参照)--memkeys
の場合すべてMEMORY USAGE
で調べたバイト数が表示される- 平均サイズ (
avg size
) は、単に 合計値をキー数で割っただけの値。例えば--bigkeys
の場合は平均の要素数 (hash のフィールド数など) であり、バイト数の平均ではないので注意
背景
- 運用している redis プロセスのメモリサイズが増加したことがあり、その調査をしていた
- 自分で集計スクリプトを書こうかと思っていたら、
redis-cli
にちょうどよく--bigkeys
というオプションが有ることに気づいてそれをまず使ってみた - 出力の見方がよくわからず、特に
avg size
にハマったavg size
はそのキーが使っている平均バイト数かと思ったが、計算してもプロセス全体のメモリ使用量と一致しなかった
- 軽く実装から追ってみると実は
--memkeys
という別のオプションがあとから追加されていることに気づき、こちらを使うのが正解だとわかった