内容简介:假设我们有一个集群,用于处理一系列不同的任务,这时候我们需要对任务进行的一定的分配,使得集群中的每台机器都负责一部分任务。一般来说会有如下几个要求:在这种场景下,该如何设计任务的分配方案?
假设我们有一个集群,用于处理一系列不同的任务,这时候我们需要对任务进行的一定的分配,使得集群中的每台机器都负责一部分任务。
一般来说会有如下几个要求:
- 一个任务最多只能被执行一次(换言之,只能被分配到一台机器上)
- 执行任务时集群中每台机器的负载能够保持平衡
在这种场景下,该如何设计任务的分配方案?
为了方便后续的展开,先约束一些表达:
Source Cluster Task Worker
四者之间的关系可以用下图表示:
思路1:简单取模分配
最简单,但也是非常有效的方案,在进行任务分配前需要提前 确定机器数量N ,为每个任务进行编号(或直接使用其id),同时为每个执行任务的机器实例进行编号(0,1,2...)。
即使用下面的公式:
Worker = TaskId % Cluster.size() 复制代码
如果任务没有id标识,那么可以通过随机数的方式来分配任务,在任务数量足够多的情况下,可以保证分配的均衡性(dts网格任务的默认规则就是这么实现的),即:
Worker = random.nextInt() % Cluster.size() 复制代码
简单取模分配的优点是足够简单,虽然负载均衡的效果比较粗糙,但可以很快达到想要的效果,在做紧急任务分机分流的时候比较有用。但从长期上看,需要维护机器数量N的实时更新和推送,并且在机器数量发生变动的时候,可能会出现集群内部的短暂不一致,如果业务对这个比较敏感,还需要进一步优化。
思路2:分布式锁控制系统
为了达到“每个任务只被一台机器执行”的目标,可以考虑使用分布式锁机制,当有多个Worker去消费Task时,只有第一个争抢到锁的Worker才能够执行该Task。
理论上讲,每次抢到锁的Worker都是随机的,那么也就近似的实现了负载均衡;在有成熟中间件依赖的前提下,实现一个分布式锁也并不难(可以借助缓存系统的并发控制实现),并且不用考虑机器数量变化的问题。
但这个方案也有着很多的缺陷,首先争抢锁的过程本身就会消耗Worker的资源,另外由于无法预测究竟哪个Worker能够争抢到Task的锁,所以基本不能保证整个集群的负载均衡。
我个人认为这种方案只适合于内容非常简单、数量比较多,同时执行频率非常高的任务分发(类比多线程读写缓存的场景)。
思路3:中心路由调度
如果要做到比较精细的负载均衡,那么最好的方式就是根据集群的状态、以及任务本身的特性去量身定制一套任务分配的规则,然后通过一个中心的路由层来实现任务的调度,即:
- Source将任务发送给Router
- Router根据规则进行决策,并将Task调度到某台Worker
- (如果任务需要返回结果)Router将对应Worker返回的结果转发给Source
一个简单可行的分配规则是在调度前,计算Worker的CPU、内存等负载,计算一个权重,选择压力最小的机器去运行任务;再进一步可以根据任务本身的复杂度做更精细的拆分。
该方案最大的问题在于,自主去实现一个路由层的成本比较高,另外有出现单点问题的风险(如果路由层挂了,整个任务调度就全部瘫痪了)。
思路4:基于消息队列
这个是类比之前看到的,基于消息队列的分布式数据库解决方案(原文),借助一个可靠的Broker,我们可以很容易构建出一个生产者-消费者模型。
Source产出的Task将全部投入消息队列中,下游的Worker接收Task,并执行(消费)。这样的好处是减少了阻塞,同时可以根据Worker的执行结果,配置重试策略(如果执行失败,再次放回到队列中)。但单单依赖Broker做任务分发的话,并不能解决我们开头的两个问题,因此还需要:
-
防止消息被重复消费的机制
因为绝大多数的消息队列Broker的传输逻辑都是“保证消息至少被送达一次”,所以很有可能出现某个Task被多个Worker获取到的现象,如果要确保“每个任务都只被执行一次”,那么这时候可能需要引入一下上面提到的锁机制来防止重复消费。
不过如果你选择NSQ作为Broker的话,就不用考虑这个问题。NSQ的特性保证了某个消息在同一个channel下,一定只能被一个消费者消费。
-
任务分发
构建了生产者-消费者模型后,依然不好回答“哪个Task要在哪个Worker上运行”,也就是任务分发的机制,本质上还是依赖于消费者消费动作的随机性,如果要做更精细的调控,大致想一下有两种方案。
一是在放入队列前就根据所需规则计算好映射关系,然后对Task做一下标记,最后Worker可以设置成只对含有特定标记的Task生效,或者根据Task的标记做不同Topic来分发。
而是在取出队列的时候再进行计算,这样的话可能下游又需要维护一个路由层来做转发,感觉有些得不偿失。
就大多数实际情况而言,依赖Broker本身的消息分发机制即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Java深入——Java 内存分配和回收机制
- Java深入——Java 内存分配和回收机制
- JVM内存分配机制与回收策略选择-JVM学习笔记(2)
- 区块链商业化离不开的第五基本元素:合成分配机制
- 操作系统学习笔记-11:内存分配(一):连续分配
- 操作系统学习笔记-12:内存分配(二):非连续分配
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Trading and Exchanges
Larry Harris / Oxford University Press, USA / 2002-10-24 / USD 95.00
This book is about trading, the people who trade securities and contracts, the marketplaces where they trade, and the rules that govern it. Readers will learn about investors, brokers, dealers, arbit......一起来看看 《Trading and Exchanges》 这本书的介绍吧!