SQL极简教程 · MySQL · MyBatis · JPA 技术笔记 教程 总结PHP开发PHP经验分享

redis 源码见闻录

2022-02-28  本文已影响0人  怀老师

redis定义

redis是一个KV(键值)类型的数据库。redis的值可以有多种类型(string,array,list),键总是字符串对象。

字符串对象

一个字符串对象里如果包含了字符串值,那么这个字符串的类型称为sds类型。(对象里可能还会有long类型的值,那个就不是sds类型)。

SDS类型

SDS(Simple Dynamic String)简单动态字符串,是C语言char*的替代品。能高效地支持长度计算和追加(append)这两种操作。

SDS类型高效的原因

从数据结构来进行分析

struct sdshdr {

    // buf 已占用长度
    int len;

    // buf 剩余可用长度
    int free;

    // 实际保存字符串数据的地方
    char buf[];
};

首先我们发现里结构体里面有存储长度字段,那么它取长度的时间复杂度就是O(1),而C原生的长度查询依赖strlen(),复杂度是O(N)。又因为不依赖C的函,直接取长度,所以说它是二进制安全的。

二进制安全(不对数据做解析,将数据当作二进制数据流处理。如C的char*,会将\0解析成结尾。而二进制安全则不进行任何转义)。)

其次我们发现,C原生对字符串进行 N 次追加,必定需要对字符串进行 N 次内存重分配(realloc)。而SDS结构里带有free和buf,会在APPEND的时候给buf一些额外的空间,并将可用内存空间记录在free里。这样下次APPEND的时候,就可以直接进行追加,不涉及内存重新分配。

关于buf的空间分配规则:在目前版本的 Redis 中, SDS_MAX_PREALLOC 的值为 1024 * 1024 , 也就是说, 当大小小于 1MB 的字符串执行追加操作时, sdsMakeRoomFor 就为它们分配多于所需大小一倍的空间; 当字符串的大小大于 1MB , 那么 sdsMakeRoomFor 就为它们额外多分配 1MB 的空间。

优化:将SDS_MAX_PREALLOC的值调低。

优点:节省内存,比如调整到一半512kb,那么每多一个APPEND超过512kb的操作,就会节省超出512kb部分的内存空间出来。
缺点:可能的性能损耗(如果再次APPEND超过512kb的时候,会不走buf,进行内存重分配)
所以还是要结合业务,根据APPEND的频率和大小来选出最适合的buf空间。

buf的内存回收规则:可以修改配置,定时释放(或者重启redis会自动释放)

思考:

所有处理 sdshdr 的函数,都必须正确地更新 len 和 free 属性,否则就会造成 bug。(这里就会导致redis暂时只能单线程执行,如果多线程的话,要考虑len和free在并发操作下的一致性)。

上一篇下一篇

猜你喜欢

热点阅读