Celery 源码解析七:Worker 之间的交互

前面对于 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 有在这方面做一些努力。

时间: 2024-11-05 12:36:19

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

volley源码解析(七)--最终目的之Response<T>

在上篇文章中,我们最终通过网络,获取到了HttpResponse对象 HttpResponse是android包里面的一个类,然后为了更高的扩展性,我们在BasicNetwork类里面看到,Volley将其包装成一个Volley自己的对象NetworkResponse 另外,在BasicNetwork类中我们也注意到,对HttpResponse包装成NetworkResponse的过程中,使用HttpResponse的Inputstream,将数据保存在一个byte[]数组中. BasicNet

Celery 源码解析六:Events 的实现

在 Celery 中,除了远程控制之外,还有一个元素可以让我们对分布式中的任务的状态有所掌控,而且从实际意义上来说,这个元素对 Celery 更为重要,这就是在本文中将要说到的 Event. 在 Celery 中,注册了很多的 Event,这些 Event 将会在 Task/Worker 的状态发生变化的时候被发出,然后被绑定的 Event 消费者(Receiver)所接受,绑定的 Event 消费者可以是一连串的回调函数,相信细心的同学在前面的源码解析过程中也有发现一些关于 event 的蛛丝

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

jQuery对象是一个类数组对象,它保存的是对应的DOM的引用,我们可以直接用[]获取某个索引内的DOM节点,也可以用get方法获取某个索引内的DOM节点,还可以用toArray()方法把jQuery对象一次性转换成一个数组,例如: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title

Tomcat Session管理机制(Tomcat源码解析七)

前面几篇我们分析了Tomcat的启动,关闭,请求处理的流程,tomcat的classloader机制,本篇将接着分析Tomcat的session管理方面的内容. 在开始之前,我们先来看一下总体上的结构,熟悉了总体结构以后,我们在一步步的去分析源代码.Tomcat session相光的类图如下: 通过上图,我们可以看出每一个StandardContext会关联一个Manager,默认情况下Manager的实现类是StandardManager,而StandardManager内部会聚合多个Sess

Spring Security 解析(七) —— Spring Security Oauth2 源码解析

Spring Security 解析(七) -- Spring Security Oauth2 源码解析 ??在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security .Spring Security Oauth2 等权限.认证相关的内容.原理及设计学习并整理一遍.本系列文章就是在学习的过程中加强印象和理解所撰写的,如有侵权请告知. 项目环境: JDK1.8 Spring boot 2.x Spring Security

Android网络编程(七)源码解析OkHttp前篇[请求网络]

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 前言 学会了OkHttp3的用法后,我们当然有必要来了解下OkHttp3的源码,当然现在网上的文章很多,我仍旧希望我这一系列文章篇是最简洁易懂

Android View体系(七)从源码解析View的measure流程

相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Scroller Android View体系(五)从源码解析View的事件分发机制 Android View体系(六)从源码解析Activity的构成 前言 在上一篇我们了解了Activity的构成后,开始了解一下View的工作流程,就是measure.layout和draw.measure

第二章 Google guava cache源码解析1--构建缓存器

1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHashMap(或者说成就是一个ConcurrentHashMap,只是在其上多添加了一些功能) 2.使用实例 具体在实际中使用的例子,去查看<第七章 企业项目开发--本地缓存guava cache>,下面只列出测试实例: import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit;

RxJava2 源码解析(二)

转载请标明出处: http://blog.csdn.net/zxt0601/article/details/61637439 本文出自:[张旭童的博客](http://blog.csdn.net/zxt0601) 概述 承接上一篇RxJava2 源码解析(一), 本系列我们的目的: 知道源头(Observable)是如何将数据发送出去的. 知道终点(Observer)是如何接收到数据的. 何时将源头和终点关联起来的 知道线程调度是怎么实现的 知道操作符是怎么实现的 本篇计划讲解一下4,5. Rx