分布式计划任务设计与实现

分布式计划任务设计与实现

目录

  • 1. 什么是分布式计划任务
  • 2. 为什么采用分布式计划任务
  • 3. 何时使用分布式计划任务
  • 4. 分布式计划任务的部署
  • 5. 谁来写分布式计划任务
  • 6. 怎么实现分布式计划任务
    • 6.1. 分布式互斥锁
    • 6.2. 队列
    • 6.3. 其他

1. 什么是分布式计划任务

首先我们解释一下计划任务,计划任务是指有计划的定时运行或者周期性运行的程序,我们最常见的就是Linux “crontab”与Windows “计划任务程序”,我们也常常借助他们实现我们的计划任务,因它们的时间调度程序非常成熟,无需我们再开发一套。

2. 为什么采用分布式计划任务

起初,我们也跟大多数人一样采用crontab调度程序,但随着项目越来越大,系统越来越复杂,就抱漏出许多问题。

首先是高可用HA需求,当运行计划任务的服务器一旦出现故障,所有的计划任务将停止工作。

其次是性能问题,越来越多的大型计划任务程序出现,对CPU/IO密集操作,单个节点已经不能满足我们的需求。

让计划任务7*24*365不间断运行,必需有一套行之有效的方案才行,我意识到必须开发一个全新的分布式计划任务框架,这样开发人员无需关注怎样实现分布式运行,集中写任务即可。

我首先提出这个框架必需具备几个特性:

分布式计划任务需具备以下特性

  1. 故障转移,我们至少使用两个节点,当一个节点出现问题,通过健康状态检查程序,另一个节点会自动接管任务。
  2. 分布式运行,一个任务可以运行在多个节点之上,能够同时运行,能够调整运行的前后顺序,能够并发互斥控制。
  3. 节点可动态调整,最少两个节点,可以随时新增节点,卸载节点。
  4. 状态共享,任务可能会涉及的通信,例如状态同步等等。

3. 何时使用分布式计划任务

何时使用分布式计划任务

  1. 遇到性能问题,遇到性能问题你可能首先想到的是分服务器,但很多应用不具备跨服务器运行。
  2. 高可用,一个节点出现故障,另一个节点将接管并继续运行。
  3. 灾备,你可以将两个或两个以上的计划任务节点分别部署在两个以上的机房,通过HA特性任何一个机房出现故障,其他机房仍会继续运行。

4. 分布式计划任务的部署

两个节点部署

两个节点可以实现“主”、“备”方案,队列(排队)运行方案与并行方案,其中并行方案又分为不同运行于异步运行,还涉及到互斥运行。

两个以上节点部署

多节点建议采用队列运行方案,并行方案,但不建议使用互斥并行方案(浪费资源)

5. 谁来写分布式计划任务

当我们的分布式计划任务框架一旦完成,任务的编写部分非常轻松,只需继承框架程序便具备分布式运行的特性。

6. 怎么实现分布式计划任务

计划任务是一个相当复杂的一块,有操作系统计划任务,有运用程序计划任务,有基于TCP/IP的访问的,有基于命令行访问的,有定时执行的,有周期运行的,还有基于某些条件触发运行的。总之解决计划任务灾备,要比web,cache, database 复杂的多。

图 1. 分时方案

严格划分时间片,交替运行计划任务,当主系统宕机后,备用系统仍然工作,只不过处理周期拉长了。缺点:周期延长了

图 2. HA 高可用方案

正常情况下主系统工作,备用系统守候,心跳检测发现主系统出现故障,备用传统启动。缺点:单一系统,不能负载均衡,只能垂直扩展(硬件升级),无法水平扩展

图 3. 多路心跳方案

上面的HA是三层的基于VIP技术实现,下面这个方案我采用多路心跳,做服务级,进程级,IP与端口级别的心跳检测,做正常情况下主系统工作,备用系统守候,心跳检测发现主系统出现故障,备用传统启动,当再次检测到主系统工作,将执行权交回主系统.缺点:开发复杂,程序健壮性要求高

图 4. 任务抢占方案

A,B 两台服务器同时工作,启动需要一前一后,谁先启动谁率先加锁,其他服务器只能等待,他们同时对互斥锁进行监控,一旦发现锁被释放,其他服务谁先抢到谁运行,运行前首先加排他锁。 优点:可以进一步优化实现多服务器横向扩展。 缺点:开发复杂,程序健壮性要求高,有时会出现不释放锁的问题。

图 5. 任务轮循或任务轮循+抢占排队方案

任务轮循或任务轮循+抢占排队方案

  1. 每个服务器首次启动时加入队列。
  2. 每次任务运行首先判断自己是否是当前可运行任务,如果是便运行。
  3. 否则检查自己是否在队列中,如果在,便推出,如果不在队列中,便加入队列。

6.1. 分布式互斥锁

