使用Redis实现定时任务多节点部署及自动任务分发

最近部署一个定时任务项目遇到一个问题:部署的代码每天会定时启动多个任务在后台串行执行,且每个任务耗时比较长。我们的生产环境会自动开启三个相同的节点把部署的代码同步运行,这就导致三个节点的定时任务会重复执行,我只好强行关闭另外两个节点,以单节点的方式串行执行定时任务。

这样代码是能跑起来,但是效率低且浪费了另外两个服务器。我需要改造代码以便能支持多节点运行,且能让每个节点分发到不同的任务去执行。

思考过后,我借助redis实现了一个简单的分布式定时任务,在这里记录一下。

思路

要实现分布式,必须要使用到每个节点都能访问到的公共变量作为全局锁,这里我使用了redis来实现锁。
对每个不同类的任务设置唯一的字符串键,当定时任务开始时,每个节点将会去遍历任务抢占锁,只有获取到锁的节点可以执行锁对应的任务,而未获取到锁的节点将继续遍历其他任务锁,直到所有任务锁被获取并执行。

示例代码:task_manager.py

from redis import Redis
from apscheduler.schedulers.blocking import BlockingScheduler
import time
import random


r = Redis(host='localhost', port=6379, db=0, decode_responses=True)

TASK_LIST = ["任务参数1", "任务参数2", "任务参数3", "任务参数4"]

# 存放当前已完成的集合键
FINISHED_TASK_KEY = "task:finished"
# 给每个任务顺序分配不同的redis键
TASK_KEYS = ["task: {}".format(task) for task in range(len(TASK_LIST))]
# redis键对应的任务参数
TASK_MAP = {key: task for key, task in zip(TASK_KEYS, TASK_LIST)}
EXPIRE = 60 * 60 * 23

# 模拟定时执行的任务,可接受不同的参数
def task(param):
    print("----------------------------------")
    print("开始执行任务:{}....".format(param))
    time.sleep(random.randint(15, 30))
    print("完成{}".format(param))
    print("----------------------------------")


def start():
    # 每日任务开始前先删除redis中已完成任务集合
    r.delete(FINISHED_TASK_KEY)
    # 添加redis中唯一任务锁,若添加成功且任务完成表中无当前任务则执行
    for key in TASK_KEYS:
        status = r.set(key, 1, ex=EXPIRE, nx=True)
        # 检查当前任务是否已执行
        is_finished = r.sismember(FINISHED_TASK_KEY, key)
        if status is True and is_finished is False:
            print("当前节点获取任务:{} 成功, 准备执行。。".format(key))
            # 获取当前redis键对应的任务参数并执行任务
            task_param = TASK_MAP.get(key)
            task(task_param)
            # 任务执行完成将当前任务添加到已完成集合,不允许其他节点再获取该任务
            r.sadd(FINISHED_TASK_KEY, key)
            r.delete(key)
        elif status is True and is_finished is True:
            print("未执行: {},其他节点已完成该任务".format(key))
        else:
            print("未执行:{},其他节点正在执行当前任务".format(key))


if __name__ == '__main__':
    # 这里可使用apscheduler定时任务框架调度start函数,该处模拟未使用定时任务
    start()



模拟多节点运行

先同时打开三个命令行窗口,并键入执行命名,然后尽量相近时间点击回车运行,模拟多节点下定时任务同时触发的场景:


模拟多节点

执行情况如下:


模拟多节点同步运行结果

根据打印的执行情况看,整体符合预期,一个任务只能被一个节点执行,且能做到自动任务分发,执行完当前任务的节点会自动去获取还未执行的任务,直到所有任务执行完毕。

最后

当然,以上只是一个demo,还需要处理很多异常判断任务,任务完成情况之类的,针对不同的任务情景还可以有其他变通方法。这里只是整理一下思路和分享,希望对你也有所启发。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,069评论 4 358
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,212评论 1 287
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,912评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,424评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,741评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,194评论 1 206
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,553评论 2 307
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,289评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,923评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,251评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,775评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,144评论 2 249
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,698评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,936评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,658评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,214评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,159评论 2 258

推荐阅读更多精彩内容