改了配置重载的瞬间,正在传输的请求会不会被直接掐断
改了配置重载的瞬间,正在传输的请求会不会被直接掐断?默认不会。重载(reload)与重启(restart)的差别正在这里:重载时主进程不退出,它按新配置拉起一批新的工作进程,把新连接交给它们,同时让旧工作进程进入退出流程——旧进程不再接受新连接,但会继续处理已经建立的连接,直到这些连接自己结束。所以短请求和长请求在重载瞬间都是安全的。会被掐断的情况只有一种:你给旧进程设了退出时限,时限一到,进程会尝试关闭当前所有仍打开的连接来结束自己。
退出时限管的是哪一种连接
nginx 核心模块文档里这条指令的说法很直接:worker_shutdown_timeout 为工作进程的优雅退出配置时限,时间到期后 nginx 会尝试关闭当前所有仍打开的连接以便完成退出;该指令从 1.11.11 版本引入,作用域是主配置层。注意它管的对象——已经建立的连接,而不是新来的请求。默认值是不设置,也就是让旧进程等到所有连接自然结束。这条默认值本身就说明了取舍:不设时限,退出时间不可控;设了时限,传输中的请求要承担被切断的代价。
哪些场景会被时限伤到
三类最典型。大文件上传:一次传输可能持续几十秒以上,时限短于传输时长,用户看到的就是上传到一半失败,而且重试还会撞上下一轮重载。长连接与流式响应:服务端推送、事件流这类连接的目的就是长期保持,任何时限都会主动把它切断。排队型任务接口:请求本身处理时间长,超时切断之后客户端无法得知服务端是否已经完成处理,容易出现重复提交。反过来,几乎不受影响的是一闪即断的短请求和已经完成响应的空闲连接。
设得太短和太长各有什么后果
时限太短的后果是可感知的失败:连接被强制关闭,客户端表现为中断,日志里则看不到明确原因,因为这是按设计执行的动作。时限太长或不设的后果更隐蔽:旧工作进程长期滞留,内存占用降不下来,同时新旧两套配置并存——限流阈值、缓存规则、证书在两组进程里不一致,排查时看同一份配置却得到两种行为。对内存敏感的场景这一点尤其值得注意,Go 技术栈的站点本身内存占用比 PHP 类程序低约 80%,滞留进程带来的额外占用在整体开销里因此更明显;页面加载速度直接关系到能否稳定承载单机约 500 万 PV 量级的负载,而旧进程没退干净时,新配置的优化要到下一轮才完全生效。合理的做法是把时限设成略长于业务里正常的最长请求时间,并在变更窗口内避免频繁重载。
改完之后的验证方式
先做语法与配置检查,确认新配置可加载;再执行重载而不是重启,保留正在进行的传输。重载之后确认三件事:新的工作进程已按新配置开始接活;旧进程处于退出状态且数量在减少;如果设了退出时限,观察是否在预期时间点归零。用 Docker 镜像部署时还要注意一点:容器里的进程信号要能传到主进程,重载动作才有效,直接重建容器属于重启,会连带切断全部连接,和重载不是一回事。AnQiCMS(安企CMS)默认监听 8001 端口,反向代理配置改动之后同样按这个顺序验证:先检查配置,再重载,然后从站外确认新规则生效、旧请求未被打断。
常见问题
问:重载和重启该选哪个? 答:只改配置内容选重载,改到必须重新加载程序本身的选项才选重启。重载保留传输中的连接,重启不保留。
问:怎么知道旧进程还活着? 答:看工作进程数量。重载后短暂出现两倍进程是正常现象,之后应回落到一批;长期不回落说明还有连接没结束。
问:长连接业务要不要设退出时限? 答:要设得更宽,或者不设。这类连接本身没有自然结束时间,短时限等于定期制造中断,除非你有明确的切换窗口。