前面对于 Celery 的分布式处理已经做了一些介绍,例如第五章的 远程控制 和第六章的 Event机制,但是,我认为这些分布式都比较简单,并没有体现出多实例之间的协同作用,所以,今天就来点更加复杂的,对于多实例直接的交互更多,这就是 Gossip 和 Mingle。

Mingle

在 Celery 的介绍中,Mingle 主要用在启动或者重启的时候,它会和其他的 worker 交互,从而进行同步。同步的数据有:

  • 其他 worker 的 clock
  • 其他 worker 已经处理掉的 tasks

这其实也就是它的所有功能的,所以你可以猜测功能应该很简单吧?不妨一起来看看,最开始还是回忆一下第一篇文章中的 Bootstep,所以我们可以毫无压力得找出源码所在的文件:

这里从注释中可以很简单得看出 Mingle 的作用,然后初始化也是比较简单,关键还是 Line 37start,需要我们关注 sync 做了什么,为什么上来二话不说就 sync?其实上来就 sync 很好理解,毕竟 Mingle 的作用就是进行 sync 嘛,所以我们要关注的是如何实现的:

这里原来的代码有点冗余,我给忽略掉了,直接上精简后的代码,所以你可以很清晰得看到代码的逻辑是这样的:

  1. Mingle 向每一个 Worker 发送问候:hello
  2. 每个 Worker 都向 Mingle 回复自己的信息(clock 和 tasks)
  3. Mingle 更新自己的信息

这些逻辑我们从精简后的代码可以简单看出来,所以就不细说了,但是有一点需要展开讲讲,那就是 Line 47 中的 inspect.hello,这应该是 第五篇 的内容,但是,之前只是介绍了一下如何注册,并没有对这些命令一一解析,所以这里用到了,我们就不妨看看里面的内容。

ok,这里我们可以看到在 Line 319、320 就返回了两个东西,分别是:

  • revoked:当前 worker 记录的已被完成的 tasks
  • clock:当前 worker 的 clock

然后就返回到刚起来的 worker 了,收到这个消息的 worker 就根据这两个信息刷新自己的状态,然后继续运行,Mingle 也就完成了自己的任务了。

Gossip

和 Mingle 不同,Gossip 却是消费 Event 的,本来按道理应该放在 第六篇 中介绍,但是由于篇幅原因,所以一起放在这里来说了,不多赘述,我们直接看 Bootstep

由于 Gossip 的初始化内容太多,所以我也不全都展开了,挑了些重点(还是很多),但是目前我们可以忽略大部分的内容,最先需要关注的是 Line 24,如果你够细心的话你会发现这个 Bootstep 和其他不一样,因为它继承的是 ConsumerStep,这是会注册一个 Consumer 的!

然后我们没啥好看了,所以按照套路还是看看 start 呗,然而它调用的也是父类的 start,所以,没办法咯,直接跟过去:

诺,是这样吧,是增加了 Consumer,这样的话,我们就必须看看这个 Consumer 是什么了,能够消费什么样的数据:

好,这样就清晰了,所有关于 worker.# 的 Event 都被这里消费了,这里算是看完了。

那现在的问题变成了这些 Event 都是从哪里过来的,我们有必要对源头进行一下追踪,但是,怎么追踪呢?回想一下 第六篇 中讲 Event 的消息传递的那里,再和这里一对比,事情就很清楚了。

你以为 Gossip 就这么结束了么?嘿嘿,那你就被 Celery 给蒙骗了,悄悄告诉你,Celery 在 Gossip 中埋伏了一个厉害的功能,但是没有对外宣称,那就是 Leader 选举!,不信?我带你去看看:

这是选举的入口,先不解析代码,我们先来看看有谁调用了它:

ok,可以发现这有个 control 命令用到了它,这里有注释,我们可以看到参数分别代表的意思:

  • id:唯一的标识,用于识别一次选举
  • topic:本次选举的 topic,其实是标识 action 的类型
  • action:本次选举的目的,选中的 leader 负责处理这个 action

那么这样我们就清楚了,首先,有一个 action 需要执行,但是,那么多的 worker,交给谁执行呢?这就需要进行 选举,那么选举的方式是怎么进行的呢,我先用一张图来描述一下这个过程:

  1. control 表示需要进行一个选举,然后一个 worker 的 gossip 就发送了一个 Event:worker-elect,然后所有的 Worker 都能接收到:

  2. 每个 Worker 接收到之后,就对这个选举进行响应,将自己的选号(clock)送过去,这样,每个 Worker 在发送选号的同时,也接收到别人的选号,因为收发的路线太多,我就找一个 Worker 来表示收,但是其他 Worker 也是有收的,只是我没有标出来:

  3. 当一个 Worker 收到所有 Worker 的 ACK 之后,那么它就会对所有的 Worker 的 选号 进行排序,选出其中 最大的选号 作为本次选举的 Leader,如果 Leader 是自己那么就处理这个 Action,如果不是自己,那么忽略,应该被选中的 Leader 也在执行这个过程,所以不需要别人担心。

这就是实际执行的示意图,对应到代码就分别是:

  1. 第一步中的 Control 要求选举和发送选举 Event 我们前面已经看过了
  2. Worker 收到选举 Event 之后,发出自己的参选声明:

  3. 每个 Wroker 对别人回应的参选信息进行选举:

