Home | 简体中文 | 繁体中文 | 杂文 | 知乎专栏 | Github | OSChina 博客 | 云社区 | 云栖社区 | Facebook | Linkedin | 视频教程 | 打赏(Donations) | About
知乎专栏多维度架构 微信号 netkiller-ebook | QQ群:128659835 请注明“读者”

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

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

图 8.1. 分时方案

分时方案

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

图 8.2. HA 高可用方案

HA 高可用方案

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

图 8.3. 多路心跳方案

多路心跳方案

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

图 8.4. 任务抢占方案

任务抢占方案

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

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

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

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

  1. 每个服务器首次启动时加入队列。

  2. 每次任务运行首先判断自己是否是当前可运行任务,如果是便运行。

  3. 否则检查自己是否在队列中,如果在,便推出,如果不在队列中,便加入队列。

8.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 宕机怎么办,是否会一直处于被锁状态?我的答案是每个锁都有一个超时阀值,一旦超时便自动解锁。

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

8.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 节点。

8.6.3. 其他

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