当前位置: 首页 > news >正文

深入解析Redis 7.0中每种数据类型的底层实现

一、String(字符串)

核心实现:SDS(Simple Dynamic String)

struct sdshdr {uint64_t len;     // 已使用长度(O(1)获取长度)uint64_t alloc;   // 总分配空间(不含header)unsigned char flags; // 类型标识(SDS_TYPE_8/16/32/64)char buf[];       // 柔性数组(实际数据)
};

Java视角特性

  1. 二进制安全:可存储任意二进制数据(如图片),非仅文本

  2. 内存预分配

    • 扩容策略:len < 1MB 时双倍扩容,≥1MB 时每次扩1MB

    • 惰性释放:缩短时不立即回收内存

  3. 编码优化

  • EMBSTR:redisObject和SDS连续存储(减少内存碎片)

  • INT:直接存储长整型值(无额外内存开销)

二、List(列表)

底层结构演进

  • ≤Redis 2.8:双向链表(linkedlist

  • Redis 3.2+:QuickList

typedef struct quicklist {quicklistNode *head;quicklistNode *tail;unsigned long count;     // 总元素数unsigned long len;       // quicklistNode数量int fill : QL_FILL_BITS; // ziplist最大大小unsigned int compress : QL_COMP_BITS; // 压缩深度
} quicklist;typedef struct quicklistNode {struct quicklistNode *prev;struct quicklistNode *next;unsigned char *zl;        // 指向ziplistsize_t sz;                // ziplist字节大小unsigned int count : 16;  // ziplist元素数unsigned int encoding : 2; // 编码类型unsigned int container : 2; // 存储方式unsigned int recompress : 1; // 临时解压标记
} quicklistNode;

Java应用场景

  • 消息队列:LPUSH/RPOP实现FIFO

  • 分页查询:LRANGE key 0 9 获取前10条

  • 性能优化点

    • 调整list-max-ziplist-size控制ziplist节点大小

    • 设置list-compress-depth压缩中间节点(首尾不压缩)

三、Hash(哈希表)

底层结构

  1. Ziplist(紧凑列表):

    • 触发条件:字段数≤hash-max-ziplist-entries(默认512)且 所有值长度≤hash-max-ziplist-value(默认64字节)

    • 存储格式:<key1><value1><key2><value2>...

  2. Dict(哈希表):

    typedef struct dict {dictEntry **table;      // 哈希桶数组unsigned long size;     // 桶数量unsigned long sizemask; // size-1(用于取模)unsigned long used;     // 元素数量
    } dict;typedef struct dictEntry {void *key;union {void *val;uint64_t u64;double d;} v;struct dictEntry *next; // 链地址法解决冲突
    } dictEntry;

    Java最佳实践

    • 存储对象:替代JSON序列化,支持字段级操作

    • 配置优化:根据字段平均大小调整hash-max-ziplist-value

四、Set(集合)

底层结构

  1. Intset(整数集合):

typedef struct intset {uint32_t encoding; // INTSET_ENC_INT16/32/64uint32_t length;int8_t contents[]; // 有序数组
} intset;
  • 触发条件:元素均为整数且数量≤set-max-intset-entries(默认512)

  • Dict(哈希表):

    • 特殊实现:value固定为NULL,仅用key存储数据

Java场景对比

操作Intset复杂度Dict复杂度Java等价类
SADDO(n)O(1)HashSet.add()
SISMEMBERO(log n)O(1)HashSet.contains()
SUNIONO(n)O(n)Set.addAll()

五、ZSet(有序集合)

双重结构

typedef struct zset {dict *dict;        // 哈希表:member->scorezskiplist *zsl;    // 跳跃表:按score排序
} zset;// 跳跃表节点
typedef struct zskiplistNode {sds ele;double score;struct zskiplistNode *backward; // 后退指针struct zskiplistLevel {struct zskiplistNode *forward;unsigned long span; // 跨越节点数} level[]; // 柔性数组
} zskiplistNode;

跳跃表特性

  1. 层高随机生成(1/4概率升级)

  2. 支持O(log n)范围查询(ZRANGEBYSCORE)

  3. 平衡树替代方案:避免旋转操作,更易实现

Java使用场景

  • 排行榜:ZINCRBY + ZREVRANGE

  • 延迟队列:score设为执行时间戳

六、高级类型实现

1. Bitmap(位图)

本质:String的位操作扩展

  • SETBIT key offset 1:扩展SDS并置位

  • GETBIT:位运算定位字节位置

  • BITCOUNT:使用SWAR算法加速统计

    // 汉明重量计算(每4位查表)
    static const unsigned char popcount_tab[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, ... 
    };

2. HyperLogLog

核心结构

struct hllhdr {char magic[4];      // "HYLL"uint8_t encoding;   // HLL_DENSE 或 HLL_SPARSEuint8_t notused[3]; // 保留字段uint8_t card[8];    // 缓存基数uint8_t registers[]; // 16384个6bit寄存器
};
  • 误差率:0.81%/√m(m=16384)

3. Stream

实现:Rax树(Radix Tree)

typedef struct raxNode {uint32_t iskey:1;     // 是否包含keyuint32_t isnull:1;    // 关联值是否为空uint32_t iscompr:1;   // 是否压缩存储uint32_t size:29;     // 子节点数/压缩字符串长度unsigned char data[]; // 柔性数组存储路径
} raxNode;
  • 消息ID:<millisecondsTime>-<sequenceNumber>

  • 消费者组:通过PEL(Pending Entries List)实现

Java开发者启示

  1. 内存优化

    • 小数据用ziplist/intset(调整max-*-entries参数)

    • 避免大Key:String≤10KB,集合元素≤5000

  2. API选择

    // 错误:多次网络IO
    for(String item : items) {jedis.sadd(key, item);
    }// 正确:管道批处理
    Pipeline p = jedis.pipelined();
    for(String item : items) {p.sadd(key, item);
    }
    p.sync();

  3. 持久化影响

    • RDB:ziplist可直接序列化,内存页高效dump

    • AOF:SDS格式对rewrite友好

  4. 集群分片

    • HashTag确保相关数据同slot:{user1000}.orders

黄金法则
理解底层结构才能写出高性能Redis代码,特别是当QPS > 10k时,数据结构选择直接影响集群规模成本。

http://www.dtcms.com/a/267217.html

相关文章:

  • 【Qt】QStringLiteral 介绍
  • 2025最新Telegram快读助手:一款智能Telegram链接摘要机器人
  • 深入理解微服务中的服务注册与发现
  • 《Java修仙传:从凡胎到码帝》第四章:设计模式破万法
  • 云原生微服务间的异步消息通信:最终一致性与系统容错的架构实战
  • 供应链管理学习笔记4-供应链网络设计
  • 前端-CSS-day1
  • QT中的网络通信
  • LLM:位置编码详解与实现
  • 深层神经网络:原理与传播机制详解
  • java的注解和反射
  • JVM的位置和JVM的结构体系
  • 交互式剖腹产手术模拟系统开发方案
  • 【openp2p】学习3:【专利分析】一种基于混合网络的自适应切换方法、装 置、设备及介质
  • C# 事件(事件访问器)
  • vue中添加原生右键菜单
  • [特殊字符]全面解锁远程运维新时代:CRaxsRat v7.4 工具实用指南(附推荐资源)
  • Oracle 高级 SQL 查询与函数详解:多表连接、子查询、聚合、分析函数
  • 冒泡和快速排序的区别
  • faster_lio 原理及代码
  • 【Oracle专栏】分区表增加分区
  • WPF学习笔记(25)MVVM框架与项目
  • spring-ai-alibaba 1.0.0.2 学习(十二)——聊天记忆扩展包
  • 深度学习的核心理论与技术
  • 11_架构演进:从单体到云原生的蜕变
  • 炸鸡派例程-ADC
  • RabbitMQ 4.1.1初体验-队列和交换机
  • 【AI论文】WorldVLA:迈向自回归动作世界模型
  • 第二章 简单程序设计
  • 盘式制动器的设计+说明书和CAD)【6张】+绛重