Redis 底层对 String 的 3 个优化

Redis对 String 类型实现了很多优化,通过以下三个重要的优化点来解释:

1. 简单动态字符串(SDS)

Redis 的 String 类型内部采用简单动态字符串(SDS)来管理字符串。相比于 C 语言的原生字符串,SDS 有以下优势:

  • 能够动态地改变自己的长度,避免了不必要的内存分配和拷贝操作;
  • SDS 本身有一个长度属性,可以快速计算字符串的长度;
  • SDS 可以与 C 语言原生字符串互相转换,方便对 C 语言中一些函数的使用。

SDS 源码:

c 复制代码
struct sdshdr {
    int len;                // 字符串实际长度
    int free;               // 字符串剩余空间
    char buf[];             // 字符串数据
};

源码解释:redis 源码实现 sds 函数,定义了 SDS 的各种操作函数,例如 sdsnew() 函数用于新建 SDS 字符串,sdsempty() 函数用于初始化一个空 SDS 字符串等。

2. 共享字符串

当多个客户端传入相同的字符串参数时,Redis 会把相同字符串的内部指针指向同一内存地址,这些指针共享同一个字符串对象。这种优化可以减少内存占用,提高性能。

c 复制代码
robj *lookupShared(const char *s, size_t len) {
    dictEntry *de = dictFind(server.shared.dict,s);
    if (de) {
        robj *shared = dictGetVal(de);
        return shared;
    }

    robj *shared = createStringObject(s,len);
    dictAdd(server.shared.dict, s, shared);
    return shared;
}

robj *createShared(const char *ptr, size_t len) {
    robj *sobj = createObject(OBJ_STRING,sdsnewlen(ptr,len));
    sobj->encoding = OBJ_ENCODING_RAW; // 设置编码方式为RAW
    return sobj;
}

源码解释:这里有两个相关函数:lookupShared() 用于在 Redis 的共享字符串池中查找指定的字符串,如果字符串存在,则返回字符串对象;如果字符串不存在,则新建字符串对象并存储在共享字符串池中。createShared() 函数则是用于创建新的共享字符串对象。

3. 编码的优化

Redis 的 String 类型支持多种编码方式,如 INT、EMBSTR、RAW 等。根据不同的编码方式和数据类型,Redis 选择最适合的编码方式来储存数据,从而避免了冗余的存储空间。

c 复制代码
int encodingType(robj *o) {
    if (o->encoding == OBJ_ENCODING_INT) {
        return OBJ_ENCODING_INT;
    } else if (o->encoding == OBJ_ENCODING_EMBSTR) {
        return OBJ_ENCODING_EMBSTR;
    } else {
        return OBJ_ENCODING_RAW;
    }
}

void setStringObject(robj *o, const char *s, size_t len) {
    if (o->encoding == OBJ_ENCODING_INT) {
        // 释放原有的整数值空间
        decrRefCount(o);
        // 创建新的Raw编码字符串对象
        o = createStringObject(s,len);
    } else if (o->encoding == OBJ_ENCODING_EMBSTR) {
        // 释放原有的Embstr编码字符串空间
        sdsfree(o->ptr);
        o->ptr = zmalloc(len);
        memcpy(o->ptr, s, len);
        o->encoding = OBJ_ENCODING_RAW;
    } else {
        // 设置Raw编码字符串值
        o->ptr = sdscpylen(o->ptr, s, len);
        o->encoding = OBJ_ENCODING_RAW;
    }
}

源码解释:这里有两个相关函数:encodingType() 用于返回某个值采用的编码方式,可以检查一个字符串对象或列表对象采用的编码方式;另一个函数 setStringObject() 用于设置一个字符串对象的值,根据需要选择适当的编码方式。

4. 总结时刻

回答出来以上三点,表明你对 Redis 的 String 类型的源码是有研究的,而不是每天只顾 CRUD,只顾写业务。

另外,也能表明你的技术深度,面试官一定会对你另眼相看哟!加油!

相关推荐
SL_staff1 小时前
告别报表重复开发:JVS-BI 模板市场的参数化继承实践
java·数据分析·数据可视化
SL_staff2 小时前
从邮箱传文档到协同流重构:企业文档协作的系统性破局实践
java·开源·github
smallyoung4 小时前
告别N+1:Spring Boot 一键数据翻译框架体系
java·后端·架构
Bazingga5 小时前
Java16 record 完整拆解——语法、语义、限制、反射
java·后端
SL_staff7 小时前
规则联动:给工厂装上‘自动化神经反射弧’——JVS·物联网平台规则引擎实战教程
java·人工智能·物联网
骑着蜗牛撵大象3277 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
WJ.Polar7 小时前
Java封装、继承、多态
java·开发语言
ly76897 小时前
PostgreSQL 备份恢复策略:pg_basebackup、WAL 归档与 PITR 在企业 Java 系统中的落地
java·数据库·postgresql·pitr·pg_basebackup·wal 归档
摇滚侠7 小时前
Java 中如何表示负数,有符号和无符号的区别,补码的计算规则,char byte short int long 的范围
java·开发语言
奇牙coding8 小时前
Codex CLI 升级后多文件编辑静默失效:config.yaml 枚举变更排查与修复指南
java·前端·javascript·ai