Redis、まだDELコマンドで消耗しているの?

公開:2020/11/09
更新:2020/11/14
2 min読了の目安(約1800字TECH技術記事

煽りタイトルですいません。

Redis のデータ削除によるブロッキング

Redis におけるクライアントからのデータ削除は、 v3 系までは DELFLUSHALLFLUSHDB がありました。

また Redis 自身による削除として、有効期限 (TTL) 切れ時の EXPIRE とメモリ溢れ時の EVICTION 、 Replica が Full Sync し直す際の flush がありました。

特に DEL コマンドや FLUSH 系コマンドは削除対象となるデータ数に比例して処理をブロッキングします。
SET 型や HASH 型で要素数が非常に多い場合は、 1 つの Key を DEL しただけでも数秒処理が止まることもあります。

Lazy Free 機能

Redis v4 以降から、 DEL に対応する UNLINK と FLUSH 系コマンドには async オプションが追加されました。
これらのコマンド・オプションはメモリを遅延解放するというものです。
これによりキー削除時にブロッキングを最小でデータ削除が行えるようになりました。

redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> UNLINK key1 key2 key3
(integer) 2
redis> GET KEY1
(nil)

トレードオフとして予測可能性の悪化があります。
Lazy Free では当然ながらメモリ解放の遅延により、一時的に Redis の消費メモリが跳ねうります。
十分なメモリの空き(=削除されるデータ量分程度)を確保できていれば、そのメモリでパフォーマンスが買える機能といえます。

また、 Redis 自身による EXPIRE や EVICTION 、 Replica の Full Sync 前の flush なども Lazy Free する設定も追加されています。

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no

※ yes にすると有効化される。

Appendix

アプリケーションの DEL を置き換えるのが大変な場合

Redis v6 からは、 lazyfree-lazy-user-del という設定値が増えました。
クライアントから DEL コマンドが発行されると、内部的には UNLINK と同様の処理をするというものです。
ソースコードを見てもわかるように、このフラグひとつで UNLINK 化します。

lazyfree-lazy-user-del no

※ yes にすると有効化される。

このフラグは CONFIG SET コマンドでオンラインに on/off 可能なため、アプリケーションを書き換える前に実験的に試してみるのも良いでしょう。

Lazy Free に関する議論

過去の議論が気になる方はこの Issue を追いかけると良いでしょう。
Lazy free of keys and databases · Issue #1748 · redis/redis · GitHub