Redis中的ZSet数据结构原理剖析

Zset 编码的选择

在通过 ZADD 命令添加第一个元素到空 key 时, Redis 会通过检查输入的第一个元素来决定使用何种编码。

如果第一个元素符合以下条件的话, 就创建一个 REDIS_ENCODING_ZIPLIST 编码的 Zset:

  • 服务器属性 server.zset_max_ziplist_entries 的值大于默认值 (默认为 128 )。
  • 元素的 member 长度小于服务器属性 server.zset_max_ziplist_value 的值(默认为 64 )。

否则,创建一个 REDIS_ENCODING_SKIPLIST 编码的 Zset。

对于一个 REDIS_ENCODING_ZIPLIST 编码的 Zset, 只要满足以下任一条件, 则会被转换为 REDIS_ENCODING_SKIPLIST 编码:

  • ziplist 所保存的元素数量超过服务器属性 server.zset_max_ziplist_entries 的值(默认值为 128
  • 新添加元素的 member 的长度大于服务器属性 server.zset_max_ziplist_value 的值(默认值为 64

ziplist原理

ziplist 编码的 Zset 使用紧挨在一起的压缩列表节点来保存,第一个节点保存 member,第二个保存 score。ziplist 内的集合元素按 score 从小到大排序,其实质是一个双向链表。虽然元素是按 score 有序排序的, 但对 ziplist 的节点指针只能线性地移动,所以在 REDIS_ENCODING_ZIPLIST 编码的 Zset 中, 查找某个给定元素的复杂度为 O(N)。

skiplist原理

skiplist 编码的 Zset 底层为一个被称为 zset 的结构体,这个结构体中包含一个字典和一个跳跃表。跳跃表按 score 从小到大保存所有集合元素,查找时间复杂度为平均 O(logN),最坏 O(N)。

字典则保存着从 member 到 score 的映射,这样就可以用 O(1) 的复杂度来查找 member 对应的 score 值。虽然同时使用两种结构,但它们会通过指针来共享相同元素的 member 和 score,因此不会浪费额外的内存。

c++ 复制代码
/* zset结构体 */
typedef struct zset {
    // 字典,维护元素值和分值的映射关系
    dict *dict;
    // 按分值对元素值排序序,支持O(logN)数量级的查找操作
    zskiplist *zsl;
} zset;
相关推荐
YOU OU2 小时前
Redis基础常识与命令
数据库·redis·缓存
GetcharZp3 小时前
抛弃低效SSH!这套Ansible+Web可视化神器,让你天天准点下班!
后端
Database_Cool_4 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森5 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_5 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白6 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
weixin_446260856 小时前
HACO:面向动态部署环境的对冲式智能计算可靠多智能体调度框架
后端·python·flask
窝子面6 小时前
手搓最简前后端协作-node
javascript·数据库
吳所畏惧7 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh