一、线程数目
- 操作数据结构的语句(即执行指令)是主线程(单线程,天然具备隔离性、不需要加锁)
- 别的线程主要用于优化:避免 IO 密集型和 CPU 密集型过多占用主线程
二、IO 密集型层面的优化
1. 磁盘 IO
- rdb:通过 fork 子进程来持久化
- aof:有异步刷盘机制(可选)
2. 网络 IO
- 通过 reactor 模型管理多个连接(主线程)
- 数据的接收,数据发送分摊到多个 io 子进程中
三、CPU 密集型层面的优化
- 分治思想:协议的解析(命令接收完之后)、协议的加密(响应回复前)分摊到多个 io 子进程
- 数据结构的切换:value 的不同数据结构底层存储方式在数据量不同情况下采取不同的策略(在执行效率与空间占比间保持平衡)
- 渐进式数据迁移:rehash 的两种方式:
- 每执行一条指令 copy 一个槽位
- 当服务器空闲时,定时 1ms 进行 rehash 的数据迁移
四、数据结构层面优化
| 编码类型 | 特点(内存 / 性能) | 适用场景 |
|---|---|---|
| 紧凑编码(ziplist/intset/embstr) | 内存占用极少,存储密度高,但增删改需要频繁重排内存 | 数据量小、访问不频繁 |
| 高效编码(dict/skiplist/raw) | 内存占用高(有结构开销),但增删改查效率高(O (1)/O (logN)) | 数据量大、访问频繁 |
简单说:数据量小时用'紧凑编码'省内存,数据量大时用'高效编码'保性能。
1. 哈希(ziplist → dict)
- ziplist(压缩列表):
- 内存上:所有键值对 / 元素连续存储,无冗余指针(dict 每个键值对要存两个指针,skiplist 每个节点有多层指针),内存密度是 dict 的 1/5 以上;
- 性能上:增删改需要重排整个列表(O (n)),但数据量小(≤512/128 个元素)时,n 很小,性能损耗可忽略;
- dict/skiplist:
- 内存上:dict 有哈希表开销(桶数组 + 链表);
- 性能上:dict 查改 O (1), 数据量大时远快于 ziplist 的 O (n)。
设计目的:小哈希省内存,大哈希用 dict 保证读写性能。
1.1 hashTypeSet
/* 给哈希对象设置 field-value 键值对 *
* 参数说明:
* o: 目标哈希对象(robj 类型)
* field: 哈希的字段(SDS 字符串)
* value: 哈希的取值(SDS 字符串)
* flags: 控制标志(如是否接管 field/value 的内存所有权)
* 返回值:1 表示更新了已有字段,0 表示新增了字段 */
int hashTypeSet(robj *o, sds field, sds value, int flags) {
int update = 0; // 标记是否是'更新'操作(1=更新,0=新增)
/* 分支 1:哈希对象当前是 LISTPACK 编码(紧凑存储,替代旧的 ziplist) */
if (o->encoding == OBJ_ENCODING_LISTPACK) {
*zl, *fptr, *vptr;
zl = o->ptr;
fptr = lpFirst(zl);
(fptr != ) {
fptr = lpFind(zl, fptr, ( *)field, sdslen(field), );
(fptr != ) {
vptr = lpNext(zl, fptr);
serverAssert(vptr != );
update = ;
zl = lpReplace(zl, &vptr, ( *)value, sdslen(value));
}
}
(!update) {
zl = lpAppend(zl, ( *)field, sdslen(field));
zl = lpAppend(zl, ( *)value, sdslen(value));
}
o->ptr = zl;
(hashTypeLength(o) > server.hash_max_listpack_entries)
hashTypeConvert(o, OBJ_ENCODING_HT);
}
(o->encoding == OBJ_ENCODING_HT) {
dictEntry *de = dictFind(o->ptr, field);
(de) {
sdsfree(dictGetVal(de));
(flags & HASH_SET_TAKE_VALUE) {
dictGetVal(de) = value;
value = ;
} {
dictGetVal(de) = sdsdup(value);
}
update = ;
} {
sds f, v;
(flags & HASH_SET_TAKE_FIELD) {
f = field;
field = ;
} {
f = sdsdup(field);
}
(flags & HASH_SET_TAKE_VALUE) {
v = value;
value = ;
} {
v = sdsdup(value);
}
dictAdd(o->ptr, f, v);
}
}
{
serverPanic();
}
(flags & HASH_SET_TAKE_FIELD && field) sdsfree(field);
(flags & HASH_SET_TAKE_VALUE && value) sdsfree(value);
update;
}


