Redis 信号处理
Redis如何处理常见的Unix信号
本文档提供了关于Redis如何响应不同的POSIX信号(如SIGTERM
和SIGSEGV
)的信息。
本文档中的信息仅适用于Redis 2.6或更高版本。
SIGTERM 和 SIGINT
SIGTERM
和 SIGINT
信号告诉 Redis 优雅地关闭。当服务器接收到此信号时,它不会立即退出。相反,它会安排一个类似于 SHUTDOWN
命令执行的关闭操作。计划的关闭会尽快开始,具体来说,只要当前执行的命令终止(如果有的话),可能会有额外的延迟,延迟时间不超过 0.1 秒。
如果服务器被长时间运行的Lua脚本阻塞,请尽可能使用SCRIPT KILL
终止脚本。计划中的关闭将在脚本被终止或自发终止后立即运行。
此关闭过程包括以下操作:
- 如果有任何副本在复制过程中落后:
- 使用
CLIENT PAUSE
和WRITE
选项暂停尝试写入的客户端。 - 等待配置的
shutdown-timeout
(默认10秒),以便副本赶上主节点的复制偏移量。
- 使用
- 如果后台子进程正在保存RDB文件或执行AOF重写,子进程将被终止。
- 如果AOF处于活动状态,Redis会在AOF文件描述符上调用
fsync
系统调用,以将缓冲区刷新到磁盘。 - 如果Redis配置为使用RDB文件在磁盘上持久化,则会执行同步(阻塞)保存。由于保存是同步的,因此不会使用任何额外的内存。
- 如果服务器已守护进程化,则删除PID文件。
- 如果启用了Unix域套接字,它将被移除。
- 服务器以退出代码为零退出。
如果RDB文件无法保存,关闭操作将失败,服务器将继续运行以确保没有数据丢失。
同样,如果用户刚刚开启了AOF,并且服务器触发了第一次AOF重写以创建初始的AOF文件,但该文件无法保存,关闭操作将失败,服务器将继续运行。
自Redis 2.6.11起,除非接收到新的SIGTERM
信号或发出SHUTDOWN
命令,否则不会再次尝试关闭。
自 Redis 7.0 起,服务器在关闭前会等待滞后副本最多一个可配置的 shutdown-timeout
,默认情况下为 10 秒。
这提供了最大努力,以在没有配置保存点且 AOF 被停用的情况下最小化数据丢失的风险。
在 7.0 版本之前,在无磁盘设置中关闭一个负载较重的主节点更有可能导致数据丢失。
为了在此类设置中最小化数据丢失的风险,在关闭主节点之前,触发手动 FAILOVER
(或 CLUSTER FAILOVER
)将主节点降级为副本,并将其中一个副本提升为新的主节点。
SIGSEGV, SIGBUS, SIGFPE 和 SIGILL
以下信号被视为Redis崩溃:
- SIGSEGV
- SIGBUS
- SIGFPE
- SIGILL
一旦捕获到这些信号之一,Redis 将停止任何当前操作并执行以下操作:
- 将错误报告添加到日志文件中。这包括堆栈跟踪、寄存器转储以及有关客户端状态的信息。
- 自 Redis 2.8 起,快速内存测试作为崩溃系统可靠性的首次检查被执行。
- 如果服务器已守护进程化,则删除PID文件。
- 最后,服务器取消注册其自身对接收到的信号的处理程序,并重新向自身发送相同的信号,以确保执行默认操作,例如在文件系统上转储核心。
当子进程被终止时会发生什么
当执行仅追加文件重写的子进程被信号杀死时,Redis 会将其视为错误并丢弃(可能是部分或损坏的)AOF 文件。稍后它将尝试再次进行重写。
当执行RDB保存的子进程被终止时,Redis会将这种情况视为更严重的错误。虽然AOF文件重写失败可能导致AOF文件增大,但RDB文件创建失败会降低持久性。
由于生成RDB文件的子进程被信号杀死,或者当子进程以错误退出(非零退出代码)时,Redis进入一个特殊错误状态,不再接受任何写命令。
- Redis 将继续响应读取命令。
- Redis 将对所有写命令回复一个
MISCONFIG
错误。
此错误情况将持续存在,直到能够成功创建RDB文件为止。
无错误地删除RDB文件
有时用户可能希望在不生成错误的情况下终止RDB保存子进程。自Redis版本2.6.10起,可以使用信号SIGUSR1
来实现这一点。这个信号以特殊方式处理:它像其他信号一样终止子进程,但父进程不会将此检测为关键错误,并会继续处理写请求。