验证编码转换检查到底发生在哪个动作上:把配置阈值调低后,已有数据不会被追溯转换,只有的写操作才会立刻触发按新阈值重新评估。
前面几篇文章验证的都是"写入时"的编码判断,这次验证判断到底发生在哪个动作上。
操作CONFIG SET hash-max-listpack-entries 512 HSET 20个字段到h1 OBJECT ENCODING h1 CONFIG SET hash-max-listpack-entries 5 -- 把阈值调到远低于h1现有的20个字段 OBJECT ENCODING h1 -- h1完全没有被碰过
h1已经有20个字段,远超过新设的阈值5,但没人碰它。
结果调低阈值之前: OBJECT ENCODING h1 → listpack (20个字段,阈值512) CONFIG SET hash-max-listpack-entries 5 (阈值改小了,h1完全没有被读写) OBJECT ENCODING h1 → :依然是listpack!
哪怕新的阈值(5)远小于h1已有的字段数(20),只要没有的读写操作发生在h1上,它的编码就不会被重新评估——CONFIG SET改的只是"以后写入时用什么标准判断",不会主动扫描现有数据、逐个检查是否需要转换。
分别做一次HGET(读)和一次HSET(写),看哪个会触发重新评估。
结果HGET h1 f1 (读取,不修改任何东西) OBJECT ENCODING h1 → :依然是listpack(读不触发) HSET h1 f21 v21 (写入一个新字段) OBJECT ENCODING h1 → :hashtable(写立刻触发!)
验证了编码检查的确切时机:只有执行了写操作(这里是新增一个字段),Redis才会按当前的配置阈值重新判断这个对象该用什么编码——这一次判断发现21个字段已经超过阈值5,于是立刻转换成hashtable。单纯的读操作,哪怕读的是同一个key,也不会触发这次重新评估。
hash-max-listpack-entries 这类编码阈值参数,不会立即影响已经存在的旧数据——已有的key会一直用旧编码,直到有一次写操作命中它,才会按新阈值重新判断。如果想让配置变更对存量数据生效,得靠后续业务的自然写入,或者手动触发一次读改写(比如给自己加个无意义的写操作)。
每一步都是本文上面用redis-cli跑出来的原始结果。
CONFIG SET hash-max-listpack-entries / OBJECT ENCODING:验证配置变更、读、写三种动作对编码的影响