天天看点

uwsgi graceful reload

传统重启弊端:

后台上线功能,以往的做法是当有对代码进行更改,需要将新代码提供给用户时,将uwsgi服务器重新启动以使更改生效,但这个重启过程会将所有uwsgi的worker进程强行kill掉,然后再重新启动这些worker,导致的结果:

  • worker正在处理的请求无法正常处理完,
  • 重启过程中uwsgi无法正常接收请求,请求报502的错误,特别是由于某些原因重启时间可能很久

从stop uwsgi到start uwsgi需要一定时间,这期间就损害了用户的体验:

  1. 在网站上看到服务不可用的错误
  2. 在请求处理中用户等待很久
  3. 服务重启遇到程序bug,导致重启失败

优雅重启过程:

优雅的重启是一门艺术,优雅重启的方式有多种,但经过测试,链式重启是最优选择之一,且实现起来非常方便

链式重启的实现过程是一个接一个工人依次重新加载启动,直到所有工人都重新加载完毕。比如你有五个工人,工人A,工人B,工人C...,当你触发链式重启时:

  • 若工人A此刻正在处理请求,链式重启允许它完成此次请求,工人A开始重新加载最新代码
  • 如果工人A顺利完成加载,此时工人A接收到的请求都由最新代码处理,而其他4个工人则依然运行旧代码
  • 工人A顺利完成加载后,依次由工人B开始重新加载最新代码,重复此操作,直到每个工人都获取新代码。链式重启过程完成
  • 如果前一个工人没有加载成功,那么后一个工人也不会进行重启加载,这就意味着,如果程序有bug,其他工人都不会受到任何影响,依然能正常接收请求,这点非常棒,与传统野蛮重启方式相比有明显优势

优雅重启实现:

链式重启的实现非常简单,是通过touch一个文件来触发优雅重启过程:

  1. 打开uwsgi的以.ini后缀的配置文件,添加这一行:
    lazy-apps = true      
    这里的lazy-apps是uwsgi的其中一种加载模式,不指定的话,默认情况下,uwsgi在第一个进程中加载整个应用程序,在加载应用程序之后,它会多次fork本身,这种方式虽然能减少应用程序的内存使用,但它是对整个堆栈进行了重新加载,比较野蛮,而不是单独对每一个工人重新加载。而lazy-apps模式会为每个工人加载应用程序一次。假设它的工人数是n,那么它的时间复杂度就是O(n),这样可能会消耗更多的内存,但这种确保了服务一直处于可用状态,不至于停机,这也是我们第二部分重启过程的思路,每个工人都重新加载,而默认的模式做不到这一点,所以想要做到优雅重启,需要将uwsgi默认设置为lazy-apps
  2. 指定touch-reload-chain的文件
    touch-chain-reload = /home/ymserver/demeter/master/backend/website/demeter/settings.py      
    这个指定一个链式重启的touch文件,每次touch这个文件来触发优雅重启过程,无论何时更新代码,只需touch settings.py即可。如果跟踪uwsgi日志,您可以看到uwsgi如何执行此过程。以下是我实操的截图,我这里有8个工人在跑,
    uwsgi graceful reload

总结:

  • 优点:
    • 保证上线过程服务高可用,提升用户体验
    • 若新代码油污导致重启失败的,不会影响其他工人运行
  • 缺点:
    • 仅对代码更新有用
    • 占用较大内存
    • 需要增加一些工人来做逐个重启

继续阅读