分布式调度任务管理—Dkron

分布式调度任务管理—Dkron

背景需求

  1. 多个系统上有属于自己业务上的计划任务,并且有部分计划任务不能多台服务器同时执行,具有唯一性,cron服务高可用难以实现。
  2. 方便管理cron
  3. 计划任务执行失败需要告警通知。

简单说说dkron

GO + Serf + gossip protocol +raft 的技术架构,通过阅读作者原文,总结几个关键字:分布式、轻量级、可靠、易拓展。

优点

  • 定时:支持精确到秒,支持cron语法、@every、@at。

  • 任务特点:指定失败重试执行次数,任务可并发执行,父任务及子任务的链式执行机制。

  • 集群:去中心化、高可扩展性和leader自动选举,完善的api接口和UI

  • 警报通知:邮件通知和可接入prometheus

  • 节点:每个节点都包含所有的服务。

缺点:

  • 前端页面不够友好(可能是个人的使用习惯)
  • 高级的邮件支持只在pro版本可用,oss版本不能设置失败邮件推送和邮件payload

注意(与我的理解的有不一致需要注意):

  • 任务执行错误,只做重试,不转移其他节点。

  • 节点故障, 当前跑的任务进程关闭,只能等待下次计划时间开启

关于运行机制和任务修改过程可以看如下两篇文章:

  • 分布式定时任务系统分析

  • 添加任务/修改任务/删除任务的过程

    可以开启debug模拟进行日志校验。

    Jul 15 14:59:54 tserver121 dkron: time="2021-07-15T14:59:54+08:00" level=info msg="2021/07/15 14:59:54 [DEBUG] memberlist: Initiating push/pull sync with: 10.3.247.118 10.3.247.118:8946"
    Jul 15 14:59:59 tserver121 dkron: time="2021-07-15T14:59:59+08:00" level=debug msg="fsm: received command" command=0 node=10.3.247.121
    Jul 15 14:59:59 tserver121 dkron: time="2021-07-15T14:59:59+08:00" level=debug msg="store: Retrieved job from datastore" job=job1 node=10.3.247.121
    Jul 15 14:59:59 tserver121 dkron: time="2021-07-15T14:59:59+08:00" level=debug msg="store: Setting job" job=job1 node=10.3.247.121
    Jul 15 14:59:59 tserver121 dkron: time="2021-07-15T14:59:59+08:00" level=debug msg="fsm: received command" command=2 node=10.3.247.121
    Jul 15 14:59:59 tserver121 dkron: time="2021-07-15T14:59:59+08:00" level=debug msg="store: Setting key" execution="executions:job1:1626332399964085243-tserver120" finished="0001-01-01 00:00:00 +0000 UTC" job=job1 node=10.3.247.121
    Jul 15 14:59:59 tserver121 dkron: time="2021-07-15T14:59:59+08:00" level=debug msg="store: to detele key" execution=1626330569972455451-tserver120 job=job1 node=10.3.247.121
    Jul 15 15:00:00 tserver121 dkron: time="2021-07-15T15:00:00+08:00" level=debug msg="fsm: received command" command=4 node=10.3.247.121
    Jul 15 15:00:00 tserver121 dkron: time="2021-07-15T15:00:00+08:00" level=debug msg="fsm: Setting execution" execution=1626332399964085243-tserver120 node=10.3.247.121 output=
    Jul 15 15:00:00 tserver121 dkron: time="2021-07-15T15:00:00+08:00" level=debug msg="store: Retrieved job from datastore" job=job1 node=10.3.247.121
    Jul 15 15:00:00 tserver121 dkron: time="2021-07-15T15:00:00+08:00" level=debug msg="store: Setting job" job=job1 node=10.3.247.121
    Jul 15 15:00:24 tserver121 dkron: time="2021-07-15T15:00:24+08:00" level=info msg="2021/07/15 15:00:24 [DEBUG] memberlist: Initiating push/pull sync with: tserver120 10.3.247.120:8946"
    

使用Dkron

可以先去官方网站阅读一下指导文档

安装

方便安装是dkron的特点 downloads page可以下载rpm直接安装:

yum localinstall dkron_3.1.8_linux_x86_64.rpm
systemctl enable dkron
systemctl restart  dkron

这样已经安装完成,如果不想服务向外网通信可以拦截stats.dkron.io,因为启动dkron会向它注册验证。

端口
8946 #用于代理之间数据同步
8080 #用于API和仪表板的HTTP  -->我部署已改为8100
6868 #用于代理之间的执行通信。

用户访问是8080,其他的端口都是服务器间通信,设置防火墙需要注意。

客户端命令
dkron agent - 启动
dkron doc - 文档
dkron keygen - 生成密钥
dkron leave - 离开集群
dkron raft - 客户端控制命令
dkron version - 显示版本

dkron agent --server --bootstrap-expect=1  #单个服务器配置需要 -bootstrap-expect=1 标志
dkron raft list-peers 查看当前状态
dkron raft remove-peer --peer-id 10.3.247.120  删除节点需要在leader执行, 删除后如果节点正常 则又自动加入
dkron leave 当前节点离开集群 需要重启后加入
API接口

