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

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

摘要

本文主要通过分布式计划任务软件设计讲述分布式软件开发。

我的系列文档

Netkiller Architect 手札

Netkiller Developer 手札

Netkiller PHP 手札

Netkiller Python 手札

Netkiller Testing 手札

Netkiller Cryptography 手札

Netkiller Linux 手札

Netkiller Debian 手札

Netkiller CentOS 手札

Netkiller FreeBSD 手札

Netkiller Shell 手札

Netkiller Security 手札

Netkiller Web 手札

Netkiller Monitoring 手札

Netkiller Storage 手札

Netkiller Mail 手札

Netkiller Docbook 手札

Netkiller Project 手札

Netkiller Database 手札

Netkiller PostgreSQL 手札

Netkiller MySQL 手札

Netkiller NoSQL 手札

Netkiller LDAP 手札

Netkiller Network 手札

Netkiller Cisco IOS 手札

Netkiller H3C 手札

Netkiller Multimedia 手札

Netkiller Perl 手札

Netkiller Amateur Radio 手札

Netkiller DevOps 手札

您可以使用iBook阅读当前文档


目录

  • 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)

原文发表时间:2015-09-29

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏求索之路

从零开始仿写一个抖音App——日志和埋点以及后端初步架构本项目的 github 地址:MyTikTok

拿 Java 来说:比如我们有两个服务 A、B 在两个服务器上,此时我们要在 A 上调用 B 的服务获取其上的数据 Foo。那么在 A 中可以写成 Foo f ...

56850
来自专栏Linyb极客之路

API设计:先思考再编码

14130
来自专栏Java技术分享

java系统高并发的解决方案

一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构、性能的要求...

81680
来自专栏芋道源码1024

小谈 Java 单元测试

总之有无数种理由不想写UT,作为工作不到三年的菜鸟深有体会。之前在点评工作的时候,团队的“UT”都集中于RPC的服务端。为啥带双引号? 因为RPC的服务端没有页...

16830
来自专栏玉树芝兰

如何用 pipenv 克隆 Python 教程代码运行环境?(含视频讲解)

咱们的 Python 教程代码已经可以免安装在线运行了。但如果你希望在本地克隆运行环境,请参考本文的步骤说明。

13230
来自专栏IT米粉

Redis常见的应用场景解析

缓存是Redis最常见的应用场景,之所有这么使用,主要是因为Redis读写性能优异。而且逐渐有取代memcached,成为首选服务端缓存的组件。而且,Redis...

84080
来自专栏Golang语言社区

Golang适合高并发场景的原因分析

典型的两个现实案例: 我们先看两个用Go做消息推送的案例实际处理能力。 360消息推送的数据: 16台机器,标配:24个硬件线程,64GB内存 Linux K...

59670
来自专栏PhpZendo

事件驱动架构设计

这篇文章是 软件架构演进 一个有关 软件架构 系列文章中的一篇。这些文章,主要是我学习软件架构、对软件架构的思考及使用方法的记录。相比于这个系列的前几篇文章,本...

82920
来自专栏携程技术中心

干货 | Android工程模块化平台的设计

19830
来自专栏FreeBuf

子域名枚举的艺术

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

46890

扫码关注云+社区

领取腾讯云代金券