所谓的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. 常用Linux命令_20190211

    1.创建文件夹:mkdir 文件夹名称 2.查看IP地址信息:ipconfig -a 3.查看内存使用情况:free -m 4.查看CPU使用情况:top 5.查看磁盘使用情况:df -a/-h 6. ...

  2. ORM优化

    orm优化数据库访问:https://docs.djangoproject.com/en/1.11/topics/db/optimization/ 一.QuerySet 可迭代 querysey=mo ...

  3. NFV

    转载: NFV介绍定义:NFV,即网络功能虚拟化,Network Function Virtualization.通过使用x86等通用性硬件以及虚拟化技术,来承载很多功能的软件处理.从而降低网络昂贵的 ...

  4. Code128条形码如何计算其宽度?如何得出其校验位?

    原文链接 Code128条形码是一个非常高密的字母数字条码,能够存储需要的编码数据,它可以编码所有128个ASCII码字符,它使用最少的空间. 在Code128符号体系中,每个数据字符编码都是由11个 ...

  5. str类型内置方法

    目录 str类型内置方法 用途 定义方式 常用操作和内置方法 优先掌握 需要掌握 了解 存一个值or多个值 有序or无序 可变or不可变 强化训练 str类型内置方法 用途 字符串数字.字母.下划线组 ...

  6. Python基础之变量进阶

    变量的引用 变量和数据都是保存在内存中的: 在python中函数的参数传递以及返回值都是靠引用传递的. 函数引用的概念 在python中 变量和数据时分开存储的: 数据保存在内存中的一个位置: 变量保 ...

  7. JavaScript保留关键字(全)

    JavaScript 标准 所有的现代浏览器已经完全支持 ES5(ECMAScript 5). JavaScript 保留关键字(keyword) Javascript 的保留关键字(标识符)不可以用 ...

  8. nyoj 19 擅长排列的小明(深搜,next_permutation)

    擅长排列的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 小明十分聪明,而且十分擅长排列计算.比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想 ...

  9. 小a和uim之大逃离(洛谷 1373)

    题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个 ...

  10. 【Java基础】Java基本数据类型与位运算

    1.赋值运算符 赋值使用操作符“=”.它的意思是“取右边的值(即右值),把它复制给左边(即左值)”.右值可以是任何 常数.变量或者表达式 (只要它能 生成 一个值就行).但左值必须是一个明确的,已命名 ...