小对象怎么聚
大量结构相同的小对象可以聚合进一个 hash:一个键承载一组字段,共享同一个键名与过期记录,dictEntry 与对象头的固定开销被摊薄。适合画像、设置项这类字段少、数量大、访问模式相近的数据。代价是过期粒度变粗,单键规模要持续盯着。
基本信息
| 结构形态 | biz:profile:id 下挂多个字段 |
|---|---|
| 收益 | 单对象的固定开销被摊薄 |
| 代价 | 过期粒度变粗,整键同生共死 |
| 验证方式 | 聚合前后的 MEMORY USAGE 与全局水位对比 |
典型使用场景
- 百万级小对象,每个只有几个字段
- 设置项与开关类配置,字段结构固定
- 用户画像标签,读写模式相近
- 键数太多,内存主要花在键与对象开销上
- 需要按主键整体过期的场景
聚合前后对比
聚合前后对比
redis-cli MEMORY USAGE user:1001:name # 拆散写法:单键开销示例
redis-cli HSET user:1001 name alice city sh age 30 # 聚合写法,一个键承载多字段
redis-cli HGET user:1001 city # 定向读取,不拉全量
redis-cli HMGET user:1001 name age # 批量取字段,减少往返
redis-cli MEMORY USAGE user:1001 # 对比聚合前后的占用
redis-cli INFO memory | grep -E 'used_memory_human' # 全局水位对比写法与开销对照
| 写法 | 内存开销 | 读取行为 |
|---|---|---|
| 每字段一个键 | 键名与对象开销重复 | 读取简单,但键数爆炸 |
| 单 hash 聚合 | 固定开销被摊薄 | 需 HMGET 定向取,避免 HGETALL |
| 按桶 hash 聚合 | 开销摊薄且单键规模可控 | 需按桶规则计算键名 |
| 用 zset 承载 | 偏重排序能力 | 不以省内存为目标 |
聚合后单键变大,要配合编码阈值评估:hash-max-listpack-entries、hash-max-listpack-value(旧版本为 ziplist 系列参数)。超过阈值后编码从紧凑结构转为哈希表,内存会出现台阶。
聚合粒度不能只按内存算。如果一组字段里有更新很频繁、有几乎不动的,聚合会把热点都压到同一个键上,热点分片的难度随之上升。
聚合方案要定期巡检键规模,否则容易出现把一堆小对象问题换成一个大键问题的情况。