ecodeclub / ecron

大规模分布式任务调度系统(学习版)
Apache License 2.0
63 stars 21 forks source link

基于MySQL 的抢占式存储引擎实现 任务3:负载均衡解决方案 #12

Closed flycash closed 1 year ago

flycash commented 1 year ago

场景

我们在 #10 和 #11 里面都提到了,抢占式的 MySQL 设计最大的问题就是负载均衡不太好搞。

设计

最基本的思想是,在抢占任务的逻辑里面加上一条规则:如果一个节点的负载比另外一个节点的负载更加低,那么我们就可以允许该节点抢占掉另外一个节点的任务。那么我们可以预期经过几轮续约、抢占,最终在所有的节点上的负载比较均匀的。 那么我们要考虑的问题就是:

方案一

一种比较简单的做法是采用近似于协商的机制,假如说现在 A 节点已经抢占了任务1,B 节点上的负载更加轻,试图从 A 节点上抢占任务1,那么基本的思路就是:

这样下来,B 就成功凭借着负载比较低的优势,抢占了任务1,获得了调度任务1 的权力。

image

场景分析

在这种方案之下,还是有很多场景需要审慎思考,确保没有遗漏掉任何的东西。

B 节点标记之后 A 节点宕机了

B 节点在数据库中写入自己的信息,即表达了自己想要抢占的意向,这个时候 A 节点就宕机了。此时 A 无法主动发现有人想抢占任务 1 并且释放掉 任务1。

image

所以我们需要引入一个兜底的机制:如果一个任务很久没被抢占(或者说很久没有续约),那么剩下的节点就可以抢占它。

基于这条原则,节点 C( B 也可以) 就会抢占掉它。

A 释放了任务 1 之后 B 节点宕机了

这种情况下, B 节点已经不可能继续抢占了,那么就需要考虑有别的节点之后会抢走任务 1.

image

节点 C(A 也可以) 轮询到了任务 1,发现虽然 B 节点想要抢占,但是一直没有抢占,于是节点 C 就会抢占掉它。

总结

我们只需要引入一个候选者-主动放弃机制,就可以保证任务朝着负载轻的节点转移。在这种形态下,演变成:

那么核心就变成了要仔细设计任务的状态迁移,确保某些时刻,只有候选者可以抢占某个任务,而在其他时候任何节点都可以抢占任务。

hookokoko commented 1 year ago

不太好测试。

hookokoko commented 1 year ago

在写测试的时候发现一个问题,

A 节点在抢占任务1的时候,往数据库写入(占有者负载=11) B 节点在定时扫描数据库,希望能够抢占一些任务的时候,发现 A 节点抢占任务1 留下的信息,它比较了一下自己的负载(9),于是在任务1 的信息里面增加(占有者负载=11,候选者负载 = 9) 等 A 节点下一次续约的时候,发现里面写了一个候选者负载 = 9,意思就是它知道有一个负载更低的节点想要抢占了,于是它就会放弃续约,并且主动释放掉这个任务,即把状态更新为可抢占状态 B 节点下一次轮询数据库的时候发现了 A 节点已经放弃了任务,那么就会直接抢占,并且将信息更新为(占有者负载=(9+1),候选者负载=NULL)

也就是在这个方案里面,第一步如果A节点抢占任务1之后又抢占了任务2,那么抢占任务2的时候,需要连同任务1的占有者负载一起更新。如果任务数很多,这里会很影响性能。 如果考虑在A节点进行任务续约的时候更新,如果续约的时间间隔很久,那么其他节点在进行负载均衡的时候误差就会很大

hookokoko commented 1 year ago

是不是有一个中心化的地方管理所有节点的负载,相对更好一些

flycash commented 1 year ago

3.28 会议记录

https://www.bilibili.com/video/BV1Z24y177pR/

3.28 分布式任务调度 MySQL 实现 rebalance 设计.xlsx