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 域套接字,则会将其删除。
- 服务器将以退出代码 0 退出。
如果无法保存 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 文件会被删除。
- 最后,服务器会取消注册自己对接收到的信号的信号处理程序,并将相同的信号重新发送给自己,以确保执行默认操作,例如将核心转储到文件系统。
子进程被杀死时会发生什么
当执行 AOF 文件重写的子进程被信号杀死时,Redis 会将其视为错误,并丢弃(可能是部分或损坏的)AOF 文件。它稍后会尝试再次进行重写。
当执行 RDB 保存的子进程被杀死时,Redis 会将其视为更严重的错误。虽然 AOF 文件重写失败会导致 AOF 文件增大,但 RDB 文件创建失败会降低持久性。
由于生成 RDB 文件的子进程被信号杀死,或者子进程以错误退出(非零退出代码)退出,Redis 会进入一个特殊错误状态,在此状态下不再接受任何写入命令。
- Redis 将继续响应读取命令。
- Redis 将对所有写入命令返回
MISCONFIG
错误。
此错误状态将持续存在,直到能够成功创建 RDB 文件为止。
杀死 RDB 文件,不产生错误
有时用户可能希望杀死正在保存 RDB 的子进程,而不产生错误。从 Redis 2.6.10 版本开始,可以使用信号 SIGUSR1
来实现这一点。此信号的处理方式特殊:它像其他信号一样杀死子进程,但父进程不会将其检测为严重错误,并继续为写入请求提供服务。