正文
去中心化架构是指所有的作业节点都是对等的。每个作业从注册中心拉取自己的执行时间并且各自定时执行,执行时均使用作业服务器的本地时钟,在作业无需分片调整时并不会对注册中心产生写操作,进而不会导致注册中心更新缓存,因此执行效率很高,对注册中心产生的压力非常小。每个作业执行实例在执行时拉取仅属于自己实例的作业分片(通过本地缓存即可,并不直接读取注册中心),并传递给业务代码,供其根据所得分片项编写业务逻辑。去中心化架构需要一个被选举出来的主节点处理分片行为,仅分片行为不是去中心化的,需要集中处理。主节点是通过选举获得的非永久节点,一旦主节点的服务器宕机,则需要重新选举主节点。当作业服务器的在线状态发生变化时,则触发ZooKeeper监听,并设置需要重新分片的标记。在下次作业运行时,主节点将根据这个标记确定是否重分片并在需要时分片,分片时其他从节点一律处于阻塞状态。主节点的唯一特别之处就是负责作业运行之前的分片,其他方面的运行节点别无二致,主节点也是一个作业运行节点。
去中心化架构的优点是轻量级,仅提供一个lib就可以与业务代码一同工作,部署成本低,只需搭建注册中心即可。缺点是如果各作业服务器时钟不一致会产生同一作业的不同分片运行有先有后,缺乏统一调度。并且不能跨语言。
中心化架构将系统分为调度节点和执行节点。由调度节点发起作业的分片和执行,然后通过RPC发布给作业执行节点,或者通过写注册中心让监听注册中心的作业执行节点主动触发。同样可以采用注册中心来协调作业调度节点和执行节点的状态,也可以将注册中心退化为配置中心,专门用于存储作业配置元数据,转而由调度中心负责监听各个执行节点的状态。
中心化架构模式可以解决服务器时间差以及跨语言的问题(如果采用跨语言RPC或REST发送执行信令的方式)。缺点是部署和运维稍复杂,需要单独部署调度节点并需要维护其高可用,这也会造成一定的资源浪费。
无论是中心化还是去中心化,在分布式的场景下由于网络重试造成的顺序不一致等原因,可能导致ZooKeeper的数据与真实运行的作业产生不一致,这种不一致通过正向的校验无法完全避免。需要另外启动一个线程定时校验注册中心数据与真实作业状态的一致性,即通过检测的方式维持最终一致性。
Elastic-Job最初的版本分离于当当内部的应用框架ddframe,是一个纯Java实现的分布式方案,参照dubbo的方式,提供无中心化解决方案。它采用all in jar的理念,使用时无需区分主从或调度、执行节点,一切都采用自我协调。Elastic-Job采用ZooKeeper作为注册中心,用于处理作业的高可用、分片、失效转移等分布式协调功能。每个使用Elastic-Job的应用都需要与ZooKeeper建立连接,这样会造成ZooKeeper的连接过多,容易成为分布式ZooKeeper的瓶颈。它的分片逻辑根据IP地址抓取所在服务器的分片,IP地址不冲突是前提条件。Elastic-Job的架构图如下:
此时,每个团队自己搭建和管理各自的注册中心和服务器,因此使用Elastic-Job的项目都散落在各处。
随着私有云的技术栈越来越普及,公司决定将业务平台逐渐迁入私有云。作为入云的第一步,选择合理、风险易控的方向则很重要。经过多方面权衡,我们选择了基于Mesos + 自研Framework的作业云方案。而之前公司大量的使用Elastic-Job的项目都需要迁移,因此我们希望完全兼容Elastic-Job的原有API,所以Chronos等作业调度框架并不能满足我们的需求。我们要做的是将Elastic-Job结合到云平台,并增加结合硬件资源的掌控,以及部署发布自动化等功能。Elastic-Job本身包含Quartz,可以直接进行Job定时调度。因此,我们的最初想法是将Elastic-Job作为常驻服务启动,用Kubernetes或Mesos + Marathon运行。