前面对于 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. 作为前端Web开发者,这12个终端命令不可不会

    对于开发人员来说,终端是最重要的工具之一.掌握终端,能够有效的提升开发人员的工作流程.使用终端,许多日常任务都被简化为了编写简单的命令并按下 Enter 按钮. 本文列举了一系列 Linux 命令,旨 ...

  2. (@WhiteTaken)设计模式学习——观察者模式

    忙里抽闲,继续学习设计模式,作为自己的读书笔记,这次介绍Java下实现的观察者模式. 观察模式需要了解的三个概念: 被观察者:被观察的对象,发生变化会通知观察者集合(存放观察者的容器) 观察者:有up ...

  3. 窗口迅速关闭的解决办法/scanf/if/for/break

    break if的格式 if(a>b) { printf("max=%d\n",a); } else printf("max=%d\n",b); scan ...

  4. Ubuntu下使用网易云音乐

    Ubuntu15真心各种崩溃啊 最后决定还是换成ubuntu14.04LTS了 在win.android平台上网易云音乐好用到爆 ubuntu下没有网易云音乐的客户端怎么能行 https://gith ...

  5. 使用 Prometheus + Grafana 对 Kubernetes 进行性能监控的实践

    1 什么是 Kubernetes? Kubernetes 是 Google 开源的容器集群管理系统,其管理操作包括部署,调度和节点集群间扩展等. 如下图所示为目前 Kubernetes 的架构图,由 ...

  6. linux脚本定时备份数据库表(详解)

    数据库备份策略 备份的数据库 服务器:10.10.10.254.10.2.11.10 数据库:gps6 备份的表: user_info alarminfo electronic_fence jpush ...

  7. 关于keyTyped

    蠢了,重写keyTyped方法时候拿keyCode去做比较....记一下....VK_UNDEFiEND.......

  8. JavaScript面向对象深入理解原型

    原型模式 function Person(){ } Person.prototype.name="Ewarm"; Person.prototype.age="29&quo ...

  9. Ajax.Nodejs.跨域访问

    使用环境: 客户端: jQuery 服务器: Node.js 在通过Ajax调用非本域的链接/接口时, 一般是不能成功的, 就算是同一个IP下不同的端口也被认作跨域访问 解决办法记录如下: 客户端: ...

  10. mybatis generator eclipse插件的安装

    mybatis generator 可以提高开发速度,这个插件可以自动生成代码,创建DAO层相关代码,就像利用HIbernate反相生成一样,安装前可以先到百度网盘下载: 文件:MyBatisGene ...