建一个423MB的大hash,对比DEL和UNLINK的自身耗时,以及测量它们对并发客户端造成的阻塞影响,看异步释放到底省在哪。
DEL和UNLINK看起来都是"删掉这个key",的区别在删除这个动作本身花了多久、以及花的时间算在谁头上。
建的keyHSET 500万个字段到bighash_del MEMORY USAGE bighash_del → :423441162字节(约423MB)
同样大小的key,分别复制一份,一个用DEL一个用UNLINK。
结果DEL耗时: 0.8499 s UNLINK耗时: 0.0002 s
差了约4250倍。DEL 是同步命令,Redis要在这一条命令里,把这500万个字段占用的内存逐个释放干净,才能返回"OK"。UNLINK 则只做了一件很小的事:把这个key从主键值字典里摘除、立刻返回,真正释放内存这件"体力活",交给了一个独立的后台线程慢慢做。
Redis是单线程处理命令的,DEL的0.85秒不是"这一个连接等了0.85秒"这么简单。
结果DEL期间,另一个并发连接的PING,观测到的最大单次延迟: 819.49 ms UNLINK期间,同样并发PING观测到的最大单次延迟: 0.81 ms
验证了:DEL在执行那0.85秒的内存释放工作时,Redis主线程整个被占住,其它所有客户端的所有请求(哪怕只是一个PING)都要排队等这条DEL执行完,819.49毫秒的延迟就是付出的代价。UNLINK因为真正耗时的释放工作被挪到了后台线程,主线程几乎立刻就能继续处理下一个客户端的请求,并发PING的延迟几乎感觉不到。
UNLINK 而不是 DEL——DEL删大key会变成一次"全服卡顿"事件,UNLINK能把这份代价隔离到后台,不影响其它客户端的实时请求。(对于很小的key,两者几乎没有区别,DEL本身就很快。)
每一步都是本文上面用423MB大hash跑出来的原始结果。
DEL vs UNLINK:对比同步与异步释放