无需停机即可重新加载新的 Nginx 配置

无需停机即可重新加载新的 Nginx 配置

我有一台 Nginx 服务器,它不断处理大量请求。我希望能够更改服务器的配置文件,并在零停机时间内动态重新加载它。

我在 shell 中运行以下行:

httperf --server=127.0.0.1 --port=80 --uri=/ --num-conns=1 --num-calls=10

当它发送请求时,我正在重新加载我的 nginx 配置。我尝试了以下两个选项:

sudo nginx -s reload

sudo kill -s HUP [pid]

这两个请求都会导致 httperf 返回一些错误。平均而言,在两次正常请求之后,httperf 会退出并打印其日志,其中包含以下相关行:

Errors: total 1 client-timo 0 socket-timo 0 connrefused 0 connreset 1

我在很多地方都看到过,重新加载应该无缝完成且没有停机时间,但从我运行的测试来看,情况似乎有所不同。

我的问题是:

  1. 我是否以错误的方式执行了测试?为什么此连接被重置?
  2. 这个问题有解决办法吗?
  3. 我实际上需要一个负载平衡器,可以动态地添加和删除服务器,有没有更好的解决方案可以解决我的问题?

提前感谢您的帮助,期待看到一些有见地的答案。

答案1

要理解以下答案,需要一些背景知识:

我是否以错误的方式进行测试?

是的,你的测试有些不正确。问题是你的测试使用 PERSISTENT 连接发送 10 个请求。你可以通过运行以下测试轻松检查它,并且不会有任何连接重置(因为你每个连接只发送一个请求):

httperf --server=127.0.0.1 --port=80 --uri=/ --num-conns=10 --num-calls=1

为什么我会重置此连接?

如果你看看nginx 文档,你会发现:

旧工作进程收到关闭命令后,将停止接受新连接并继续处理当前请求,直到处理完所有请求。 此后,旧工作进程退出。

这是真的,但文档没有提到持久连接发生了什么。我在旧的邮件列表. 在当前正在运行的请求得到处理后,nginx 将通过[FIN, ACK]向客户端发送来启动持久连接关闭。

为了检查这一点,我使用了 WireShark 并配置了一个简单的工作程序,该工作程序在收到请求后会休眠 5 秒然后回复。我使用以下命令发送请求:

httperf --server=127.0.0.1 --port=80 --uri=/ --num-conns=1 --num-calls=2

在发出上述命令后,我重新加载了 nginx(当时它正在处理第一个请求)。以下是 WireShark 嗅探到的包:

wireshark 流量

  • 3892-3894-通常建立 TCP 连接。
  • 3895 – 客户端发送了第一个请求。
  • 3896 – 服务器确认 3895。
  • 在这里nginx reload被处决。
  • 4089 – 服务器已发送响应。
  • 4090-服务器发送关闭连接信号。
  • 4091-客户端确认 4089。
  • 4092-客户端确认 4090。
  • 4093 - 客户端发送了第二个请求(什么鬼?
  • 4094-客户端发送关闭连接信号。
  • 4095-服务器确认4093。
  • 4096-服务器确认 4094。

没关系,该服务器没有对第二个请求发送任何响应。根据TCP 连接终止

终止的一方不能再向连接发送任何数据,但另一方可以。终止方应继续读取数据,直到另一方也终止。

下一个问题是为什么客户端收到服务器的关闭连接信号后会出现 4093 错误?

这可能是回答

我想说的是 POST 与 FIN 同时发生,即客户端发送 POST 是因为其 TCP 堆栈尚未处理来自服务器的 FIN。请注意,数据包捕获是在系统处理数据之前完成的。

我无法对此发表评论,因为我不是网络专家。也许其他人可以给出更深刻的答案,说明为什么发送了第二个请求。

更新型多巴胺之前链接的问题不相关。问单独问题关于这个问题。

这个问题有解决办法吗?

正如在邮件列表

HTTP/1.1 客户端需要处理保持连接关闭,所以这应该不是问题。

我认为应该在客户端处理。如果服务器关闭了连接,客户端应该打开新连接并重试请求。

我实际上需要一个负载平衡器,可以动态地添加和删除服务器,有没有更好的解决方案可以解决我的问题?

我不知道其他服务器的情况,所以无法在此提供建议。

只要您的客户端可以正确处理连接关闭,就没有任何理由阻止您使用 nginx。

相关内容