互斥锁也叫排它锁,用于并发时管理多进程或多线程同一时刻只能有一个进程或者线程操作一个功能。如果你理解什么是互斥锁,便很容易理解分布式锁。

我们将进程,线程中的锁延伸到互联网上,实现对一个节点运行的进程或线程加锁,解锁操作。这样便能控制节点上进程或线程的并发。

			+------------------+                             +------------------+
| Server A         |                             | Server B         |
+------------------+      +---------------+      +------------------+
| Thread-1         |      | Cluster Mutex |      | Thread-1         |
| Thread-2         |----> +---------------+ <----| Thread-2         |
| Thread-3         |      | A Thread-2    |      | Thread-3         |
+------------------+      +---------------+      +------------------+
                                  |
                                  V
                          +---------------+
                          | Cluster Mutex | 
                          +---------------+
                          | A Thread-2    |
                          +---------------+			

上图中有两台服务器上运行任务,其中Server A 的 Thread-2 做了加锁操作,其他程序必须等待它释放锁才能运行。

你会问如果 Server A 宕机怎么办,是否会一直处于被锁状态?我的答案是每个锁都有一个超时阀值,一旦超时便自动解锁。

另外我们还要考虑“域”的问题,你也可以叫它命令空间,主要是防止锁出现同名被覆盖。

6.2. 队列

排队运行

			+------------------+                             +------------------+
| Server A         |                             | Server B         |
+------------------+      +---------------+      +------------------+
| Thread-1         |      | Task Queue A  |      | Thread-1         |
| Thread-2         |----> +---------------+ <----| Thread-2         |
| Thread-3         |      | A Thread-2    |      | Thread-3         |
+------------------+      | B Thread-1    |      +------------------+
                          | B Thread-3    |
                          | A Thread-3    |
                          +---------------+
                                  |
                                  | <sync>
                                  V
                          +---------------+
                          | Task Queue B  |
                          +---------------+
                          | A Thread-2    |
                          | B Thread-1    |
                          | B Thread-3    |
                          | A Thread-3    |
                          +---------------+			

从上图中我可以看到Task Queue中排队情况,运行是自上而下的。

注意Task Queue 需要两个节点,它们是主从结构,A 节点实时向 B 节点同步sh状态。如果 A 节点出现故障, B 节点立即取代 A 节点。

6.3. 其他

计划任务可以分布式运行了,但并不能保证万无一失,配套其他服务器也要做调整。例如数据库,缓存等等。

原文发布于微信公众号 - Netkiller(netkiller-ebook)

原文发表时间:2016-05-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT米粉

Redis常见的应用场景解析

Redis是一个key-value存储系统,现在在各种系统中的使用越来越多,大部分情况下是因为其高性能的特性,被当做缓存使用,这里介绍下Redis经常遇到的使用...

3516
来自专栏Java架构沉思录

Web系统权限控制如何设计

这篇文章的定位,不是宣传某个框架,仅仅之是梳理一下有关权限方面的一些想法和最近项目中的一些探索过程。 我们主要想解决一下问题。

1392
来自专栏jojo的技术小屋

原 微信授权和朋友圈分享

作者:汪娇娇 日期:2016.9.25 现在想想,微信这东西真是让人又爱又恨,刚接触的时候,简直毫无头绪,不过在后台的配合下,现在终于能八九不离十的将微信获取用...

5265
来自专栏FreeBuf

子域名枚举的艺术

写在前面的话 当我们在查找某个域名的有效子域名时,我们通常需要使用子域名枚举这项技术。但是,除非DNS服务器暴露了完整的DNS空间(涉及到AXFR协议),否则我...

2739
来自专栏北京马哥教育

Python老司机带你快速搞定日志分析工具

转载自:Python中文社区 ID:python-china 日志分析在web系统中故障排查、性能分析方面有着非常重要的作用。该工具的侧重点不是通常的P...

2915
来自专栏码代码的陈同学

Spring Cloud 网关异常处理实践

有余力可以自建异常处理平台,有一套异常处理流程,有个炫酷且实用的Dashboard。

68220
来自专栏Netkiller

分布式计划任务设计与实现

分布式计划任务设计与实现 摘要 本文主要通过分布式计划任务软件设计讲述分布式软件开发。 我的系列文档 Netkiller Architect 手札 Netk...

2985
来自专栏星流全栈

dva - React + Redux, but like elm

1254
来自专栏Java帮帮-微信公众号-技术文章全总结

Java并发学习5【面试+工作】

future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用。当我们需要调用一个函数方法时,如果这个函数执行很慢,那么我们就要进行等待。但有时候...

1002
来自专栏喵了个咪的博客空间

phalapi-进阶篇4(notrom进阶以及事务操作)

#phalapi-进阶篇4(notrom进阶以及事务操作)# ? ##前言## 先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的...

3206

扫码关注云+社区