所谓的Aggregate模式,其实就是聚合模式,跟masterWorker模式有点类似,但其出发点不同。masterWorker模式是指master向worker发送命令,worker完成某种业务逻辑。而聚合模式则刚好相反,由各个worker完成某种业务逻辑后,把结果汇总发给某个actor,这个actor不一定是masterActor。

class AggregateMasterActor extends Actor{
override def receive: Receive = {
case cmd: AggregateCommand.Aggregate =>
// 将此次汇总结果汇报给from,为了简化,此处用self替代
val from = self
val backendActor = context.actorOf(Props(new AggregateMasterBackendActor(from,cmd.parallel)),s"AggregateMasterBackendActor-${cmd.at}")
backendActor ! cmd
case AggregateBackendEvent.WorkDone(sum) =>
val from = sender()
println(s"AggregateMasterActor [${self.path.name}] 收到 ${from.path.name} 汇总结果 $sum")
}
}
class AggregateMasterBackendActor(replyTo:ActorRef,parallel:Int) extends Actor{
var counter = 0
var sum = 0L
override def receive: Receive = {
case AggregateCommand.Aggregate(_) =>
println(s"AggregateMasterBackendActor [${self.path.name}] 开始工作,parallel $parallel,工作结果汇总给 ${replyTo.path.name}")
1 to parallel foreach { i =>
val worker = context.actorOf(Props(new AggregateWorker(self)),s"AggregateWorker-$i")
worker ! AggregateBackendCommand.Aggregate(i,parallel)
}
case AggregateWorkerEvent.WorkDone(result) =>
counter += 1
sum += result
if(counter == parallel){
replyTo ! AggregateBackendEvent.WorkDone(sum)
context.stop(self)
println(s"AggregateMasterBackendActor [${self.path.name}] 工作结束退出")
}
}
}
class AggregateWorker(replyTo:ActorRef) extends Actor{
def calcResult(index:Int,parallel:Int):Long = index * parallel
override def receive: Receive = {
case AggregateBackendCommand.Aggregate(index,parallel) =>
println(s"AggregateWorker [${self.path.name}] 开始工作 index=$index,工作汇总给 ${replyTo.path.name}")
val result = calcResult(index,parallel)
replyTo ! AggregateWorkerEvent.WorkDone(result)
println(s"AggregateWorker [${self.path.name}] 工作结束退出")
context.stop(self)
}
} object AggregatePattern {
def main(args: Array[String]): Unit = {
val system = ActorSystem("AggregatePattern",ConfigFactory.load())
val aggregateMasterActor = system.actorOf(Props(new AggregateMasterActor),"AggregateMasterActor")
aggregateMasterActor ! AggregateCommand.Aggregate(3)
}
}

输出:

AggregateMasterBackendActor [AggregateMasterBackendActor-1531383454073] 开始工作,parallel 3,工作结果汇总给 AggregateMasterActor
AggregateWorker [AggregateWorker-1] 开始工作 index=1,工作汇总给 AggregateMasterBackendActor-1531383454073
AggregateWorker [AggregateWorker-2] 开始工作 index=2,工作汇总给 AggregateMasterBackendActor-1531383454073
AggregateWorker [AggregateWorker-3] 开始工作 index=3,工作汇总给 AggregateMasterBackendActor-1531383454073
AggregateWorker [AggregateWorker-1] 工作结束退出
AggregateWorker [AggregateWorker-3] 工作结束退出
AggregateWorker [AggregateWorker-2] 工作结束退出
AggregateMasterBackendActor [AggregateMasterBackendActor-1531383454073] 工作结束退出
AggregateMasterActor [AggregateMasterActor] 收到 AggregateMasterBackendActor-1531383454073 汇总结果 18

  从代码来看该设计模式也比较简单,就是由Master创建以临时的子actor,此处命名为MasterBackend,将汇报对象的actorRef以构造函数的形式传递给MasterBackend,此处为了简单用self替代;MasterBackend根据并行参数,创建对应个数的workerActor,并把本身的actorRef以构造函数的形式传递给workerActor,workerActor执行具体的业务逻辑,并将汇总结果,发送给replyTo(也就是MasterBackend);MasterBackend收到workerActor的汇总结果,根据并行参数,判断所有子actor是否执行结束,若执行结束,此次计算完成,将汇总后的结果,发送给replyTo(也就是MasterActor)。

  上面这种设计模式有一个明显的好处,就是Master可以迅速创建大量的聚合工作而不阻塞,因为它收到命令后,只是简单的创建MasterBackend,工作交给它去执行,这个过程非常快。如果某个聚合工作比较慢,并不会影响其他任务。

  之所以说这个设计模式非常重要,是因为在spark/storm等大多分布式框架中都有它的影子。他们都选择将功能进行拆解,专门的节点或actor分别负责任务的接收、创建、执行、汇总这些工作,工作之间互不影响。如果能够深刻的理解这种设计模式,你将会设计出一个架构分层合理、互相解耦的高质量应用系统。

