Redis中的潜在阻塞点及其解决方案

       

目录

一、Redis 有哪些阻塞点

二、客户端交互

        2.1 网络I/O

        2.2 键值对操作

三、和磁盘交互

四、主从节点交互

五、切片集群实例交互时阻塞点

六、如何避免阻塞

        6.1 客户端

        6.2 AOF

        6.3 RDB


        Redis 作为高性能的键值对存储系统,在实际项目中得到了广泛的应用。但是在使用中我们必须重视有可能影响 Redis 性能的各种因素,本篇文章就带你了解可能会引起 Redis 阻塞的各种因素及解决方案。

一、Redis 有哪些阻塞点

        Redis 在实际运行中,要和许多对象进行交互,这些不同的交互会涉及不同的操作,下面是 Redis 实例交互的对象,以及交互过程中会发生什么操作。

  • 客户端:为客户端提供服务是最重要的功能,Redis 与客户端之间存在网络 I/O,通过网络 I/O 来实现数据的增删改查操作;
  • 磁盘:Redis 在运行过程中要保证数据的可靠性,就需要将内存中的数据持久化到磁盘。因此,Redis 会记录 AOF 日志、AOF 日志重写,以及 RDB 快早生成;
  • 主从节点:为了防止 Redis 实例挂掉后无法提供服务,通常会有若干个从节点进行数据冗余,以保证可用性。在同步的过程中,主库会生成、传输 RDB 文件,从库会接受到 RDB 文件,清空数据库,加载 RDB 文件等操作;
  • 切片集群:为了保存大量的数据,对 Redis 进行切分,每个切片上保存一部分数据,这样就可以保存大量的数据。这个过程中会涉及向其他实例传输哈希槽信息以及数据迁移等。

        下面来分析一下这些操作中哪些可能会引起阻塞。

二、客户端交互

        2.1 网络I/O

        网络 I/O 有时会成为性能瓶颈,但 Redis 使用了 I/O 多路复用机制,避免了主线程一直处于网络连接或等待状态,所以在 Redis 中,网络 I/O 不是做成阻塞的因素。

        2.2 键值对操作

        键值对的增删改查是 Redis 和客户端交互的主要部分,也是 Redis 主线程的主要任务。所以复杂度高的增删改查操作肯定会阻塞主线程,进而阻塞 Redis。

        判断操作复杂度的高低有一个基本的标准,就是看操作的复杂度是否为O(N),Redis 中涉及到集合操作时,操作的复杂度为 O(N),例如集合元素的全量查询 HGETALL、SMEMBERS,以及集合的聚合统计,如求交集、并集。

        关于操作命令的复杂度,Redis 官方提供了复杂度查询方式:Commands | Docs

        所以 Redis 的第一个阻塞点为:集合的全量查询和聚合操作

        此外,客户端的某些命令也是有阻塞的,比如 BLPOP、BRPOP 等,所以要尽量避免使用阻塞的命令。

        除此之外,集合自身的删除操作同样存在潜在的阻塞风险点,为什么删除可能会阻塞呢?其实,删除操作的本质是要释放键值对占用的内存空间。内存释放过程中释放内存只是第一步,为了更加高效的管理内存空间,在应用程序释放内存时,操作系统需要把释放掉的内存块插入一个空闲内存块链表中,以便后续进行管理和分配。这个过程本身需要一定时间,而且会阻塞当前释放内存的应用程序,所以一下释放大量内存,空闲内存块链表操作时间会增加,相应的就造成 Redis 阻塞。

        什么时候会存在释放大量内存呢?其实就是删除大量键值对数据的时候,最典型的就是删除包含大量元素的集合,或者 bigkey。

        如果大量的 key 在同意时间过期,也会出现大量 key 删除的情况,可能出现阻塞。 

        所以,第二个阻塞点为:删除大量数据时

        既然删除数据会造成阻塞,那清空整个库也会有同样的问题,所以,第三个阻塞点位:清空数据库

三、和磁盘交互

        磁盘 I/O 一般是很耗时的操作,Redis 采用子进程的方式生成RDB快照文件,以及执行 AOF 日志重写操作。这样一来,这两个操作由子进程负责执行,磁盘 I/O 就不会阻塞主线程。但 Redis 直接记录 AOF 日志时,会根据不同的写回策略对数据罗盘保存。如果采用的 always 写回策略,Redis 主线程会在每次执行写命令后立即写入 AOF 文件,这意味着 Redis 主线程直接参与 AOF 文件的写入操作,主线程会阻塞。

        所以,第四个阻塞点位:AOF 同步写

