@(分布式计算集群)
Master-Worker设计模式在生活中非常地常见,比如:督工和工人,督工给每个工人分配任务,也监督每个工人的工作情况。一般还有以下场景:如果有个工人身体不好,就重新将他的任务分配给其他人;现实中一般督工就一个,督工自己也有可能身体不好,然后呢?就没有然后了——也有可能由一个工人暂时顶替,或者再从其他小组挪一个督工,或者由一直陪同的小秘顶上。额外补充的场景是为了能够应对不正常事件,保证任务能够准时完成。同样的,程序设计中,也有这样的场景存在,尤其是任务量很大的时候。那我们是怎样完成这样的场景抽象,又是如何保证异常问题下的正常任务执行的呢?Hadoop中的Master-Worker设计模式又是怎么指导MapReduce工作流程的?
##Master-Worker设计模式介绍
Master-Worker模式是常用的并行设计模式。核心思想是,系统由两个角色组成,Master和Worker,Master负责接收和分配任务,Worker负责处理子任务。任务处理过程中,Master还负责监督任务进展和Worker的健康状态;Master将接收Client提交的任务,并将任务的进展汇总反馈给Client。各角色关系如下图
Master-Worker模式满足于可以将大任务划分为小任务的场景,是一种分而治之的设计理念。通过多线程或者多进程多机器的模式,可以将小任务处理分发给更多的CPU处理,降低单个CPU的计算量,通过并发/并行提高任务的完成速度,提高系统的性能。
具体细节如上图,Master对任务进行切分,并放入任务队列;然后,触发Worker处理任务。实际操作中,任务的分配有多种形式,如Master主动拉起Workder进程池或线程池,并将任务分配给Worker;或者由Worker主动领取任务,这样的Worker一般是常驻进程;还有一种解耦的方式,即Master指做任务的接收、切分和结果统计,指定Worker的数量和性能指标,但不参与Worker的实际管理,而是交由第三方调度监控和调度Worker。
##用例说明
###1. 简单demo(来自网友编写,做了些细节调整)
####Master类定义
package com.linesum.linjx.test.masterWorker;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
/**
* Master定义
* @author linjx
* @Date 2016年9月22日
*/
public class Master {
/**
* 任务列表(这边作为Master成员变量,可以拆分)
*/
private Queue<Object> jobQueue = new ConcurrentLinkedQueue<Object>();
/**
* Worker组
*/
private Map<String, Thread> workers = new HashMap<>();
/**
* 结果集(这边作为Master成员变量,可以拆分)
*/
private Queue<Object> results = new ConcurrentLinkedQueue<Object>();
/**
* 原始任务数
*/
private AtomicLong oriJobNum = new AtomicLong(0);
/**
* @param workerNum,worker数量上限
* @param workerClass, worker实现类
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Master(int workerNum, Class<? extends Worker> workerClass)
throws InstantiationException, IllegalAccessException {
for (int i = 0; i < workerNum; i ++) {
Worker worker = workerClass.newInstance();
worker.setJobQueue(jobQueue);
worker.setResults(results);
worker.setId(i);
workers.put(Integer.toString(i),
new Thread(worker, Integer.toString(i)));
}
}
/**
* 任务是否已经完成
* @return
*/
public boolean isComplete() {
for (Map.Entry<String, Thread> worker : workers.entrySet()) {
if (Thread.State.TERMINATED != worker.getValue().getState()) {
return false;
}
}
return true;
}
/**
* 由Client提交一个子任务
* @param job
*/
public void submit(Object job) {
oriJobNum.incrementAndGet(); //允许动态增加任务
jobQueue.add(job);
}
/**
* 返回子任务结果集
* @return
*/
public Queue<Object> getResults() {
return results;
}
/**
* 将运行结果放到结果集
* @param result
*/
public void putResult(Object result) {
results.add(result);
}
/**
* 启动worker,进行任务处理
*/
public void execute() {
for(Map.Entry<String, Thread> entry : workers.entrySet()) {
entry.getValue().start();
}
}
/**
* 获取完成任务占比
* @return
*/
public float getFinishRatio() {
return 100.0f-100.0f * ((float)jobQueue.size()) / oriJobNum.get();
}
}
####Worker类定义
package com.linesum.linjx.test.masterWorker;
import java.util.Queue;
/**
* Worker
* @author linjx
* @Date 2016年9月22日
*/
public abstract class Worker implements Runnable {
/**
* id
*/
private int id;
/**
* 任务队列
*/
protected Queue<Object> jobs;
/**
* 子任务结果集
*/
protected Queue<Object> results;
public abstract Object handle(Object input);
@Override
public void run() {
System.out.println(String.format("Worker:[%d] start working...", this.id));