一、Redis 的"字符串对象"是什么?
Redis 中的字符串不是 C 的 char*,而是一个 对象(redisObject),结构大致是:
cpp
typedef struct redisObject {
unsigned type:4; // 对象类型(string / list / hash ...)
unsigned encoding:4; // 编码方式(int / embstr / raw)
void *ptr; // 指向实际数据
...
} robj;
所以你看到的:
int
embstr
raw
不是三种数据类型,而是同一种 string 类型的三种"内部编码方式"。
二、int 编码:当字符串"长得像整数"
触发条件
当一个字符串:
内容是 整数
并且这个整数 可以用 C 的 long 表示
内部存储方式
redisObject
┌─────────────┐
│ type=string │
│ encoding=int│
│ ptr=100 │ ← 直接存整数,不是指针
└─────────────┘
ptr 不指向内存
而是 *直接存整数值(void 强转 long)**
没有 SDS
没有字符串拷贝
三、embstr 编码:优化"短字符串"
embstr 的核心思想(重点)
redisObject + SDS 一次性分配在一块连续内存中
一整块内存
┌───────────────────────────────────┐
│ redisObject │ SDS header │ buf[] │
└───────────────────────────────────┘
一次 malloc
一次 free``ptr
指向 SDS
为什么 embstr 比 raw 快?
| 对比项 | embstr | raw |
|---|---|---|
| malloc 次数 | 1 次 | 2 次 |
| free 次数 | 1 次 | 2 次 |
| 内存连续 | 是 | 否 |
| CPU cache 命中 | 高 | 较低 |
短字符串非常多(key、状态值、flag),所以 embstr 是高频优化。
四、raw 编码:通用字符串方案
raw 的内存结构
两块内存
┌─────────────┐ ┌─────────────────────┐
│ redisObject │ ───► │ SDS header + buf[] │
└─────────────┘ └─────────────────────┘
redisObject 一块
SDS 一块
两次 malloc
raw 的优势
字符串可变
支持 APPEND / SETRANGE
支持 SDS 扩容策略
五、String 缓存对象
方式一:直接缓存整个 JSON
SET user:1 '{"name":"xiaolin","age":18}'
适合场景
整体读、整体写
用户详情页、商品详情页
不频繁修改单个字段
Redis 完全不关心 JSON 结构,只把它当字符串存。
优点
结构清晰
只需要一次 GET
网络开销小
缺点
修改一个字段 → 必须整体反序列化 + 序列化
不适合高频局部更新
方式二:Key 拆分(字段级缓存)
适合场景
经常只改 部分字段
单个字段被频繁访问(如 age、status)
优点
修改局部字段非常方便
不需要 JSON 解析
缺点
key 数量膨胀
需要 MGET 拼装对象
维护成本高
方式三:String 做计数器
为什么 String 特别适合计数?