Redis拒绝策略
Redis 的运行流程 (核心:单线程事件循环)
Redis 的核心处理模型基于一个单线程的事件循环,这使得命令的执行具有原子性。其运行流程可以概括如下:
-
启动与初始化:
- Redis 服务器启动,加载配置文件(
redis.conf)。 - 初始化内部数据结构(如键空间、过期字典等)。
- 绑定监听端口,准备好接受客户端连接。
- Redis 服务器启动,加载配置文件(
-
事件循环 (Event Loop):
- 这是 Redis 运行的核心。它使用 I/O 多路复用技术(如
epoll,kqueue,select)来同时监控多个文件描述符(主要是客户端套接字)。 - 循环不断检查是否有事件发生:
- 文件事件 (File Event): 主要是客户端的连接请求 (
accept) 和已连接客户端的命令请求 (read)。 - 时间事件 (Time Event): 主要是定时任务,如
serverCron函数(负责周期性任务,如过期键清理、持久化检查、集群状态维护等)。
- 文件事件 (File Event): 主要是客户端的连接请求 (
- 这是 Redis 运行的核心。它使用 I/O 多路复用技术(如
-
处理客户端请求:
- 当 I/O 多路复用器检测到某个客户端套接字可读(有命令发送过来)时:
- 读取客户端发送的命令请求。
- 解析命令(命令名称、参数个数、参数值)。
- 在单线程中执行命令对应的处理函数。
- 将命令执行结果写入该客户端对应的输出缓冲区。
- 当该客户端的套接字下次变为可写时,将输出缓冲区的内容发送给客户端。
- 当 I/O 多路复用器检测到某个客户端套接字可读(有命令发送过来)时:
-
后台处理:
- 时间事件
serverCron会周期性地执行,处理一些后台任务:- 过期键删除:被动删除(访问时检查) + 主动删除(定期随机扫描过期字典)。
- 持久化操作:根据配置触发 RDB 快照或 AOF 重写。
- 主从复制相关:心跳、同步等。
- 集群管理:节点通信、故障检测。
- 更新统计信息:内存使用、命令执行数等。
- 调整哈希表大小:渐进式 rehash。
- 处理关闭的客户端连接。
- 时间事件
-
内存管理:
- 执行命令可能导致内存使用增加。
- 当内存使用达到配置的
maxmemory上限时,会根据配置的内存淘汰策略来释放内存(见下文)。
Redis 的内存淘汰策略 (内存满时的“拒绝策略”)
当 Redis 使用的内存达到 maxmemory 配置的限制时,新写入的命令如果需要申请更多内存,就会触发内存淘汰机制。Redis 提供了多种策略,通过 maxmemory-policy 配置项进行选择:
-
noeviction(默认策略):- 行为:当内存达到上限时,新写入的命令(会要求分配内存的命令,如
SET,LPUSH,HMSET等)会返回错误 (通常是(error) OOM command not allowed when used memory > 'maxmemory')。 - 特点:不会淘汰任何已有的键值对。读请求通常不受影响(除非该命令需要临时内存,如排序)。
- 适用场景:数据绝对不能丢失,且能接受写入失败的情况。
- 行为:当内存达到上限时,新写入的命令(会要求分配内存的命令,如
-
volatile-lru(Least Recently Used - 最近最少使用):- 行为:在设置了过期时间 (
expire) 的键中,淘汰最近最少使用的键。 - 特点:只淘汰有 TTL 的键。使用近似 LRU 算法(随机采样 N 个键,淘汰其中最久未使用的),并非严格 LRU,以平衡精度和效率。
- 适用场景:希望优先保留常用数据(即使它设置了过期时间),淘汰不常用的过期数据。
- 行为:在设置了过期时间 (
-
allkeys-lru:- 行为:在所有键中(无论是否设置过期时间),淘汰最近最少使用的键。
- 特点:近似 LRU 算法。
- 适用场景:希望优先保留常用数据,即使某些数据没有设置过期时间。这是生产环境非常常用的策略。
-
volatile-lfu(Least Frequently Used - 最不经常使用):- 行为:在设置了过期时间的键中,淘汰使用频率最低的键(LFU 算法)。
- 特点:Redis 4.0 引入。LFU 统计访问频率。
- 适用场景:希望淘汰访问次数最少的过期数据。
-
allkeys-lfu:- 行为:在所有键中,淘汰使用频率最低的键。
- 特点:LFU 算法。
- 适用场景:希望淘汰访问次数最少的数据,无论是否过期。
-
volatile-random:- 行为:在设置了过期时间的键中,随机淘汰一个键。
- 特点:简单随机。
- 适用场景:对淘汰规则无特殊要求,只需要释放部分过期键的内存。
-
allkeys-random:- 行为:在所有键中,随机淘汰一个键。
- 特点:简单随机。
- 适用场景:对淘汰规则无特殊要求,只需要释放内存。
-
volatile-ttl(Time To Live):- 行为:在设置了过期时间的键中,淘汰剩余生存时间 (TTL) 最短的键。
- 特点:优先淘汰即将过期的键。
- 适用场景:希望尽快释放即将过期的键所占用的内存。
总结:
- Redis 的核心是一个单线程事件循环,通过 I/O 多路复用处理并发连接和定时任务。
- 当内存达到上限 (
maxmemory) 时,根据配置的maxmemory-policy来决定如何处理新写入的请求:noeviction:拒绝写入。- 其他策略:通过淘汰一些键来释放空间。
- 淘汰策略主要分为:
- 淘汰范围:所有键 (
allkeys-*) vs 仅过期键 (volatile-*)。 - 淘汰算法:LRU (最近最少用) vs LFU (最不经常用) vs Random (随机) vs TTL (最快过期)。
- 淘汰范围:所有键 (
- 选择合适的淘汰策略需要根据应用的具体需求和数据访问模式来决定。
allkeys-lru和volatile-lru是比较常用的策略。务必监控内存使用情况并合理设置maxmemory。
