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
来执行此操作。此信号以特殊方式处理:它像任何其他信号一样终止子进程,但父进程不会将其检测为严重错误,并将继续处理写入请求。