Redis缓存之String的滥用

在我们日常开发中如果使用redis做缓存,那么使用最多的可能为String类型,String类型使用简单而且容易理解但这只是开发方面,如果业务数据量过大使用String类型存储可行性是否还是最高,我们可以依靠在线Redis内存预估统计工具http://www.redis.cn/redis_memory/如下统计
模拟1亿个String类型的键值对,key占用4个字节value占用4个字节,仅key,value占用内存800M,那Redis的String类型需要占用多少呢?如下所示

Redis缓存之String的滥用

文章插图
 
key和value单纯的内存消耗只占据了Redis的String类型所需总内存的十分之一,也是说有十分之九是存储其它信息,那到底是什么呢?如下分析 。
简单动态字符串SDSRedis使用的String类型底层实现就是SDS简单动态字符串,为什么Redis需要封装而不是c自带的字符串呢?
SDS的优势
  • SDS获取字符串的长度时间复杂度为O(1),而C语言自带的需要遍历数组时间复杂度为O(N) 。
  • SDS有效避免缓冲区溢出(在长度不足时可以扩容) 。
  • SDS可以减少修改字符串带来的内存分配(C语言字符串修改N次都需要重新分配内存,SDS最多需要重新分配N次内存) 。
SDS结构SDS底层结构从3.x到6.x版本变化挺大需要分开学习,3.x结构简单如下所示
typedef char *sds;struct sdshdr {    // 记录buf数组已使用的长度    unsigned int len;        // 记录buf数组没有使用的长度    unsigned int free;        // 字符串保存位置    char buf[];};
Redis缓存之String的滥用

文章插图
 
需要注意的是buf结尾是结束符'''是一定存在的,占用一个字节,但是在计算len时是不会计算结束标识符''的 。
6.x版本SDS结构代码如下所示
typedef char *sds;/*  * Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings.  * sdshdr5未使用,其余都有使用 */struct __attribute__ ((__packed__)) sdshdr5 {    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */    char buf[];};struct __attribute__ ((__packed__)) sdshdr8 {    uint8_t len; /* used  已使用长度*/    uint8_t alloc; /* 分配长度 不包括报头和空终止符,1个字节存储 */    unsigned char flags; /* 高3位存储、低5位预留 */    char buf[];};struct __attribute__ ((__packed__)) sdshdr16 {    uint16_t len;     uint16_t alloc; /* 分配长度 不包括报头和空终止符,2个字节存储 */    unsigned char flags;     char buf[];};struct __attribute__ ((__packed__)) sdshdr32 {    uint32_t len;     uint32_t alloc; /* 分配长度 不包括报头和空终止符,4个字节存储 */    unsigned char flags;     char buf[];};struct __attribute__ ((__packed__)) sdshdr64 {    uint64_t len;     uint64_t alloc; /* 分配长度 不包括报头和空终止符,8个字节存储 */    unsigned char flags;     char buf[];};结构图如下所示
Redis缓存之String的滥用

文章插图
 
RedisObject结构Redis存在不同的数据类型,在这些不同的数据类型中又需要记录一些相同的信息如key最后访问时间、引用次数等所以需要将其封装为一个结构体(JAVA中的对象)来存储这些元素这就是RedisObject结构图如下所示 。
Redis缓存之String的滥用

文章插图
 
元数据type元数据中的type为数据类型目前存在六种数据类型:string,hash,set,list,zset,stream可以通过命令type {key}获取类型


推荐阅读