【redis】redis常见数据结构及其底层,redis单线程读写效率高于多线程的理解,

redis常用数据结构及底层

  • string字符串、list链表、set无序集合、zset有序集合、hash哈希

1.string

  • 底层结构是SDS简单动态字符串

    struct sdshdr {
    int len; // 已用长度(字符串实际长度)
    int free; // 剩余可用空间
    char buf[]; // 数组,存储实际字符数据
    };

  • 相较于c字符串 ,它通过lenfree 字段实现O(1)长度查询,自动扩容,支持二进制存储

2.list

  • 是一个有序可重复 链表结构,会根据数据量和长度 ,自动选择不同数据结构,提升性能
  • 底层实现主要三种:
    • ziplist 压缩列表:redis3.2之前 ,元素数量<512 ,元素大小<64用压缩列表
    • linkedlist 双链表:redis3.2之前大数据量使用。
    • quicklist 快速列表:redis3.2之后 的默认存储,所有情况都用quicklist ,他是由多个ziplist 组成的双向链表

3.set

  • 无序 ,元素唯一 的集合类型,会根据数据量和内容 ,自动选择不同数据结构,提升性能
  • 底层两种实现:
    • intset 整数集合:适用于,都是整数数量<=512 。内存连续升序 排列,插入删除慢
    • hashtable 哈希表:适用于,多数据类型,数量多。标准hash,内存开销较大 (存储指针、哈希表结构)操作效率高

redis会根据数据自动切换,添加非整数/数量超512自动转hashtable,但是不会重新转回来

4.zset

  • 元素唯一 ,通过每个元素关联的score 自动排序 的结构,支持范围查找,范围排名等操作
  • 底层两种实现:
    • skiplist跳表:跳表提供有序遍历和范围操作
    • hashtable哈希表:哈希表提供快速查找

为什么用跳表 而不是红黑树?

实现简单插入删除性能好 (时间复杂度平均 O(log n)),更容易实现范围操作

  • 跳表原理 :通过分多个索引层加速查询底层完整 的有序链表 ,上层是索引层 ,每上一层减少一半,所以log₂n

    第3层:1 --------------------------> 9
    第2层:1 ------> 5 ------> 7 ------> 9
    第1层:1 -> 3 -> 5 -> 6 -> 7 -> 8 -> 9

5.hash

  • 一个键值对集合 ,常用于存对象(用户配置)等,会根据字段数量和内容自动选择不同的实现方式
  • 底层两种实现:
    • ziplist 压缩列表: 对象用压缩列表,(字段数<512,长度<64 )连续内存,占用少,节省空间,查询速度稍慢,字段超过阈值时,会自动转换为hashtable
    • hashtable 哈希表: 对象用hash表,读写效率更高

为什么小数据用 ziplist?

内存利用率高(无指针开销)
Redis 的哈希表如何扩容?

采用 渐进式扩容:扩容时同时保留新旧两个哈希表,分批次迁移数据

关于hash渐进式扩容,可以看我的这篇https://blog.csdn.net/m0_74282926/article/details/147522876

总结

数据类型 底层结构 说明
String int / embstr / raw(SDS) 根据长度和内容选择优化方式:int 表示整数,embstr 表示小字符串,raw 是通用 SDS
List ziplist(旧) / quicklist Redis 3.2+ 默认用 quicklist(多个 ziplist + 双向链表)
Set intset / hashtable 小量整数用 intset,其他情况用 hashtable
ZSet skiplist + hashtable 哈希表查找,跳表排序;两个结构同时维护
Hash ziplist / hashtable 字段少且短用 ziplist,否则用 hashtable

为什么redis单线程反而更快?

  1. 一个误区:并不是多线程一定比单线程快:
  • 在mysql中我们对于耗时较长的磁盘io 操作往往采用多线程并发执行,因为多线程产生的线程切换开销 往往于磁盘读写开销,所以并发等待可以提高效率;
  • 而redis是内存存储 ,本身单线程速度就很快,如果用多线程,
    涉及cpu上下文切换,锁竞争 ,这些耗时可能会超过内存中取数据的时间,从而降低性能。
  1. redis的性能瓶颈往往是网络或者内存 ,而非cpu,内存访问的速度高于切换线程的开销

  2. Redis 6.0 起引入了I/O 多线程模型,用于并行处理高并发 下,客户端的网络读写数据 (网络 I/O),但命令执行 仍是单线程,以保证数据一致性

网络 线程并发提速,核心逻辑线程保证安全。

  1. redis的数据协议 设计很高效 ,比如HashTable,理想情况下只需要O(1)的时间复杂度就可以找到数据。

例如 Hash 的 ziplist + hashtable 组合,在数据量小 时用 ziplist(节省内存),时转 HashTable(O(1) 查询)。

相关推荐
阿华田5122 分钟前
MySQL性能优化大全
数据库·mysql·性能优化
kaico20189 分钟前
python操作数据库
开发语言·数据库·python
被摘下的星星9 分钟前
MySQL 别名使用规则详解
数据库·mysql
墨着染霜华15 分钟前
MySQL 重复数据删除语句
数据库·mysql
ego.iblacat17 分钟前
PostgreSQL 数据库
数据库·postgresql
2401_8920709824 分钟前
顺序栈(动态数组实现) 超详细解析(C++ 语言 + 可直接运行)
数据结构·c++·顺序栈
漫霂39 分钟前
二叉树的翻转
java·数据结构·算法
wgzrmlrm741 小时前
如何解决ORA-28040没有匹配的验证协议_sqlnet.ora版本兼容设置
jvm·数据库·python
一江寒逸1 小时前
零基础从入门到精通MySQL(附加篇):面试八股文全集
数据库·mysql·面试
3秒一个大1 小时前
深入理解 JS 中的栈与堆:从内存模型到数据结构,再谈内存泄漏
前端·javascript·数据结构