异步编程规避Redis的阻塞

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 本文探讨Redis内部的阻塞式操作及应对方案,分析影响性能的因素如命令操作、系统配置、关键机制和硬件配置等。重点研究Redis主线程可能被阻塞的风险点,包括集合全量查询、大Key删除、AOF日志同步写、主从节点交互等场景,并提出通过异步线程机制优化阻塞问题的方法。最后,明确哪些操作可异步执行,以提升Redis性能与稳定性。

1 简介

Redis重视影响Redis性能的因素,如:

  • 命令操作
  • 系统配置
  • 关键机制
  • 硬件配置 ...

要尽可能避免性能异常场景,还要做好异常应对方案。影响Redis性能的潜在风险:

  • Redis内部的阻塞式操作
  • CPU核和NUMA架构的影响
  • Redis关键系统配置
  • Redis内存碎片
  • Redis缓冲区

本文研究Redis内部的阻塞式操作及应对方案。

Redis的网络I/O和KV对读写都由主线程完成。若在主线程执行操作耗时太长,就会引起主线程阻塞。但Redis既有服务客户端请求的键值对增删改查操作,也有保证可靠性的持久化操作,还有主从复制时的数据同步操作。哪些会引起阻塞?

2 Redis阻塞风险点

Redis要和不同对象交互,有不同操作:

  • 客户端:网络IO,KV对CRUD操作,DB操作
  • 磁盘:生成RDB快照,记录AOF日志,AOF日志重写
  • 主从节点:主库生成、传输RDB文件,从库接收RDB文件、清空数据库、加载RDB文件
  • 分片集群实例:向其他实例传输哈希槽信息,数据迁移

2.1 客户端交互

Redis使用I/O多路复用,避免主线程一直处在等待网络连接或请求到来的状态,所以,网络I/O并非导致Redis阻塞因素。

2.1.1 集合全量查询和聚合操作

KV对的crud操作是Redis和客户端主要交互,也是Redis主线程执行的主要任务。复杂度高crud操作势必阻塞Redis。

最基本标准:看操作复杂度是否O(N)。Redis涉及集合的操作复杂度通常O(N):

  • 集合元素全量查询操作,如HGETALL、SMEMBERS
  • 集合的聚合统计操作,如交、并差集

2.1.2 删除大key

集合自身的删除也可能阻塞。

Q:不就直接数据删除,咋阻塞主线程?

A:删除本质是释放KV对占用内存空间。

释放内存只是第一步,为高效管理内存,应用程序释放内存时,os要把释放掉的内存块插入一个空闲内存块的链表,以便后续管理和再分配。这过程耗时,且会阻塞当前释放内存的应用程序。 所以,若突然释放大量内存,空闲内存块链表操作时间就会增加,导致Redis主线程阻塞。

啥时释放大量内存?

最常见于删除含大量元素的集合,即删除bigkey。不同元素数量集执行删除耗时:

集合类型 10万(8字节) 100万(8字节) 10万(128字节) 100万(128字节)
Hash 50ms 962ms 91ms 1980ms
List 25ms 133ms 29ms 283ms
Set 42ms 821ms 75ms 1347ms
Sorted Set 53ms 809ms 61ms 991ms
  • 当元素数量从10w到100w,集合类型删除时间增长幅度从5倍上升到近20倍
  • 集合元素越大,删除耗时越长
  • 当删除有100w个元素的集合时,最大删除时间绝对值已达1.98s(Hash类型)。Redis响应时间一般在微秒级,这不可避免严重阻塞主线程

2.1.3 清空数据库

Redis数据库级操作:清空数据库,如FLUSHDB、FLUSHALL也是重大阻塞风险,涉及删除、释放所有KV对。

2.2 磁盘交互阻塞

2.2.1 AOF日志同步写

磁盘I/O费时费力,Redis开发者早就设计为:

  • 子进程生成RDB
  • AOF日志重写

都由子进程负责执行,慢速的磁盘I/O就不阻塞主线程。

但Redis直接记录AOF日志时,会根据不同写回策略对数据做落盘保存。 一个同步写盘操作耗时大约1~2ms,若大量写操作需记录在AOF日志,并同步写回,就会阻塞主线程。

2.3 主从节点交互阻塞

2.3.1 从库加载RDB文件

主从集群中的主库需:

  • 生成RDB文件
  • 并传输给从库

主库在复制过程,创建、传输RDB都由子进程完成,不阻塞主线程。

但从库,接收RDB文件后,需用FLUSHDB命令清空当前数据库,恰好撞车三大阻塞点。从库清空当前数据库后,还要把RDB文件载入内存,RDB文件越大,加载越慢。

2.3.2 分片集群实例交互阻塞

  • 部署Redis Cluster时,每个Redis实例上分配的哈希槽信息,需在不同实例间传递 不过,哈希槽信息量不大
  • 当需负载均衡或有实例数变化时,数据会在不同实例间迁移 而数据迁移是渐进式执行

所以,一般这两类操作对Redis主线程阻塞影响不大。

但若使用Redis Cluster,且同时正好迁移大key,就会阻塞主线程,因Redis Cluster使用的同步迁移。 当无大key时,分片集群的各实例在进行交互时一般不会阻塞主线程。

