V2EX NeedI09in
 NeedI09in 最近的时间轴更新
NeedI09in

NeedI09in

从来就没有什么救世主,人只能自救
V2EX 第 656002 号会员,加入于 2023-10-23 19:15:41 +08:00
NeedI09in 最近回复了
202 天前
回复了 doggg 创建的主题 分享创造 WebhookX 0.5.0
start!
2024-05-29 10:18:40 +08:00
回复了 abersheeran 创建的主题 程序员 fastapi 作者 Sebastián Ramírez 又给我打了一千美金!
恭喜,钱进账的声音就是好听
2024-05-13 17:34:09 +08:00
回复了 gongxuanzhang 创建的主题 程序员 在一个群里被恶心坏了
@Wesson 哈哈哈,有道理。这个解释很有意思,哈哈哈。
2024-05-13 14:03:14 +08:00
回复了 doggg 创建的主题 程序员 理解 Nginx 的优雅退出机制
2024-05-13 10:00:59 +08:00
回复了 doggg 创建的主题 程序员 理解 Nginx 的优雅退出机制
@doggg 嗯嗯,关于进程泄漏的说法应该是设置比较长,然后卡在 timer 那里。
我还遇到过一种进程泄漏,是 worker 里起了 timer ,然后 timer 是一直递归的,发现 reload 后,worker 一直处于 shutting down 。我加了检测 worker.exiting 进程便不泄漏了,现在看来应该是卡在 ngx_process_events_and_timers 里。
2024-05-13 09:53:48 +08:00
回复了 doggg 创建的主题 程序员 理解 Nginx 的优雅退出机制
@doggg 我可能没有表述清楚,我是指在 reload 前进来的请求耗时较长,且`worker_shutdown_timeout `设置较短,这样的话请求就返回报错了。但是这个不影响,还是看实际场景的,我是想到了这个例子哈哈。
2024-05-12 16:11:43 +08:00
回复了 doggg 创建的主题 程序员 理解 Nginx 的优雅退出机制
问题 1:
从大佬文章介绍出发,先看如何关闭 listen port
发现下列代码
``` c

ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {

#if (NGX_QUIC)
if (ls[i].quic) {
continue;
}
#endif

c = ls[i].connection;

if (c) {
if (c->read->active) {
if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {

/*
* it seems that Linux-2.6.x OpenVZ sends events
* for closed shared listening sockets unless
* the events was explicitly deleted
*/

ngx_del_event(c->read, NGX_READ_EVENT, 0);

} else {
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
}
}

ngx_free_connection(c);

c->fd = (ngx_socket_t) -1;
}

```
cycle->listening.elts 明显存储着监听相关对象
接着全局查询 cycle->listening.elts

https://github.com/nginx/nginx/blob/6f7494081ae8a56664afb480eff583d639b60ab4/src/core/ngx_cycle.c#L505-L620 部分找到代码,这部分应该是处理 listening 数组的一些信号,调用 ngx_open_listening_sockets 开始监听 cycle 中的端口。

那他真的是零停机吗?

从流程上来看是的,ngx_init_cycle 阶段就已经开始监听端口了,在启动新 worker 后,会按照顺序删除用于接受 IO 通知的事件,关闭监听端口,关闭空闲连接,之后 ngx_process_events_and_timers 会保证处理完所有的未完成的请求。

但是这一切都是基于在指定 worker_shutdown_timeout 时间内能够执行完请求的前提下,能够正常处理完请求,所以如果在这段时间内处理不完,或者接口 duration 超过设置超时时间,那这个请求就会来不及处理,就结束了。
所以,worker_shutdown_timeout 设置要贴合实际场景。这个值如果设置非常大,就会有 worker 进程泄露的风险,设置的比较小,就会 reload 期间,存在接口返回报错。

我认为 nginx 已经处理得很好了,在 reload 期间,有些耗时较长的接口会存在一定问题,但是要根据具体场景,去规划这个超时值就可以避免,我认为他是零停机的。
2024-05-11 23:12:00 +08:00
回复了 doggg 创建的主题 程序员 理解 Nginx 的优雅退出机制
@NeedI09in 补充一下,如果说的有误,麻烦大佬斧正,我对 nginx 底层源码了解甚少,只是看了这篇文章,尝试了解了一下源码。如果说的有什么不妥的地方,烦请大佬斧正,感谢。
不知道 ngx_close_idle_connections 是否是只 close 客户端的长连接,烦请大佬斧正。
2024-05-11 23:01:41 +08:00
回复了 doggg 创建的主题 程序员 理解 Nginx 的优雅退出机制
问题 2:
从小聪明的角度,感觉函数调用名字是 ngx_close_idle_connections ,应该只是关闭 client 和 upstream 的空闲连接。
从源代码角度分析,收到 NGX_RECONFIGURE_SIGNAL 信号后会走到 ngx_reconfigure ,会通过 ngx_start_worker_processes 启动一个新的 worker ,然后 ngx_signal_worker_processes 会处理掉旧 worker 。旧 worker 的处理方式跟大佬文章里写的一样,旧 worker 的 connection 是否还有效,我是从 ngx_close_idle_connections 出发看他是怎么获取的 connection 。发现他是这么取的 connections
``` c
void
ngx_close_idle_connections(ngx_cycle_t *cycle)
{
ngx_uint_t i;
ngx_connection_t *c;

c = cycle->connections;

for (i = 0; i < cycle->connection_n; i++) {

/* THREAD: lock */

if (c[i].fd != (ngx_socket_t) -1 && c[i].idle) {
c[i].close = 1;
c[i].read->handler(c[i].read);
}
}
}

```


侧面追踪发现 shutdown 超时也会出发关闭连接。大胆猜测 cycle->connections 就是连接池

``` c

static void
ngx_shutdown_timer_handler(ngx_event_t *ev)
{
ngx_uint_t i;
ngx_cycle_t *cycle;
ngx_connection_t *c;

cycle = ev->data;

c = cycle->connections;

for (i = 0; i < cycle->connection_n; i++) {

if (c[i].fd == (ngx_socket_t) -1
|| c[i].read == NULL
|| c[i].read->accept
|| c[i].read->channel
|| c[i].read->resolver)
{
continue;
}

ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
"*%uA shutdown timeout", c[i].number);

c[i].close = 1;
c[i].error = 1;

c[i].read->handler(c[i].read);
}
}
```

那就追踪 cycle ,从 ngx_master_process_cycle 函数追踪到这一行代码
``` c

cycle = ngx_init_cycle(cycle);
if (cycle == NULL) {
cycle = (ngx_cycle_t *) ngx_cycle;
continue;
}

```

显然,如果这里的 ngx_init_cycle 返回是 NULL ,那么长连接就会无效,问题就回到了 ngx_init_cycle 里发生了什么。大胆猜测这个 init_cycle 正常情况返回自己,异常情况返回 Null 。点进去还真是。
所以结论就是非空闲长连接不会释放,cycle 还是老 cycle ,看起来很合理

不知道我推论对不对,烦请大佬解惑。大佬的文章收益匪浅,看完有种会捕鱼了的快乐,非常感谢。
不过想请教大佬 ngx_temp_pool 是做什么用的,为何 ngx_temp_pool 是 Null 会需要清理长连接呢?
也就是这段代码 https://github.com/nginx/nginx/blob/master/src/core/ngx_cycle.c#L778C1-L801C6

最后感谢大佬的输出,受益匪浅。
怎么方便怎么来吧
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3085 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 13ms UTC 12:57 PVG 20:57 LAX 05:57 JFK 08:57
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86