官方文档API ,包含了:

  • 节点管理
  • jobs管理
  • 执行日志(只能查到最近100条信息)

由于页面添加方式不太习惯,所以我常使用post localhost:8080/v1/jobs,添加和修改jobs

curl localhost:8080/v1/jobs -XPOST -d '{
  "name": "job1",
  "schedule": "@every 10s",
  "timezone": "Europe/Berlin",
  "owner": "Platform Team",
  "owner_email": "platform@example.com",
  "disabled": false,
  "tags": {
    "server": "true:1"
  },
  "metadata": {
    "user": "12345"
  },
  "concurrency": "allow",
  "executor": "shell",
  "executor_config": {
    "command": "date"
  }
}'
集群

接下来就是配置集群,我使用的是3+N server + N node模式,

node不提供web UI,不做leader,只做任务执行器,部署在各个业务服务器上,当然如果是单纯的跑任务,没有任务环境依赖,我建议全部配置server,

请参照配置

server 配置文件

# Dkron example configuration file

# This node is running in server mode
server: true                    #false 不能成为leader
bootstrap-expect: 3            #集群初始化数量
http-addr: 0.0.0.0:8100         # false 不能成为leaderhttp访问端口默认8080

node-name: 10.13.3.26         #唯一, 默认主机名
#advertise-addr: 0.0.0.0   		#代理之间通信
#bind-addr: 0.0.0.0        		#API和仪表板的HTTP通信

data-dir: '/export/dkron'       #数据目录
datacenter: ywkf                #本地代理的数据中心标识(默认为“ dc1”)
region: sre_ywkf4                #区域

log-level: info                 #日志级别,默认info
tags:
   project: manager				
   serverip: 10001				
   approle: leader

encrypt: XXXXXXXXXXXXXXXXXXXXXX==    #用于加密网络流量的密钥,需要一致 dkron keygen - 生成密钥
raft-multiplier: 5             
join:                           #加入的初始代理
  - 10.13.3.26
  - 10.13.3.25
  - 10.13.3.248
retry-join:                     #集群创建后加入
retry-max: 6                    #最大连接尝试次数。默认为0,它将无限期重试
serf-reconnect-timeout: 60s     #失败节点尝试重新连接 默认24h

#mail-from: platform@example.com   #oss版本不能设置失败邮件推送和邮件payload ,所以不配置
#mail-host: 10.13.3.25
#mail-password:
#mail-payload:
#mail-port: 25
#mail-subject-prefix: "[Dkron]"
#mail-username:

node 配置文件

# Dkron example configuration file

# This node is running in server mode
#server: true                    #false 不能成为leader
#bootstrap-expect: 3             #集群初始化数量 false 不能成为leader
#http-addr: 0.0.0.0:8100         # false 不能成为leaderhttp访问端口 m默认8080

node-name: 10.13.3.230         #唯一, 默认主机名
#默认路由不在同一网段添加如下: (不带端口!!!!!!!!!!)
#advertise-addr: 10.13.3.236   #代理之间通信
#bind-addr: 10.13.3.236      #API和仪表板的HTTP通信

data-dir: '/export/dkron'       #数据目录
datacenter: ywkf                #本地代理的数据中心标识(默认为“ dc1”)
region: sre_ywkf4                #区域

log-level: warn                 #日志级别,默认info
tags:
   project: app
   serverid: 10133230
   approle: node

encrypt: XXXXXXXXXXXXXXXXXXXXXX==     #用于加密网络流量的密钥,需要一致
raft-multiplier: 5             #lead选取时间
join:                           #加入的初始代理
  - 10.13.3.26
  - 10.13.3.25
  - 10.13.3.248
retry-join:                     #集群创建后加入
retry-max: 6                    #最大连接尝试次数。默认为0,它将无限期重试
serf-reconnect-timeout: 60s     #失败节点尝试重新连接 默认24h

问题1:为什么会区分node 和server?

​ 因为node不会启动web端口,减少了端口占用,node是部署在业务服务器上,变动性比较大,leader不稳定,不方便前端nginx做反向代理。

问题2:tags如何添加?

​ 我建议最少需要有 唯一标签serverid、项目标签project, 唯一标签作用是指定服务器执行,项目标签是多台角色相同的服务器上执行,

添加和修改job

oss 版本提供了4种执行器 Executors 和3种日志处理 Execution,可以处理多种需求

dkron系统提供了两种方式添加jobs:

命令行post方式(shell/postman)推荐使用postman

curl localhost:8080/v1/jobs -XPOST -d '{
  "name": "job1",
  "schedule": "@every 10s",
  "timezone": "Europe/Berlin",
  "owner": "Platform Team",
  "owner_email": "platform@example.com",
  "disabled": false,
  "tags": {
    "server": "true:1"
  },
  "metadata": {
    "user": "12345"
  },
  "concurrency": "allow",
  "executor": "shell",
  "executor_config": {
    "command": "date"
  }
}'