在主线程中执行以上操作,势必导致主线程长时间无法服务其它请求。 为避免阻塞式操作,Redis提供异步线程机制:Redis会启动一些子线程,把一些任务移交子线程,让它们在后台处理。使用异步线程机制执行操作,可以避免阻塞主线程。

以上这些阻塞式操作可以被异步执行吗?

3 可异步执行的阻塞点

在分析阻塞式操作的异步执行的可行性前,先了解异步执行对操作的要求。

若一个操作能被异步执行,说明它不是Redis主线程关键路径上的操作。

3.1 关键路径操作

客户端把请求发给Redis后,等Redis返回数据结果:

  • 主线程接收到操作1后,由于操作1无需给客户端返回具体数据,所以,主线程可将其移交给后台子线程处理,同时只需给客户端返回“OK”。 操作1就不属关键路径操作,因其不用给客户端返回具体数据,所以可由后台子线程异步执行
  • 子线程执行操作1时,客户端又向Redis实例发送操作2,而此时,客户端需使用操作2返回的具体数据结果。若操作2不返回结果,则客户端将一直处等待状态。 该操作需把结果返给客户端,所以是关键路径操作,主线程须立即执行完该操作。

那Redis的写操作(如SET,HSET,SADD)属于关键路径吗?这需要客户端根据业务需要区分:

  • 若客户端依赖操作返回值的不同而处理不同业务逻辑,则HSET、SADD算关键路径,而SET操作不算关键路径
    因为HSET和SADD操作,若field或member不存在,Redis返回1,否则返0。而SET操作返回的结果都是OK
  • 若客户端不关心返回值,只关心数据是否写成功,则SET/HSET/SADD都不算关键路径,多次执行这些命令都是幂等的,这时可放到异步线程
  • 若Redis设置maxmemory,但未设置淘汰策略,这三个操作也都算关键路径
    因为若Redis内存超过maxmemory,再写入数据时,Redis返回的结果是OOM error,这种情况下,客户端需要感知有错误发生才行

3.2 各阻塞点分析

3.2.1 集合全量查询和聚合操作

Redis读都是关键路径操作,因为客户端发起读请求后,就会等待返回读取数据,再处理后续。所以,涉及读操作,无法异步!

推荐使用SCAN命令,分批读取数据,再在客户端进行聚合计算。

3.2.2  删除操作

无需给客户端返具体数据,不算关键路径操作。

“大K删除”、“清空数据库”同理,都可用后台子线程异步执行。

3.2.3 AOF日志同步写

为保证数据可靠性,Redis实例需保证AOF日志中的操作记录已落盘,这操作虽需实例等待,但不会返回具体数据结果给实例。所以,可使用一个子线程执行。

3.2.4 从库加载RDB文件

从库想对客户端提供数据存取服务,须将RDB文件加载完成。所以,这也属于关键路径操作,须让从库的主线程执行。把主库数据量大小控制在2~4GB左右,以保证RDB文件能以较快的速度加载。

综上,可使用Redis异步子线程机制实现大K删除,清空数据库及AOF日志同步写。

本文已收录在Github关注我,紧跟本系列专栏文章,咱们下篇再续!

  • 🚀 魔都架构师 | 全网30W技术追随者
  • 🔧 大厂分布式系统/数据中台实战专家
  • 🏆 主导交易系统百万级流量调优 & 车联网平台架构
  • 🧠 AIGC应用开发先行者 | 区块链落地实践者
  • 🌍 以技术驱动创新,我们的征途是改变世界!
  • 👉 实战干货:编程严选网
目录
相关文章
|
运维 监控 NoSQL
Redis 分享-AOF的阻塞简单记录
公司分享讨论一些东西 拿出来大家分享讨论下
884 0
Redis 分享-AOF的阻塞简单记录
|
存储 NoSQL Redis
Redis del bigkey即使开启了lazyfree,为什么还是阻塞的,但是别人又不阻塞?why
Redis del bigkey即使开启了lazyfree,为什么还是阻塞的,但是别人又不阻塞?why
|
负载均衡 NoSQL Redis
异步编程规避Redis的阻塞(中)
磁盘I/O一般费时费力,需重点关注。所以Redis开发者也早就把Redis设计为: 子进程生成RDB AOF日志重写
135 0
|
缓存 NoSQL API
一对一直播平台开发,导致Redis阻塞的原因和解决方式
一对一直播平台开发,导致Redis阻塞的原因和解决方式
|
NoSQL 关系型数据库 MySQL
Redis实现并发阻塞锁方案
由于用户同时访问线上的下订单接口,导致在扣减库存时出现了异常,这是一个很典型的并发问题,本篇文章为解决并发问题而生,采用的技术为Redis锁机制+多线程的阻塞唤醒方法。
|
NoSQL Redis
Redis 阻塞(学习笔记七)
1、持久化引起的主线程阻塞操作:fork阻塞、AOF刷盘阻塞、HugePage写操作阻塞 2、
791 0
|
6月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
1月前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
|
2月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
181 1
Redis专题-实战篇二-商户查询缓存
|
1月前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。

相关产品

  • 云数据库 Tair(兼容 Redis)