1. 服务架构
目前 Redis 的线程/进程有如下:
线程/进程类型 | 职责 | 创建方式 | 出现版本 |
---|---|---|---|
主线程 | 执行命令 | 默认创建 | 所有版本 |
BIO 后台线程 | 处理异步任务,如关闭旧的文件描述符、AOF 刷盘、惰性删除 | 默认创建 | 3.0+ |
I/O 多线程 | 并行处理网络数据的读取和响应的发送 | 需配置开启 | 6.0+ |
持久化子进程 | 执行 RDB 持久化、AOF 重写 | 需要时创建 | 所有版本 |
I/O 多线程
Redis 在 6.0 之前主要是单线程架构,所有命令都是串行执行的。Redis 6.0 引入了多线程 I/O 模型,用于处理客户端连接、读取网络数据和传输返回数据,而命令执行仍然是单线程的,以保证原子性和隔离性。
I/O 多线程默认不启用,需要配置启用:
# 启用 I/O 多线程
io-threads-do-reads yes
# 设置 I/O 线程数量,建议为 CPU 核数的 1/2 或 1/4
io-threads 4
I/O 多线程适用于 CPU 使用率较低而网络 I/O 瓶颈的场景,而对于计算密集型任务或 I/O 没有瓶颈的场景则效果不显著。
网络模型
在 Redis 6.0,仍然是由主线程负责监听和接收客户端的连接请求,而 I/O 多线程则负责并行读取已建立连接的 socket 数据,读取请求数据,接着主线程会解析请求并按顺序执行所有命令,最后由 I/O 多线程并行将命令的响应结果写入 socket,发送至客户端。
Redis 通过事件驱动模型和多路服用来实现非阻塞 I/O,可以在单个线程同时监控和处理多个输入输出源。在 Linux 上使用的是 epoll,在 BSD/macOS 上使用的是 kqueue,对于其他未支持以上的系统使用 select 作为备选。
Redis 使用非阻塞套接字进行网络通信,对套接字进行读写操作时,如果不能立即完成,系统会立即返回而不阻塞线程,使 Redis 可以迅速响应多个客户端请求。
2. 部署方式
单节点架构
对于数据量较小、可用性要求不高的开发测试环境,只需要部署单节点的 Redis。
这种方式的部署和维护成本最低,但是性能和存储容量有限,存在单点故障风险。
主从复制
对于读多写少的场景,通过主从复制,部署一个主节点和多个从节点,主节点处理写请求,从节点处理读请求。
这种方式提高了 Redis 的读请求的性能,但是当主节点存在问题时需要手动进行故障转移和主从切换,写请求在高并发时可能成为瓶颈。
哨兵
部署一个主节点和多个从节点,然后部署多个 Redis 哨兵节点对 Redis 数据节点进行监控。
这样既能提高 Redis 的读性能,还能利用哨兵的监控和自动故障转移,实现 Redis 的高可用。
集群
部署 Redis 集群,集群内能将数据分散多个分片,存储在多个 Redis 主节点上,每个 Redis 主节点还能够配置相应的从节点。
Redis 集群本身具有故障自动重定向和故障转移的高可用性,同时将数据分散为多个分片也大大扩展了 Redis 处理写请求的能力。
proxy
使用代理服务器如 Twemproxy 或 Redis Cluster Proxy 来管理多个 Redis 节点,在代理层进行负载均衡和请求分发。
通过引入 proxy 提高系统整体性能,同时隐藏了后端 Redis 节点的复杂性,代价是增加了系统的组件复杂度和需要维护额外的代理服务器。