如何更新正在运行的Python应用程序

2 投票
1 回答
1445 浏览
提问于 2025-04-17 04:41

我有一个Python应用程序,更准确地说,是一个网络应用。这个应用不能停下来,因为它需要和其他服务器、客户端进行交流,停机每分钟会损失很多钱,你懂的,就是那种需要24小时不间断运行的系统。

不过在我的一些兴趣项目中,我也经常使用WSGI框架,发现即使在非高峰时段,我也会遇到同样的问题。

想象一下,一个普通的服务器在使用TCP/UDP(你可以在这里放上你喜欢的WSGI/SIP/分类信息服务器等)。

现在你在远程服务器上执行一个git pull命令,这样新的Python文件就会被放到服务器上(这些文件只会影响数据处理,而不会影响实际的网络连接,所以不需要重新启动网络连接或以任何方式触碰网络部分)。

我通常不使用文件监控,因为我更喜欢用信号来唤醒内部的应用更新程序。

现在想象一下以下代码:

from mysuper.app import handler

while True:
  data = socket.recv()
  if data:

    socket.send(handler(data))

假设handler是一个有数据库连接、缓存连接等的应用。

更新这个handler的最佳方法是什么呢?

调用reload(handler)安全吗?

这样会破坏数据库连接吗?

数据库连接能在重启后存活吗?

当前的交易会丢失吗?

这样会产生反物质吗?

如果有的话,你们通常使用的最佳实践模式是什么?

1 个回答

4

调用 reload(handler) 是安全的。

这要看你在哪里初始化连接。如果你在 handler() 函数里面建立连接,那么当 handler() 这个对象不再使用时,连接会被自动清理掉。但你应该不会在主循环里面建立连接吧?我强烈建议你使用类似下面的方式:

dbconnection = connect(...)
while True:
    ...
    socket.send(handler(data, dbconnection))

这样做的原因之一是,你不会在一个紧凑的循环里进行昂贵的连接操作。

不过,我建议你采用完全不同的架构。可以创建一个监听进程,它基本上只负责监听 UDP 数据包,然后把这些数据包发送到像 RabbitMQ 这样的消息队列,再等待回复消息,把结果发回给客户端。然后再写你的实际服务器,让它们从消息队列中获取请求,处理这些请求,并发送回复消息。

如果你想升级 UDP 服务器,可以启动一个新的实例,监听另一个端口。更新你的防火墙规则,把进入的流量重定向到新端口。重新加载规则。然后杀掉旧的进程。这样就可以无缝切换了。

真正的好处在于将你的后端解耦。因为多个进程可以同时监听来自前端“代理”服务的相同消息,你可以在不同的机器上并行运行多个进程。如果要升级后端,启动一个新的实例,然后杀掉旧的实例,这样就不会有任何时间是没有实例在运行。

要扩展你的代理,可以在不同的端口或不同的主机上运行多个实例,并配置防火墙随机将进入的数据包重定向到其中一个代理。

要扩展你的后端,只需运行更多的实例。

撰写回答