ok,整个流程就是这样的了,那么问题来了,万一有一个 Worker 收不到 replies 或者发出的 reply 不小心丢了会怎么样?是不是整个选举过程就进行不下去了?我好像没有看到 Celery 有在这方面做一些努力。

Celery 源码解析七:Worker 之间的交互的更多相关文章

  1. Celery 源码解析三: Task 对象的实现

    Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...

  2. Celery 源码解析五: 远程控制管理

    今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...

  3. Celery 源码解析六:Events 的实现

    在 Celery 中,除了远程控制之外,还有一个元素可以让我们对分布式中的任务的状态有所掌控,而且从实际意义上来说,这个元素对 Celery 更为重要,这就是在本文中将要说到的 Event. 在 Ce ...

  4. QT源码解析(七)Qt创建窗体的过程,作者“ tingsking18 ”(真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法)

    前言:分析Qt的代码也有一段时间了,以前在进行QT源码解析的时候总是使用ue,一个函数名在QTDIR/src目录下反复的查找,然后分析函数之间的调用关系,效率实在是太低了,最近总结出一个更简便的方法, ...

  5. Celery 源码解析四: 定时任务的实现

    在系列中的第二篇我们已经看过了 Celery 中的执行引擎是如何执行任务的,并且在第三篇中也介绍了任务的对象,但是,目前我们看到的都是被动的任务执行,也就是说目前执行的任务都是第三方调用发送过来的.可 ...

  6. jQuery 源码解析(七) jQuery对象和DOM对象的互相转换

    jQuery对象是一个类数组对象,它保存的是对应的DOM的引用,我们可以直接用[]获取某个索引内的DOM节点,也可以用get方法获取某个索引内的DOM节点,还可以用toArray()方法把jQuery ...

  7. Celery 源码解析八:State 和 Result

    在前面几篇解析中,我们已经看过了 Worker 是如何运行的,Task 是如何创建的,以及怎么被路由到 Worker 中,除了这些之外,我们还对流量限制,Worker 控制和 Task/Worker ...

  8. ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现

    本篇博客我们就来聊一下combineLatest()的使用以及具体的实现方式.在之前的<iOS开发之ReactiveCocoa下的MVVM>的博客中我们已经聊过combineLatest( ...

  9. [源码解析] 并行分布式框架 Celery 之 worker 启动 (1)

    [源码解析] 并行分布式框架 Celery 之 worker 启动 (1) 目录 [源码解析] 并行分布式框架 Celery 之 worker 启动 (1) 0x00 摘要 0x01 Celery的架 ...

随机推荐

  1. [ZJOI2005]九数码游戏

    [ZJOI2005]九数码游戏 题目描述 输入输出格式 输入格式: 输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字.初始状态不会是目标状态. 输出格式: 如果目标 ...

  2. 微信小程序- 生成二维码

    wx.request({ // 获取token url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential', ...

  3. electron 写入注册表 实现开机自启动

    windows平台 首先先明确:开机自启动写入注册表的位置,在KEY_CURRENT_USER\Software\\Microsoft\\Windows\\CurrentVersion\\Run 打开 ...

  4. Visual Studio中让一个JS文件智能提示另一个JS文件中的成员

    当一个Web页面引用了两个JS文件(假如分别叫common.js和JScript1.js),如果JScript1.js中需要调用大量的common.js中的方法,这时候在JScript1.js中智能提 ...

  5. python学习笔记(一)之入门

    1.python的安装 官网下载.exe文件直接安装即可,在安装过程中选择加入环境变量,就不用在安装后再去增添环境变量了. 本文选择的是python3.6版本,没有选择2.7版本. 2.启动pytho ...

  6. Java基础总结--Java编程环境变量配置

    1.jdk--bin--都是命令行程序(图形化是对命令行的封装)eg javac&java执行javac必须切换到其所在目录--太麻烦---想在任意目录下使用要执行一个命令--先在当前目录下找 ...

  7. MongoDB用户权限管理

    创建用户账号: (roles参数指定了用户的角色以及这个账号授权的数据库,在同一个数据库中不能同时创建两个用户名相同的账号) Mongodb内置的用户角色: 数据库用户角色:read.readWrit ...

  8. vue数据请求

    我是vue菜鸟,第一次用vue做项目,写一些自己的理解,可能有些不正确,欢迎纠正. vue开发环境要配置本地代理服务.把config文件加下的index.js里的dev添加一些内容, dev: { e ...

  9. 汇总一些知名的 JavaScript 开发开源项目

    汇总一些知名的 JavaScript 开发开源项目   转自:CTOLib , www.ctolib.com/topics-107352.html ggraph - 图形可视化的凌乱数据 这是一个建立 ...

  10. 想成为一个高效的Web开发者吗?来看看大牛分享的经验吧~ #精选JAVASCRIPT前端开发

    想成为一个高效的Web开发者吗?来看看大牛分享的经验吧~ 作为一个软(ku)件(bi)工(de)程(ma)师(nong),你有没有觉得做什么事都没时间?没时间学习新东西,没时间去回顾.整理原来写的烂代 ...