akka设计模式系列-Aggregate模式的更多相关文章

  1. akka设计模式系列-Backend模式

    上一节我们介绍了Akka使用的基本模式,简单点来说就是,发消息给actor,处理结束后返回消息.但这种模式有个缺陷,就是一旦某个消息处理的比较慢,就会阻塞后面所有消息的处理.那么有没有方法规避这种阻塞 ...

  2. akka设计模式系列-While模式

    While模式严格来说是while循环在Akka中的合理实现.while是开发过程中经常用到的语句之一,也是绝大部分编程语言都支持的语法.但while语句是一个循环,如果循环条件没有达到会一直执行wh ...

  3. akka设计模式系列-Chain模式

    链式调用在很多框架和系统中经常存在,算不得上是我自己总结的设计模式,此处只是简单介绍在Akka中的两种实现方式.我在这边博客中简化了链式调用的场景,简化后也更符合Akka的设计哲学. trait Ch ...

  4. akka设计模式系列-基础模式

    本文介绍akka的基本使用方法,由于属于基础功能,想不出一个很高大上的名称,此处就以基础模式命名.下文会介绍actor的使用方法,及其优劣点. class SimpleActor(name:Strin ...

  5. akka设计模式系列-慎用ask

    慎用ask应该是Akka设计的一个准则,很多时候我们应该禁用ask.之所以单独把ask拎出来作为一篇博文,主要是akka的初学者往往对ask的使用比较疑惑. "Using ask will ...

  6. akka设计模式系列-消息模型(续)

    在之前的akka设计模式系列-消息模型中,我们介绍了akka的消息设计方案,但随着实践的深入,发现了一些问题,这里重新梳理一下设计方法,避免之前的错误.不当的观点给大家带来误解. 命令和事件 我们仍然 ...

  7. akka设计模式系列

    由于本人爱好Scala,顺便也就爱好Akka,但目前网上对Akka的介绍大多都是概念上或技术方向上的介绍,基本没有Akka设计模式或者Actor模型设计模式的资料.这对于Akka的普及非常不利,因为即 ...

  8. PHP设计模式系列 - 外观模式

    外观模式 通过在必需的逻辑和方法的集合前创建简单的外观接口,外观设计模式隐藏了调用对象的复杂性. 外观设计模式和建造者模式非常相似,建造者模式一般是简化对象的调用的复杂性,外观模式一般是简化含有很多逻 ...

  9. akka设计模式系列-actor锚定

    actor锚定模式是指使用actorSelection对acor进行锚定的设计模式,也可以说是一个对actor的引用技巧.在某些情况下,我们可能需要能够根据Actor的path锚定对应的实例.简单来说 ...

随机推荐

  1. Bat 脚本(常用命令)

    Bat 批处理脚本 (常用) Bat 批处理脚本 === Content === 1. Rem 和 :: Rem 为注释命令,能回显. :: 为符号注释,不能回显. %行内注释内容% ===== (不 ...

  2. mysql insert一条记录后 返回创建记录主键id的方法

    mysql插入数据后返回自增ID的方法 mysql和oracle插入的时候有一个很大的区别是,oracle支持序列做id,mysql本身有一个列可以做自增长字段,mysql在插入一条数据后,如何能获得 ...

  3. Hdu 4864(Task 贪心)(Java实现)

    Hdu 4864(Task 贪心) 原题链接 题意:给定n台机器和m个任务,任务和机器都有工作时间值和工作等级值,一个机器只能执行一个任务,且执行任务的条件位机器的两个值都大于等于任务的值,每完成一个 ...

  4. 【Codeforces 1073D】Berland Fair

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 我们可以从左到右枚举一轮. 定义一个cost表示这一轮花费的钱数 如果cost+a[i]<=T那么就可以买它,并且买下它(模拟题目要求) ...

  5. Android layer-list(3)

     Android layer-list(3) 在附录文章3.4的基础上,就Android layer-list再写一个较为复杂的应用. 先写布局文件,该布局涉及到LinearLayoutCompa ...

  6. 利用async和await异步操作解决node.js里面fs模块异步读写,同步结果的问题

    async await 解决异步问题,这两个关键字是es7提出的,所以测试,node和浏览器版本提高一些 async await 操作基于promise实现的 async await这两个关键字是一起 ...

  7. PHP rand()和mt_rand()的区别

    rand()和mt_rand()作用都是产生一个随机整数,都有两种使用形式: 1.int rand(void) / int mt_rand(void) 2.int rand(int $min, int ...

  8. PostGIS学习相关术语

    POI 兴趣点(英语:point of interest,通常缩写成POI)乃是电子地图上的某个地标.景点,用以标示出该地所代表的政府部门.各行各业之商业机构(加油站.百货公司.超市.餐厅.酒店.便利 ...

  9. MYSQL常用的时间日期函数

    #时间日期函数 #获取当前日期XXXX-XX-XXSELECT CURRENT_DATE(); SELECT CURDATE();#效果与上一条相同 #获取当前日期与时间XXXX-XX-XX XX:X ...

  10. Servlet监听器(Listener)实例

    以下内容是翻译自http://www.journaldev.com/1945/servletcontextlistener-servlet-listener-example: 说明:web.xml的加 ...