Redis 其他知识点汇总
Redis 其他知识点
一、事务
(待补充内容)
二、多线程
2.1 多线程 I/O 的引入
因为 Redis 的性能瓶颈有时会出现在网络 I/O 的处理上,为了提高网络 I/O 的并行度,采用多个 I/O 线程来处理网络请求。但是对于命令的执行,Redis 仍然使用单线程来处理,引入了多线程 I/O 之后,Redis 的性能至少提升了一倍以上。
2.2 多线程配置
不过默认的多线程 I/O 只针对发送响应数据(write client socket),并不会以多线程的方式去处理读请求(read client socket)。
若要开启多线程处理客户端读请求,就需要把 Redis.conf 配置文件中的 io-threads-do-reads 配置项设为 yes,当然还有 IO 多线程个数的配置项。
注意: 主线程也算是一个 I/O 线程。
1 | io-threads N |
2.3 线程模型
在 Redis 6.0 版本之后,Redis 在启动的时候,默认会额外创建 4 个 IO 线程。
Redis-server 是 Redis 的主线程,平时我们使用的启动命令就是启动它,主要负责执行命令。
三、大 Key 问题
3.1 什么是 Redis 大 Key?
这里的大 key 并不是指 key 的值很大,而是指 key 对应的 value 很大。
一般而言,下面两种情况被称为大 key:
- String 类型:值大于 10 KB
- Hash、List、Set、Zset 类型:元素超过 5000 个
3.2 如何找到大 Key?
3.2.1 使用 redis-cli –bigkeys 命令
可以使用 redis-cli --bigkeys 命令查找大 key(自动扫描,快速报告大 key)。
1 | redis-cli --bigkeys |
3.2.2 使用 SCAN 命令
使用 SCAN 命令查找大 key(需要写脚本,自行判断大小)。
3.2.3 使用 RdbTools 工具
使用 RdbTools 工具查找大 key。
3.3 大 Key 会造成什么问题?
一般大 key 会带来下面四种影响:
3.3.1 客户端超时阻塞
因为 Redis 执行命令是单线程处理,所以在操作大 key 的时候会比较耗时,就会一直阻塞 Redis。
3.3.2 引发网络阻塞
每次获取大 key 的时候产生的网络流量较大。
比如说一个 key 的大小是 1 MB,每秒的访问量是 1000,那么每秒就会产生大概一个 G 的流量,这对于只有普通千兆网卡的服务器来说很明显压力过大了。
3.3.3 阻塞工作线程
如果使用 del 删除大 key,会阻塞工作线程,这样就不能执行后续其他的命令了。
3.3.4 内存分配不均
集群模型在 slot 分片均匀的情况下,会出现数据和查询倾斜的情况。部分有大 key 的 Redis 节点占用内存多,QPS 也会比较大。
3.4 如何删除大 Key?
3.4.1 删除大 Key 的原理
删除操作的本质就是要释放键值对占用的内存空间。
当然,释放内存只是第一步,为了可以更好地管理内存空间,在应用程序释放内存的时候,操作系统需要将释放掉的内存块插入一个空闲内存块的链表,以便后续进行管理和再分配,这个过程是需要一定的时间的,而且会阻塞当前释放内存的应用程序。
所以说,如果我们一下子释放了大量的内存,空闲内存块链表操作时间就会增加,相应地就会造成 Redis 主线程的阻塞。
所以,我们在删除大 key 的时候,一定要小心。
3.4.2 删除方案
下面给出了两种方案来删除大 key:
- 分批次删除
- 异步删除(Redis 4.0 版本以上)
3.4.3 方案一:分批次删除
删除大 key,我们可以针对具体大 key 的类型定制不一样的删除策略:
删除大 Hash:
使用 hscan 命令获取一定的字段数量,然后再使用 hdel 命令。
1 | # 示例:每次扫描100个字段并删除 |
删除大 List:
使用 ltrim 命令每次删除少量的元素。
1 | # 示例:每次从右侧删除100个元素 |
删除大 Set:
使用 sscan 命令每次扫描一定的元素,然后再用 srem 命令删除。
1 | # 示例:每次扫描100个元素并删除 |
删除大 Zset:
使用 zremrangebyrank 每次删除一定的元素。
1 | # 示例:每次删除前100个元素 |
3.4.4 方案二:异步删除(推荐)
从 Redis 4.0 版本之后,更推荐使用异步删除法,也就是使用 unlink 命令替代 del 来删除,这样 Redis 会将这个 key 放入到一个异步线程中进行删除,不会阻塞主线程。
1 | # 使用 unlink 替代 del |
unlink 与 del 的区别:
- del 命令:同步删除,会阻塞主线程
- unlink 命令:异步删除,不会阻塞主线程,由后台线程处理
四、总结
4.1 多线程特性
| 特性 | 说明 | 配置项 |
|---|---|---|
| 多线程 I/O | 提升网络 I/O 并行度 | 默认开启(Redis 6.0+) |
| 命令执行 | 仍然是单线程 | 无需配置 |
| 读请求多线程 | 需要手动开启 | io-threads-do-reads yes |
| I/O 线程数 | 默认 4 个 | io-threads N |
4.2 大 Key 问题总结
| 问题类型 | 影响 | 解决方案 |
|---|---|---|
| 客户端超时 | 阻塞 Redis 主线程 | 分批删除或异步删除 |
| 网络阻塞 | 占用大量带宽 | 避免频繁访问大 key |
| 工作线程阻塞 | 影响其他命令执行 | 使用 unlink 异步删除 |
| 内存分配不均 | 集群数据倾斜 | 拆分大 key 或重新分片 |
4.3 大 Key 删除方案对比
| 删除方案 | 优点 | 缺点 | 适用版本 |
|---|---|---|---|
| 分批次删除 | 不阻塞主线程 | 需要编写脚本,操作复杂 | 所有版本 |
| 异步删除(unlink) | 简单高效,不阻塞主线程 | 需要 Redis 4.0+ | Redis 4.0+ |
4.4 最佳实践
多线程配置:
- Redis 6.0+ 默认开启多线程 I/O
- 根据服务器 CPU 核心数合理配置 I/O 线程数
- 命令执行仍然是单线程,保证数据一致性
避免大 Key:
- 设计时避免单个 key 存储过多数据
- String 类型控制在 10 KB 以内
- 集合类型控制在 5000 个元素以内
监控大 Key:
- 定期使用
redis-cli --bigkeys扫描 - 使用监控工具实时监控 key 的大小
- 设置告警阈值及时发现问题
- 定期使用
删除大 Key:
- Redis 4.0+ 优先使用
unlink命令 - Redis 4.0 以下版本使用分批删除
- 避免在业务高峰期删除大 key
- Redis 4.0+ 优先使用
拆分大 Key:
- 将大 Hash 拆分成多个小 Hash
- 将大 List 拆分成多个小 List
- 使用合理的 key 命名规范便于管理
五、总结
Redis 的多线程特性和大 Key 问题是实际应用中需要重点关注的两个方面:
- 多线程 I/O:Redis 6.0 引入多线程 I/O 提升了网络处理性能,但命令执行仍是单线程,保证了数据一致性
- 大 Key 问题:会导致阻塞、网络拥塞、内存分配不均等问题,需要通过合理设计、监控和删除策略来避免
- 最佳实践:合理配置多线程参数,避免产生大 key,使用异步删除,建立监控告警机制
理解这些知识点,有助于我们更好地使用 Redis,构建高性能、高可用的应用系统。