四、主从节点交互

        在主从集群中,主库需要生成 RDB 文件,并传输给从库。主库在复制过程中,创建和传输 RDB 都是由子进程完成的,不会阻塞主线程。但是,对于从库来说,在收到 RDB 文件后,首先要做的事就是要清空数据库,以免旧数据有影响,这就正好撞上了第三个阻塞点。

        此外,从库在清空当前数据库后,还需要把RDB文件加载到内存,这个过程的快慢和RDB文件的大小密切相关,RDB文件越大,加载过程越慢。

        所以,Redis 第五个阻塞点为:加载 RDB 文件

五、切片集群实例交互时阻塞点

        当我们部署 Redis 切片集群时,每个 Redis 实例上分配的哈希槽信息需要在不同实例间传递,同时,当需要进行负载均衡或者实例增删时,数据会在不同实例间进行迁移。不过,哈希槽的信息量不大,而迁移数据是渐进式执行的,所以这两类操作对 Redis 主线程的阻塞风险不大。

        如果使用了Redis Cluster方案,而且同时正好迁移 bigkey 的话,就会造成主线程阻塞,因为 Redis Cluster 使用了同步迁移。

六、如何避免阻塞

        6.1 客户端

        在客户端操作时要避免使用全量查询的命令,如 keys *、全量查询集合或对集合进行聚合统计等操作;避免使用阻塞的命令,如 BLPOP、BRPOP 等。

        比如需要返回 set 中所有的成员,不需要使用 SMEMBERS 命令,而使用 SSCAN 多次迭代返回,避免一次返回大量数据,造成阻塞。当你需要执行交集、并集、排序操作时,可以在客户端进行这些操作,以免拖慢 Redis。 

        在删除数据时,要避免大量的数据在同一时间过期,可以有小时间间隔的设置过期时间。

        对于 bigkey 的大集合删除,可以采用渐进式的删除方式,这种方式允许你分批删除 bigkey 中的元素,而不是一次性的删除整个 bigkey。比如要删除 hash 表的 bigkey 可以采用一下的命令:

HSCAN key cursor [MATCH pattern] [COUNT count]
HDEL key field [field ...]

        6.2 AOF

        在使用 AOF 进行持久化时,避免使用同步写回机制,以免影响主线程阻塞,影响客户端使用。

        AOF 日志提供了三种写回策略:no、everysec、always。这三种写回策略依赖文件系统的两个系统调用来完成,也就是 write 和 fsync。

        

     write 只是把数据写到了内核缓冲区,就可以返回了,并不需要等待日志时机写入磁盘。fsync 需要把日志记录写会磁盘才能返回,时间较长。

        当写回策略设置为 everysec 或 always 时,Redis 需要调用 fsync 把日志写会磁盘。但这两种写回策略的具体情况不同。

        在使用 everysec 写回策略时,Redis 允许丢失 1s 的操作记录,所以 Redis 主线程不需要确保每个操作记录日志都写回磁盘。如果在 Redis 主线程执行 fsync 就容易阻塞。所以在使用 everysec 时,Redis 会使用后台子线程异步的完成 fsync 的操作。

        而对于 always 写回策略来说,Redis 需要确保每个操作记录都写回磁盘,如果用后台子线程异步完成,主线程就无法及时的知道每个操作是否完成,所以 always 不使用后台子线程来执行。

        所以,在选在写回策略时要进行取舍,根据业务场景选择合适的写回策略,避免 Redis 阻塞。 

        6.3 RDB

        当 Redis 实例从 RDB 快照文件恢复数据时,如果 RDB 文件非常大,加载过程可能会非常慢,这会导致 Redis 在启动期间无法接受客户端请求,从而造成阻塞。

        可以调整 RDB 文件生成的频率,两次 RDB 之间可以使用 AOF 进行持久化,以此来减小 RDB 文件的大小,要在业务低峰期进行处理等。

        总之,通过正确的方式来进行 Redis 操作,可以有效的避免 Redis 的阻塞,从而提升整体的性能。

往期经典推荐

Logback 日志打印导致程序崩溃的实战分析_logback 打日志导致卡死-CSDN博客

从理论到实践:零拷贝技术的全面解读_零拷贝详解-CSDN博客

揭秘SpringBoot自动装配原理-CSDN博客

透视Redis大key背后的I/O挑战-CSDN博客

决胜高并发战场:Redis并发访问控制与实战解析_redis并发控制-CSDN博客

  

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超越不平凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值