大对象的内存释放是一个会阻塞主线程的操作:删掉一个大集合,别的客户端就得等。Lazy Free 把释放挪到后台线程。这篇不重复 DEL 与 UNLINK 的区别(第 19 篇),而是量各个 lazyfree 开关到底改变了什么,包括默认值(在这个版本上出乎意料)和「过期删除」这条容易被忽略的路径。
lazyfree-lazy-user-del no lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no lazyfree-lazy-user-flush no replica-lazy-flush no
这个版本(8.10.2)上,所有相关的开关默认都是 no。也就是说不做任何配置时,DEL、过期删除、淘汰、清库都在主线程里同步释放内存。(不同版本的默认值可能不同,以 CONFIG GET 为准。)
方式 命令耗时 PING 最大停顿 (集合已建好:SCARD = 2000000 ,used_memory 61 MB) DEL(默认 lazyfree-lazy-user-del no) 165.0 ms 164.2 ms lazyfreed_objects=0 UNLINK 0.7 ms 0.2 ms lazyfreed_objects=1 DEL + lazyfree-lazy-user-del yes 0.4 ms 0.3 ms lazyfreed_objects=2
200 万成员的集合(used_memory 约 61 MB)。默认 DEL:165 ms,另一个连接的 PING 停顿 164 ms;UNLINK 或者开了 lazyfree-lazy-user-del yes 的 DEL:不到 1 ms。INFO memory 里的 lazyfreed_objects 记录被后台释放的对象数。
FLUSHALL 命令耗时 403.6 ms PING 最大停顿 0.2 ms lazyfree_pending_objects(命令刚返回后)见下 FLUSHALL ASYNC 命令耗时 0.4 ms PING 最大停顿 0.1 ms lazyfree_pending_objects(命令刚返回后)见下
300 万个小 key:FLUSHALL 命令本身 404 ms,FLUSHALL ASYNC 0.4 ms。有意思的是,同步 FLUSHALL 期间另一个连接的 PING 停顿也只有 0.2 ms——说明清库不是一次性阻塞到底(我没有查是不是分批清空时处理了事件)。所以清库和删单个大 key 的阻塞形态不同。
lazyfree-lazy-expire no 3 秒观察期内 PING 最大停顿 212.8 ms;bigexp 是否还存在 = 0 lazyfree-lazy-expire yes 3 秒观察期内 PING 最大停顿 0.5 ms;bigexp 是否还存在 = 0
给大集合设 500 ms 过期。lazyfree-lazy-expire no:到期时主线程同步释放,观察到另一个连接 PING 最大停顿 213 ms;yes:0.5 ms。这就是「大 key 过期造成周期性抖动」的来源(第 20、27 篇)。