【问题标题】:Is there any approach to update and restart a server keeping its socket in a "suspended" state?是否有任何方法可以更新和重新启动服务器,使其套接字保持“暂停”状态?
【发布时间】:2018-11-01 20:28:55
【问题描述】:

在 TCP/IP 端口中有一个程序监听和应答请求(专有二进制协议)。但是这个程序需要更新,所以需要重新启动它才能继续在同一个端口上工作。

根据其协议,所有当前连接都可以关闭,因为所有客户端在关闭后都会立即重新建立新连接,但新连接应保留(但不拒绝)直到程序重新启动(对于少数秒),怎么办?

因此,一旦它再次运行,给定端口上的所有保留连接都可以被释放以到达侦听套接字。

让我们想象以下步骤:

  1. 一个服务器程序正在运行并监听给定的端口,让我们 说港口 A。
  2. 它要求外部资源(如操作系统或任何第三方模块)保留所有到达端口 A 的连接。
  3. 它会关闭当前与端口 A 建立的所有当前连接 - 这可能需要一些时间(可能需要几分钟,因为它将首先完成所有请求的服务)
  4. 它已重新启动,一个全新的可执行文件开始运行并开始侦听端口 A。
  5. 它要求外部资源释放所有保留的连接,以便它们现在可以到达端口 A,该端口现在已准备好接收连接。

第 2 步和第 4 步只是假设。

【问题讨论】:

  • 我知道的唯一方法是将监听套接字委托给一个单独的进程。但是,如果该过程也需要更新,那么您又回到了同样的问题。第 22 条军规。不值得尝试解决。只需让服务器杀死其活动客户端并关闭其侦听端口,然后在更新完成后重新打开该端口即可。在更新期间尝试重新连接的客户端将无法连接。应该对它们进行合理的编码,以 X 间隔重试 N 次,直到重新连接,并在 N 次尝试失败后超时并放弃。
  • 您最好在负载均衡器后面拥有多个程序实例。这样你就可以从一个实例中释放连接,并在它空闲时重新启动它。
  • @dbush:对不起,我没有列出在那种情况下我没有多个主机(计算机),但是有没有办法像负载均衡器那样切换连接,但是在进程之间(在同一个系统中)?
  • 负载均衡器不一定需要多个主机。让 LB 在一个端口上运行,应用程序的每个实例在不同的端口上运行。
  • @RemyLebeau:在非 Windows 系统上,可以通过本地 Unix 域套接字使用 SCM_RIGHTS 辅助有效负载,在进程之间传输侦听套接字描述符。所以,助手进程只需要在更新期间存活,之后就可以退出。事实上,我建议(在下面回答)让服务自己创建该子进程。不过,我猜 Windows 服务编写者只能使用负载均衡器。

标签: c sockets serversocket


【解决方案1】:

在 POSIXy 系统(Linux、Mac、BSD)中,服务进程有一种相当简单但聪明的方法来实现这一点。它甚至不需要任何特权。

核心思想很简单:当服务知道它将重新启动时,它将创建一个分离的子进程(在一个新的会话和进程组中,因此它将被重新设置为 init)持有侦听套接字.然后,父级将不再accept() 任何新连接,完成任何不完整的响应,并使用更新的二进制文件重新执行自身。

持有者进程还将侦听 Unix 域(流或 seqpacket;面向连接)套接字上的传入连接。更新的服务器实例将使用 SCM_CREDENTIALS 的辅助有效负载连接到持有者进程,其中包括内核验证的用户和进程运行的组,以及持有者进程可用于检查连接方是否为更新版本的进程 ID的二进制。 (在 Linux 中,这可以通过比较 /proc/PID/exestat()s 和预期的可执行文件来完成。)如果另一端被授权,则持有者使用 SCM_RIGHTS 辅助有效负载将侦听套接字描述符传回。最后,更新后的服务发送一个最后的谢谢,告诉持有者进程退出(这也关闭了它的侦听套接字描述符的副本)。

只要 backlog(请参阅 listen())足够(或在 Linux 中启用 syncookies,这使得 backlog 基本上不受限制),这应该是非常强大的方法。

如果需要,我可以提供有关如何在 Linux 中工作的示例代码。 (我认为这里的安全方面很重要,所以我肯定会只做 Linux 的工作,比如检查 /proc/PID/exe,以验证只有更新的二进制文件才能重新获取侦听套接字。)

【讨论】:

  • 在现代内核中是否有可能用SO_REUSEPORT而不是分叉来做同样的事情?
  • @gudok:如果新服务在旧服务退出之前启动(并准备好接受新连接),那么 SO_REUSEPORT 套接字选项将起作用。
【解决方案2】:

监听套接字与连接无关。诀窍是让新服务器启动并与旧服务器协调以接管对服务端口的侦听。一旦旧服务器关闭了它的监听套接字,新服务器就可以打开它自己的。然后它继续处理新的连接。

同时,旧服务器继续为新服务器接管之前接受的连接提供服务,并在完成连接后关闭每个连接。全部关闭后,旧服务器就可以退出了。

【讨论】:

    猜你喜欢
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 2017-05-05
    • 2018-11-08
    • 1970-01-01
    相关资源
    最近更新 更多