大家好,我是Leo
继上篇文章Redis技术总结三,我们继续聊聊Redis相关技术!
我们在上一篇文章中介绍了
-
主要介绍Redis类型的底层实现和技术,以及类型选择的依据
-
通过时间序列数据介绍各类使用思路,拓展RedisTimeSeries模块的使用。
-
Redis作为消息队列也是面试常见问题。这道题延伸了List的优缺点和Streams的应用
本文主要介绍Redis中阻塞的原因
推荐阅读
30,000 字介绍 MySQL 是什么
30,000 字介绍 Redis 是什么 (1)
30,000 字介绍 Redis 是什么 (2)
30,000 字介绍 Redis 是什么 (3)
单线程模型阻塞
说到阻塞的原因,这应该是单线程的噩梦。在日常使用中,想要了解Redis阻塞的原因,就要从它的交互对象开始。下面我列出了Redis常见的交互场景
客户
客户端主要有网络IO开销,键值对增删改查操作,数据库操作等。
Redis 使用 IO 复用机制来防止主线程等待网络连接或请求到达,因此网络 IO 并不是导致 Redis 阻塞的因素。
查询:键值对查询,可以通过时间复杂度来判断。使用集合类型时,一般时间复杂度为O(n)。因此,集合类型的列表查询和聚合统计操作将是Redis的第一个阻塞点。
删除:删除也是Redis阻塞的重要因素之一。很多人不明白,删除是指直接删除指针的索引吗?事实上,事实并非如此。它与MySQL 有点不同。为了保证Redis中高效的内存管理,操作系统需要将释放的内存插入到空闲内存块中,以便后续管理和分配。因此,如果一次性释放大量内存,就会降低插入空闲内存块的效率。这也可以称为bigkey删除,这也是第二个阻塞点
数据库:如果说删除bigkey是阻塞Redis的因素之一,那么清除数据库也是第三个阻塞点
磁盘
带磁盘,主要生成RDB快照并保存在本地,记录AOFlog、AOFlog重写等。
Redis 意识到磁盘 IO 带来的阻塞影响,因此它使用子线程生成 RDB 快照并使用子线程执行 AOF 重写操作。
唯一的阻碍点是Redis在记录AOF日志时,会根据不同的写入策略来保存数据。 AOF日志同步写入
主从节点
与从库数据同步的主要目的是主库需要生成RDB快照并发送给从库,从从库接收,从从库清除数据库,加载RDB文件等等
通过子线程生成RDB不会阻塞。上面已将清除数据库列为阻塞点。主从节点主要讲加载RDB文件。如果RDB文件太大,也会阻塞。所以加载RDB文件就成了阻塞点之一
切片集群实例
切片集群的主要目的是查询一条数据。如果当前数据不在本实例上,则将哈希槽信息转移到其他实例上进行数据迁移。哈希槽中的信息量不会太大,数据迁移也不会太大。这是渐进的。因此,哈希槽和数据迁移对Redis阻塞影响不大。
但是,如果使用Redis Cluster方案,同时迁移bigkey,就会造成阻塞。
调整计划
如何调音?我们可以将所有不需要等待的操作改为异步执行。
大型查询和聚合查询显然必须完成才能继续,所以这是无法调优的。我们只能从数据类型入手,或者使用其他解决方案。
Bigkey和清库不需要等待返回才继续,所以这两个阻塞点可以优化为异步执行。
加载RDB文件时,必须等待以确保从数据库接收数据完成。严格来说,从库会向主库发送ack消息。
AOF日志同步写入也可以异步操作。它不需要将结果返回到实例。
子螺纹机构
上面我们谈到了五个阻塞点。所有三个阻塞点都可以异步优化Redis 的整体性能。我们来说一下子线程机制。
Redis主线程启动后,会使用操作系统提供的pthread_create函数创建三个子线程。它们负责同步写入 AOF 日志、bigkey 删除、清除数据库以进行异步执行。 (下图来自蒋德君老师)