分布式任务调度的几种实现(Redis实现分布式锁 MySQL实现任务调度 负载均衡)

需求背景

现在有一个计算搜索词热榜的任务,该服务部署在了多个节上,希望只有一个节点在执行这个任务。

常见方案

使用Redis实现分布式锁方案

使用一个分布式锁,确保整个分布式环境下,只有一个节点能够拿到锁。节点先抢占分布式锁,如果抢到了分布式锁的话,就执行计算搜索词热榜的任务,否则的话,就跳过该任务。

使用Redis实现的话,可以使用SexNX命令,SETNX task1_key pod1表示节点pod1正在尝试抢任务task1的分布式锁。设置的时候需要设置过期时间。如果上锁成功的话,说明该节点可以执行任务task1

解锁的话,采用lua脚本完成。这个脚本检查一个键的值是否等于给定的参数值,如果相等,则删除该键;否则,返回0。传入的KEYS[1] = "task1_key",ARGV[1]="pod1"

lua 复制代码
if redis.call('get', KEYS[1]) == ARGV[1] then  
    return redis.call('del', KEYS[1])  
else  
    return 0  
end

使用MySQL实现任务调度

在MySQL的数据库里创建一张表,里面是所有等待运行的定时任务。所有的节点都试着从表里抢占任务,如果成功的话就执行该任务。

这里的抢占,可以使用乐观锁来更新状态实现。先找到符合条件的任务,假设任务执行状态为等待开始,对应的数据库表字段为status=waiting_start,假设此时的version=1。然后尝试更新状态为update status = running。那么对于更新成功的节点来说,就相当于抢占到了该任务。如何保证更新的时候,没有其他节点抢占呢?更新的时候同时判断status=waiting_start,version=1,就能保证单节点抢占。

这里会存在的一个问题就是,如果已经抢占到任务但是任务还没执行完,该节点就异常退出了,但是其他节点都会认为该节点依旧在执行任务,就会陷入死锁的局面。想了一下解决方案就是,引入续约机制,对于MySQL实现而言,就是该节点需要不断地更新数据库的update_time字段,也就是更新时间,证明自己的状态正常;对于Redis实现而言,相当于延长锁的过期时间。

开源框架 XXL-JOB

XXL-JOB 是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习门槛低、功能强大并且轻量级。它支持自定义任务调度策略,支持多种执行模式,并且支持动态分片。

XXL-JOB主要由调度中心和执行器两部分组成。调度中心负责管理调度信息,按照调度配置发出调度请求,但自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块。执行器则负责接收调度请求并执行任务逻辑。

退一步而言,如果引入XXL-JOB的成本过高,可以考虑起一个单独的服务执行定时任务,运行在单pod上,这样的好处是开发快捷方便,缺点可能在于修改任务需要服务发版。

负载均衡

前两种方案在设计的时候,都是看哪个节点先抢占到任务,没有结合节点的情况考虑,如果一个本身就负载高的节点抢占到了任务,那么可能会影响到其他的业务逻辑,甚至引发节点OOM或崩溃。这种情况下,应该在调度的时候就引入一些负载均衡策略,

  • 检查节点的负载情况,超出健康阈值后就不抢占任务,比如内存使用率>=80%或CPU使用率>=80%,就不抢占该定时任务,同时设置一个定时任务未执行的报警,方便监控。
  • 每次选取负载最低的节点来进行,可以是内存最低也可以是CPU利用率最低,这就要求有一个控制中枢检测各个节点的负载情况,感觉需要借助中间件实现
  • 如果某个节点正在运行该任务,但是运行中的负载较高,就要及时中断并更换节点,做容错处理
  • 如果定时任务运行需要的资源较多,可以考虑使用XXL-JOB这种分布式任务调度框架
相关推荐
踏着七彩祥云的小丑40 分钟前
忘记Redis是否安装过时查看
数据库·redis·缓存
xqqxqxxq3 小时前
DML 表数据:插入、删除、修改
笔记·mysql
☆凡尘清心☆3 小时前
CentOS Stream 9 Redis 7.2.7 源码编译一键安装脚本
linux·运维·redis·centos
xxwl5854 小时前
数据库后端接口测试报告
spring boot·mysql·tomcat
xqqxqxxq5 小时前
MySQL 数据类型笔记
数据库·笔记·mysql
Logintern095 小时前
理解MySQL数据库的“事务与锁”
数据库·mysql
nvd115 小时前
GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘
运维·php·负载均衡
朱容zr3331336 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化
麻瓜code6 小时前
【Redis 】数据类型、持久化与过期删除
数据库·redis·缓存
笨蛋不要掉眼泪6 小时前
RabbitMQ消息队列:发送者的可靠性
java·分布式·rabbitmq