Redis 的 hash 在元素个数 ≤ hash-max-ziplist-entries 且每个字段和值长度 ≤ hash-max-ziplist-value 时使用 ziplist 编码;否则升级为 hashtable,且不可逆。
Hash 什么时候会用 ziplist 编码?
Redis 的
默认不是一直用哈希表(hashtable)存的。当满足两个条件时,它会退化成更省内存的
:元素个数 ≤
,且每个字段和值的长度都 ≤
。一旦任一条件被突破,整个
就会立即升级为 hashtable —— 这个过程不可逆,且会翻倍占用内存。
常见错误现象:
看似很小,但如果某次写入一个长字符串(比如
,bio 超过
),整个 key 就立刻转成 hashtable,哪怕之前只有 3 个短字段。
默认值(Redis 7.0+):
= 512,
= 64
如果你存的是 JSON 片段、base64 图片 ID 或带空格的描述文本,64 字节很容易超
升级后无法自动降级,即使你后续删掉长字段,内存也不会回收回 ziplist
怎么查当前 hash 是什么编码?
别猜,直接用
命令确认:
注意:
返回
才说明还在紧凑模式;返回
就已经“失守”了。线上如果发现大量
占用异常高,优先批量检查这个。
用
配合
可以做粗筛,但别在大实例上高频执行
这类管道容易丢结果,建议用 Lua 脚本原子判断
监控层面可采集
中的
,突然下降可能意味着大量 ziplist 升级(因 hashtable 冗余更高)
调参前必须想清楚的三件事
改
或
不是越大越好,本质是在内存、CPU、延迟之间做权衡。
增大
到 128 或 256,对存短文本(如邮箱、手机号)友好,但若误存日志片段,单个 field 就可能撑爆 ziplist,触发一次性扩容,卡住主线程
减小
(比如设成 64)能更快进入 hashtable,降低单次查找的平均复杂度(O(1) vs O(N)),但内存立刻多出 3–5 倍
这些参数是全局的,影响所有
,不能按 key 区分。如果你有“用户资料”(小而密)和“用户行为日志”(大而稀)两类 hash,硬靠一套参数必然顾此失彼
真实场景中,更推荐:对明确知道结构的小型 hash(如配置项、状态映射),用
+ 客户端缓存;对可能变大的,从设计上就避免塞进单个 hash,改用
或拆成多个 key。
内存溢出真正在哪发生?
很多人以为调低 ziplist 阈值就能防溢出,其实不然。真正的风险点不在 ziplist 本身,而在它升级成 hashtable 后的**内存放大效应**和**碎片累积**。
一个 10 字段、每字段平均 20 字节的 hash,在 ziplist 下约占 300 字节;升级后通常要 2KB+(含 dict 结构头、bucket 数组、指针等)
频繁 HDEL + HSET 混用,会导致 ziplist 升级后产生大量小内存块,jemalloc 很难合并,
悄悄升到 1.8 以上
Redis 6+ 的
对 hashtable 效果有限,别指望它自动救场
所以最有效的“防止”,其实是控制写入节奏和数据形态:避免在 hash 中存不确定长度的内容,不把 hash 当通用对象容器用。ziplist 参数只是兜底手段,不是安全绳。
hashziplisthash-max-ziplist-entrieshash-max-ziplist-valuehashHSET user:1001 name "Alice" age "30" city "Beijing"HSET user:1001 bio "..."hash-max-ziplist-valuehash-max-ziplist-entrieshash-max-ziplist-valueOBJECT ENCODINGredis-cli> HSET myhash a 1 b 2
(integer) 2
redis-cli> OBJECT ENCODING myhash
"ziplist"
redis-cli> HSET myhash c "x".repeat(65)
(integer) 1
redis-cli> OBJECT ENCODING myhash
"hashtable"OBJECT ENCODINGziplisthashtablehashSCANOBJECT ENCODINGredis-cli --scan --pattern "user:*" | xargs -L 1 -I {} redis-cli OBJECT ENCODING {}INFO memoryused_memory_dataset_perchash-max-ziplist-entrieshash-max-ziplist-valuehash-max-ziplist-valuehash-max-ziplist-entrieshashHGETALLJSON.SETmem_fragmentation_ratioactive-defrag