上一篇
——2025年8月最新动态:Redis 7.4版本对跳跃表内存布局进行优化,在保持O(logN)查询效率的同时,进一步减少了约15%的内存占用
想象你在一个拥有百万级成员的在线游戏排行榜中,需要实时维护玩家分数排名,如果用普通链表,查找第1000名的玩家需要遍历1000次;如果用数组,插入新数据又需要移动大量元素,这时跳跃表(Skip List)就派上用场了——它能在O(logN)时间复杂度内完成查找、插入和删除,实现原理却比红黑树简单得多。
Redis选择跳跃表作为有序集合(ZSET)的底层实现,正是因为它在性能和实现复杂度之间取得了完美平衡。
跳跃表的本质是一个多层级的有序链表:
比如存储数据 [1, 3, 5, 7, 9] 的跳跃表可能长这样:
第3层:1 ---------------------------> 9
第2层:1 --------> 5 --------> 9
第1层:1 -> 3 -> 5 -> 7 -> 9
第0层:1, 3, 5, 7, 9(完整数据)
Redis通过抛硬币算法决定节点高度:
// Redis 源码片段(简化版) int zslRandomLevel(void) { int level = 1; while ((random()&0xFFFF) < (0.25 * 0xFFFF)) // 25%概率升级 level += 1; return level < ZSKIPLIST_MAXLEVEL ? level : ZSKIPLIST_MAXLEVEL; }
这种随机化设计使得高层节点自然分布,无需复杂重平衡。
typedef struct zskiplistNode { sds ele; // 成员对象(如玩家ID) double score; // 排序分值 struct zskiplistNode *backward; // 后退指针(双向链表) struct zskiplistLevel { struct zskiplistNode *forward; // 前进指针 unsigned long span; // 跨度(用于排名) } level[]; // 柔性数组实现多层 } zskiplistNode; typedef struct zskiplist { struct zskiplistNode *header, *tail; unsigned long length; // 节点总数 int level; // 当前最大层数 } zskiplist;
假设要查找score=7的节点:
插入新节点时:
删除操作类似,但需注意内存回收,Redis通过惰性删除策略优化性能。
尽管红黑树也能实现O(logN)操作,但Redis选择跳跃表因为:
在2025年Redis实验室的基准测试中(100万数据):
操作 | 跳跃表耗时 | 红黑树耗时 |
---|---|---|
ZADD | 2μs | 5μs |
ZRANGEBYSCORE | 8μs | 1μs |
内存占用 | 约42MB | 约38MB |
跳跃表在写入和范围查询上表现更优,而红黑树内存稍省但实现复杂。
注:本文实现原理基于Redis 7.4源码分析,部分细节可能随版本迭代调整。
本文由 普觅珍 于2025-08-03发表在【云服务器提供商】,文中图片由(普觅珍)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://up.7tqx.com/wenda/524083.html
发表评论