Redisでttlを指定していないキーを探し、削除する
1. はじめに
Redisを長く運用していると、いつの間にかSwap Usageが高騰したり、Freeable Memoryが枯渇してきて問題になることがあります。
そんなとき様々な原因が考えられますが、その一つにTTLを指定していないキーが容量を逼迫していたときの対処についてご紹介します。
2. Redis TTL とは
ttl コマンドでキーの有効期間を確認します。
有効期間を設定する場合は expire コマンドで指定します。
有効期間が設定されていないキーからは -1 が返ります。
存在しないキーからは -2 が返ります。
※Redis 2.6以前の場合は存在しないキーも -1 が返ります。
下記は使用例です。
> set key "hage" OK > get fuga "hage" // キーにTTL(単位はseconds)をセット > expire key 100 (integer) 1 // TTLを確認 > ttl key (integer) 98 > ttl key (integer) 95
3. TTLが指定されていないキーを探す
ざっくりとTTLが指定されていないキーの数を確認する場合は、 info コマンドが有効です。
ここでは2つのキー全てがTTL未指定ということになります。
% redis-cli -h localhost info Keyspace # Keyspace db0:keys=2,expires=0,avg_ttl=0
それぞれどのようなキーなのか、Luaスクリプトを作成して探します。
ファイル名は find.lua とします。
local t = {} local i = 1 for _, v in ipairs(redis.call('keys', 'prefix*')) do if redis.call('TTL',v) == -1 then t[i] = v i = i + 1 end end return t
実行
db指定は必要であれば。
% redis-cli -h [redis-host] -n 0 --eval find.lua
結果
標準出力にキーが羅列していきます。
1) "hage" 2) "hagee"
4. TTLが指定されていないキーを削除する
色々やり方はあるかと思いますが、TTLが指定されていないキーに対してdelコマンドを羅列するシェルを生成するスクリプトにしました。
ファイル名は del_output.lua とします。
local t = {} t[1] = "#!/bin/sh" local i = 2 local cmd = "redis-cli -h [redis-host] del " for _, v in ipairs(redis.call('keys', 'prefix*')) do if redis.call('TTL',v) == -1 then -- redis-cliのコマンドのターゲットをダブルクォーテーションで囲むため、keyの中のダブルクォーテーションをエスケープ local _v = string.gsub(v, '\"', '\\"') t[i] = cmd.."\"".._v.."\"" i = i + 1 end end return t
実行
シェルを生成します。
% redis-cli -h [redis-host] --eval del_output.lua > del_exec.sh % chmod 755 del_exec.sh % ./del_exec.sh
結果
削除が成功していくとこのように出力されるかと思います。
(integer) 1 (integer) 1 (integer) 1 (integer) 1 …
これでお掃除は完了です。
5. 最後に
運用期間が長いサービスだと、こういった作業が必要になることも出てくると思うので、キー毎に適切な有効期間を設定しておくことをオススメします。