web UI方式 localhost:8080 --> jobs --> create -->save

配置简单介绍

Name freestyle-test         #job名
Displayname freestyle-test  #页面显示名称
Timezone Asia/Shanghai      #时区
Schedule  30 */5 * * * ?    #秒 分 时 天 月 周, 还有两种种格式 @every 10s 每隔10秒 和 “@at 2018-01-02T15:04:00Z” 将在指定的日期和时间(假设UTC时区)运行作业。
Owner admin                  #所属人
Owner email  platform@example.com    #所属人邮箱,邮件通知
Parent job  parent_job               #父任务,子任务在父任务之后执行
Last success    2021/4/7下午2:27:02   #最后成功时间
Last error  2021/4/7下午2:10:35       #最后失败时间
Status  success                       #当前状态
Next  2021/4/7下午2:50:30             #下一次执行时间
Concurrency forbid                    #allow(默认):允许并发作业执行。
                                      #forbid:如果作业已经在运行,则不发送执行,它将跳过执行,直到下一个计划。
Processors
{
"files":{                             #日志输出  有指定files,有输出到log日志, 输出到syslog
"forward":"true"                      #true将日志输出转发到下一个处理器
"log_dir":"/data/logs/dkron"          #指定文件
}
}
Tags                                  #标签,用于指定对应标签节点执行,在节点的配置文件可以创建标签
{
"object":"monitor:1"                  #"object":"monitor" 带monitor的都执行,这是多节点并发执行
}                                     #"object":"monitor:1" 带monitor的其中一台执行,采用随机的方式。
                                      #可以使用多个标签组合使用

Executor shell                        #支持shell、http、kafka、nats

Executor config
{                                     #以shell 为例
"command":"bash /data/dkron/dkron.sh" #执行命令
"timeout":"200s"                      #超时时间
"env": "ENV_VAR=va1",                 #环境变量
"cwd": "/app",                        #执行路径
}

Disabled                              #是否启动   (toggle 启动/停止 切换)
Retries  3                            #失败重试次数

简单的配置文件模版

{
    "name": "job1",                   
    "displayname": "job1",             
    "timezone": "Asia/Shanghai",
    "schedule": "20 59 23 * * ?",                     
    "owner": "master",                               
    "owner_email": "platform@example.com",           
    "parent_job": "",
    "ephemeral": false,
    "expires_at": null,
    "concurrency": "forbid",
    "processors": {
        "log": {
            "forward": "true"
        }
    },
    "tags": {
        "project": "manager"                           
    },
    "metadata": null,
    "executor": "shell",
    "executor_config": {
        "command": "bash /data/dkron/dkron.sh",          
        "cwd": "/",
        "env": "",
        "timeout": "60s"
    },
    "retries": 2,
    "disabled": false
}

问题3: 计划任务执行失败

level=error msg="grpc: Error calling gRPC method" error="rpc error: code = Unknown desc = agent: Run error retrieving job: job5 from scheduler" method=RunJob node=10.13.3.26 server_addr="10.13.3.25:6868"

​ 将disabled 改为 false 会自动执行

备份和恢复

官方给出的备份还原的方法。

curl localhost:8100/v1/jobs > backup.json
curl localhost:8100/v1/restore --form 'file=@backup.json'

在日常维护中,也可以使用/jobs/{job_name}将每个job 的配置使用json文件格式存储下来,jobs 的修改和单个jobs的恢复都可能需要它。

集群节点恢复

日志收集与报警

问题4:为什么要做日志收集?

  • 虽然dkron 的web上有保存任务执行输出记录,每个jobs最多保存100条记录,频率较高的任务容易被覆盖。
  • oss版本不能设置失败邮件推送和邮件payload ,所以不适合邮件告警方式
  • dkron监听脚本执行的stdout 和stderr,所以命令中的重定向是没有效果的。

job 需要使用log配置

"processors": {
    "log": {
        "forward": "true"    
    }
}
// /etc/rsyslog.conf 配置转发指定文件目录下
//  $template fileformat,"/export/logs/dkron/%programname%_%$year%-%$month%-%$day%.log"
// if $programname == "dkron" then ?fileformat

或者

{
	"files":{                             
		"forward":"true"                      
		"log_dir":"/data/logs/dkron"         
	}
}

将任务日志输出到指定位置,通过ElasticStack收集,再对日志级别,使用elastalert可以做出对应的规则报警。

logstatsh grok 规则 识别日志的level
match => [ "message" , "%{SYSLOGTIMESTAMP:timestamp} %{DATA:logsource} %{SYSLOGPROG}: %{GREEDYDATA} (?:level=%{LOGLEVEL:level}) ?(?:msg=%{GREEDYDATA:msg})"]
match => [ "message" , "%{SYSLOGTIMESTAMP:timestamp} %{DATA:logsource} %{SYSLOGPROG}: (?:%{GREEDYDATA:msg})"]

参考:

dkron

Serf

gossip protocol

Reliable Cron across the Planet

另一个实现方案xxl-job

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值