大数据开发技术学习,Python程序中不同的重启机制

科多大数据带你看看,大数据开发技术学习之Python程序中不同的重启机制

分析典型案例:

Celery 分布式异步任务框架

Gunicorn Web容器

之所以挑这两个,不仅仅是应用广泛,而且两个的进程模型比较类似,都是Master、Worker的形式,在热重启上思路和做法又基本不同,比较有参考意义

知识点:

atexit

os.execv

模块共享变量

信号处理

sleep原理:select

文件描述符共享

这几个知识点不难,区别只在于Celery和Gunicorn的应用方式。如果脑海中有这样的知识点,这篇文章也就是开阔下视野而已。。。

Celery和Gunicorn都会在接收到HUP信号时,进行热重启操作

Celery的重启:关旧Worker,然后execv重新启动整个进程

Gunicorn的重启:建立新Worker,再关旧Worker,Master不动

下面具体的看下它们的操作和核心代码。

对于Celery:

def _reload_current_worker():

platforms.close_open_fds([

sys.__stdin__, sys.__stdout__, sys.__stderr__,

])

os.execv(sys.executable, [sys.executable] + sys.argv)

def install_worker_restart_handler(worker, sig='SIGHUP'):

def restart_worker_sig_handler(*args):

"""Signal handler restarting the current python program."""

import atexit

atexit.register(_reload_current_worker)

from celery.worker import state

state.should_stop = EX_OK

platforms.signals[sig] = restart_worker_sig_handler

HUP上挂的restart_worker_sig_handler 就做了两件事:

注册atexit函数

设置全局变量

考虑到这个执行顺序,应该就能明白Celery 是Master和Worker都退出了,崭新呈现。。

看过APUE的小伙伴,应该比较熟悉 atexit 了,这里也不多说。os.execv还挺有意思,根据Python文档,这个函数会执行一个新的函数用于替换掉 当前进程 ,在Unix里,新的进程直接把可执行程序读进进程,保留同样的PID。

在Python os标准库中,这是一整套基本一毛一样的函数,也许应该叫做函数族了:

os. execl ( path , arg0 , arg1 , … )

os. execle ( path , arg0 , arg1 , … , env )

os. execlp ( file , arg0 , arg1 , … )

os. execlpe ( file , arg0 , arg1 , … , env )

os. execv ( path , args )

os. execve ( path , args , env )

os. execvp ( file , args )

os. execvpe ( file , args , env )

以exec开头,后缀中的l和v两种,代表命令行参数是否是变长的(前者不可变),p代表是否使用PATH定位程序文件,e自然就是在新进程中是否使用ENV环境变量了

然后给worker的state.should_stop变量设置成False。。。 模块共享变量 这个是PythonFAQ里提到的一种方便的跨模块消息传递的方式,运用了Python module的单例。我们都知道Python只有一个进程,所以单例的变量到处共享

而should_stop这个变量也是简单粗暴,worker在执行任务的循环中判断这个变量,即执行异步任务->查看变量->获得异步任务->继续执行 的循环中,如果True就抛出一个【应该关闭】异常,worker由此退出。

这里面有一个不大不小的坑是:信号的发送对于外部的工具,例如kill,是非阻塞的,所以当HUP信号被发出后,worker可能并没有完成重启(等待正在执行的旧任务完成 才退出和新建),因此如果整个系统中只使用HUP信号挨个灰度各个机器,那么很有可能出现全部worker离线的情况

接下来我们看看Gunicorn的重启机制:

信号实质上挂在在Arbiter上,Arbiter相当于master,守护和管理worker的,管理各种信号,事实上它init的时候就给自己起好Master的名字了,打印的时候会打出来:

class Arbiter(object):

def __init__(self, app):

#一部分略

self.master_name = "Master"

def handle_hup(self):

"""\

HUP handling.

- Reload configuration

- Start the new worker processes with a new configuration

- Gracefully shutdown the old worker processes

"""

self.log.info("Hang up: %s", self.master_name)

self.reload()

这里的函数文档里写了处理HUP信号的过程了,简单的三行:

读取配置

开启新worker

优雅关闭旧Worker

reload函数的实现本身没什么复杂的,因为Gunicorn 是个Web容器,所以master里面是没有业务逻辑的,worker都是master fork出来的,fork是可以带着文件描述符(自然也包括socket)过去的。这也是Gunicorn可以随意增减worker的根源

master只负责两件事情:

拿着被Fork的worker的PID,以供关闭和处理

1秒醒来一次,看看有没有worker超时了需要被干掉

while True:

sig = self.SIG_QUEUE.pop(0) if len(self.SIG_QUEUE) else None

if sig is None:

self.sleep()

self.murder_workers()

self.manage_workers()

continue

else:

#处理信号

在sleep函数中,使用了select.select+timeout实现,和time.sleep的原理是一样的,但不同之处在于select监听了自己创建的一个PIPE,以供wakeup立即唤醒

总结

以上就介绍了Celery和Gunicorn的重启机制差异。

从这两者的设计来看,可以理解他们这样实现的差异。

Celery是个分布式、异步的任务队列,任务信息以及排队信息实质上是持久化在外部的MQ中的,例如RabbitMQ和redis,其中的持久化方式,这应该另外写一篇《高级消息队列协议AMQP介绍》,就不在这里说了,对于Celery的Master和Worker来说,可以说是完全没有状态的。由Celery的部署方式也可以知道,近似于一个服务发现的框架,下线的Worker不会对整个分布式系统带来任何影响。唯一的例外可能是Beat组件,作为Celery定时任务的节拍器,要做少许改造以适配分布式的架构,并且实现Send Once功能。

Gunicorn作为Python的Web容器之一,会接收用户的请求,虽然我们通常都会使用nginx放在Gunicorn前方做反向代理,通常也可以使用nginx来做upstream offline、online的热重启,但那就不是一个层次的事情了

这里回头来再吐槽Golang

项目中使用到了Golang的一个Web框架,Golang在1.8中也已经支持Http.Server的热关闭了,但是一是因为刚出不就(竟然现在才出),二是因为Golang的进程模型和Python大相近庭,go协程嘛,目前还没有看到那个Web框架中真正实现Gunicorn类似的热重启。

Golang 在fcgi的操作应该就类似Python之于wsgi了。。我感觉我是选择错了一个web框架

也没看见有人用syscall.Exec来用一下execve系统调用,Golang也没看见有人用socket REUSE。。作为一个懒惰的人感觉很蛋疼。。。

先让nginx大法做这件事情好了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容