一文吃透 Redis 压缩列表、listpack 及哈希表扩容与并发查询

目录

压缩列表是怎么实现的?

[介绍一下 Redis 中的 listpack哈希表是怎么扩容的?](#介绍一下 Redis 中的 listpack哈希表是怎么扩容的?)

哈希表扩容的时候,有读请求怎么查?

压缩列表是怎么实现的?

压缩列表图:

链表的表头有三个字段

zlbytes:用于统计整个压缩列表有多少字节

zltail:用于统计末尾节点距离起始节点相差多少字节的距离

zllen:用于统计整个列表的节点数量

末尾一个字段:

zlend:用于标记列表的结束点,固定值是0xFF十进是255

如果需要查询列表的最后一个节点,只需要依赖头部字段zltail就可以查到了只需要查找一次复杂度是O(1),而其他节点就需要依次查找,时间复杂度是O(n),所以压缩列表不适合存储元素过多的场景

每一个节点有三个属性

prevlen:存放前一个节点占用的内存字节大小,列表倒序就需要依赖prevlen

encoding:存放当前数据的类型,整数型或者字符串

data:存当前数据

当压缩列表插入数据时,压缩列表会根据当前元素的类型和大小来使用不同的空间的prevlen和encoding来存储数据,这一根据元素大小分配空间的方案,提高了内存的使用率

压缩列表的缺点

一旦遇到连锁更新时,就有可能导致压缩列表分配的内存空间重新分配,而多次的重新分配会影响压缩列表的访问性能

若节点过多或节点过大也有可能引发连锁更新,所以压缩列表适合存储节点比较少的场景

redis为了解决这个缺点redis3.2引入了quicklist和redis5.2引入了listpack,保存了节省空间的优点,同时解决压缩列表连锁更新的问题

介绍一下 Redis 中的 listpack

listpack核心目的就是解决了ziplist(压缩列表)的连锁更新问题

listpack的结构如下:

头部两个属性:记录了总字节数和元素数量

结尾还有结尾标识

每一个元素有三个属性:

encoding:定义该元素的编码类型,会对整数或字符串进行不同的编码

data:数据

len:记录encoding和data的长度

listpack每一个节点会根据内容的大小来进行不同的编码,主要依赖于encoding

没有了prevlen之后依旧可以倒叙,因为如果更改字符串不会导致其他节点的内容变化直接解决了连锁更新的问题

倒序遍历的核心逻辑

  • 第一步:通过表头的「总字节数」定位到整个 listpack 的末尾。
  • 第二步:减去结尾标识(1 字节),得到最后一个节点的末尾地址。
  • 第三步:读取该节点的 len 字段,用末尾地址减去 len 得到上一个节点的末尾地址。
  • 第四步:重复第三步,直到遍历到表头,完成倒序。

哈希表是怎么扩容的?

哈希扩容需要两个哈希表

有两种方式:

一次性映射所有值:会导致redis阻塞卡死,所以基本不用

Redis 的核心是单线程处理所有客户端的读写请求 (底层操作是单线程的),这是 Redis 高性能的原因,也是不能一次性扩容的根本原因:

  1. 一次性拷贝的问题 :如果哈希表中存储了百万 / 千万级的 key-value ,一次性遍历 ht 0 所有数据、重新计算哈希、迁移到 ht 1,这个过程会消耗几十毫秒甚至几秒的时间;
  2. 单线程的致命影响 :在这几十毫秒 / 几秒内,Redis 的单线程会被完全阻塞 ,无法处理任何客户端的读、写、查询请求 ------ 客户端会看到请求超时、服务无响应,这在生产环境中是不可接受的(比如电商场景的秒杀、缓存查询,一秒的阻塞都会导致大量请求失败);
  3. 结论 :一次性扩容的技术上可以实现 ,但业务上完全不可用,违背了 Redis 高性能、高可用的设计目标

渐进式映射:分区段的把哈希表1映射到哈希表2,在映射的过程中,如果有读的操作,若在哈希表1没有,就去查询哈希表2。若有写的操作只在哈希表2进行,保证哈希表1的数量只减少。最终把哈希表1的内容全部映射到哈希表2之后哈希表1的空间释放,然后把哈希表2设置为哈希表1

哈希表的渐进式扩容并非原位置顺序拷贝数据,而是对每个 key 通过哈希取模,把映射key到新表的新位置(即 rehash),这是扩容大幅度减少哈希冲突的核心

哈希取模是哈希表将「哈希函数算出的大数值」转换为「数组合法下标」的核心操作,通过哈希值 % 数组容量实现,保证任意 key 都能映射到哈希表的指定位置;

哈希表扩容的时候,有读请求怎么查?

查找一个 key 的值的话,先会在「哈希表 1」 里面进行查找,如果没找到,就会继续到哈希表 2 里面进行找到。

相关推荐
努力努力再努力wz1 分钟前
【Redis进阶系列】:从主从复制到 Sentinel,一文建立故障检测、Leader 选举与 Failover 的完整心智模型
数据库·redis·缓存
达梦数据9 分钟前
DMDRS搭建部署简介与运行环境
数据库
Omics Pro12 分钟前
1个月2轮融资!长寿虚拟细胞
数据库·人工智能·算法·机器学习·自然语言处理
zcn12634 分钟前
row_number()函数与group by性能比较
数据库·sql优化改写
Wang's Blog1 小时前
Java 项目实战: 外卖平台-后台系统登录功能开发
java·服务器·redis
小K讲AI营销1 小时前
AI基础设施融资路径的中美比较:资本市场模式与政策金融模式
大数据·数据库·人工智能
净水深流1 小时前
中国冷链冷库行业数据分析:从规模扩张到技术驱动
大数据·数据库·人工智能·冷库冷链
李兆龙的博客2 小时前
从一到无穷大 #94:ClickHouse TimeSeries——时间线组织与 Prometheus 兼容性
数据库
冰暮流星2 小时前
事务的四个特性(ACID)详解
数据库
byte轻骑兵2 小时前
时序数据库选型全指南|大数据工业场景Apache IoTDB落地实操
大数据·数据库·人工智能·apache iotdb