akka设计模式系列-消息模型
通过前面的文章我们总结了几个常见的actor设计模式,但此处不得不提前介绍一下在Akka中消息的设计模式。随着对Akka的使用,我们会发现,使用Akka设计系统其实就是面向消息编程。actor之间消息设计的是否合理,往往意味着Akka应用设计的是否合理。那么actor之间的消息该如何设计呢?
命令和事件
actor之间都是通过“消息”进行通信的,对各种各样的“消息”进行分析,我们可以把它简单的分为命令和事件两类。命令,是指一个actor给另外一个actor发送指令做相关的业务逻辑;事件,则是actor对某个命令的响应结果,或者对其他事件的响应结果。简单来说,命令是主动让actor做出某种响应,例如发送Stop命令让其他actor销毁自己;事件,往往意味着某种通知,例如actor销毁之前发送Stopped事件给它的supervisor。
我们在用Akka开发应用时候,一定要仔细认真的把系统间的消息按照定义划分为命令和事件。具体如何划分可以参考这两种消息的具体定义或DDD(领域驱动设计)相关概念。此处我们只介绍在代码结构上如何设计它们。
trait Message{
// 消息创建的时间
final val at:Long = System.currentTimeMillis()
}
trait Command extends Message
trait Event extends Message
trait MasterCommand extends Command{
// 定义MasterCommand公有的方法或字段
}
object MasterCommand{
case class StartWork(message:String) extends MasterCommand
}
trait MasterEvent extends Event{
// 定义MasterEvent公有的方法或字段
}
object MasterEvent{
case class WorkStarted(message:String) extends MasterCommand
}
上面是我在开发时常用的设计消息的框架。其中Message这个trait表示对消息的抽象,其中只有一个at字段,是消息创建的时间。Command继承Message,表示对命令的抽象。Event也继承Message,表示对事件的抽象。MasterCommand这个trait继承Command标志master发出的命令。所有master发出的具体命令放在与MasterCommand这个trait同名的object中。当然也可以不同名,只要在一个object中即可。把master具体命令放到一个object中,只是为了对其进行名称的限定。如果其他类型的actor也有一个StartWork命令,在同一个actor中要对这两个StartWork同时做响应的话,会引起歧义。所以我一般都用object来进行隔离,当然是用package或者把StartWork改名也都可以对其进行隔离,这个就是个人爱好了。MasterEvent这个特质表示master收到某个命令或事件进行响应的事件,同样也是master发出的。
上一段话中,我用红色字体标志出了“发出”二字。这意味着,不管是命令还是事件,都是针对发送actor而言的。具体什么意思呢?这其实是一个代码设计的问题,但我觉得比较重要,这里需要单独解释一下。我们知道actor之间是通过消息传递来通信的,那么消息传递一个有一个发送方和接收方。在设计代码时,我们是把消息放到发送方的域中,还是放到接收方的域中呢。比如StartWork这个命令,如果放到masterActor中,就意味着master发出了一个StartWork这个命令,具体是谁收到该消息就不关心了,接收方一定知道该消息是masterActor发出的。如果放到workActor中,就意味着workActor一定会接收该命令,对其作出反应,具体是谁发送的就不关心了。对于事件可以做类比理解。
具体是按照发送方还是按照接收方封装消息,这个就仁者见仁智者见智了,只不过我比较推崇上面代码中的设计方案。因为我们可以围绕actor设计上下文边界,不会对其他领域内的对象进行引用,高内聚低耦合。
其实我们还可以通过消息名称来区分,比如有两个actor都会发出StartWork的消息,那么可以分别用StartType1Work和StartType2Work来命令。但这种方式有个问题就是没法按照类型对不同的命令进行筛选,比如我们可以使用match来对不同类型的消息进行过滤,如果消息是用消息名称进行区分的,在偏函数或者match时是很不方便的,关于这一点希望大家自己好好体会。
其实对于上图中的代码,我一般都会优化成下面的形式。就是把master相关的命令和事件上面再加一个抽象层:master消息。其实都差不多,只不过层次更深而已。优点是可以单独修改公共字段或方法,缺点是设计复杂。
trait Message{
// 消息创建的时间
final val at:Long = System.currentTimeMillis()
}
trait Command extends Message
trait Event extends Message
trait MasterMessage extends Message{
// 定义Master消息共有的方法或字段
}
trait MasterCommand extends MasterMessage with Command{
// 定义MasterCommand公有的方法或字段
}
trait MasterEvent extends MasterMessage with Event{
// 定义MasterEvent公有的方法或字段
}
object MasterCommand{
case class StartWork(message:String) extends MasterCommand
}
object MasterEvent{
case class WorkStarted(message:String) extends MasterCommand
}
关于Akka消息的设计模式就介绍到这里了,在Akka中消息设计的好坏往往决定着应用的质量,希望大家多多实践,多多体会。当然了每个人的设计理念不同,这里也只是抛砖引玉,如果你有更好的设计模式,欢迎留言讨论。
akka设计模式系列-消息模型的更多相关文章
- akka设计模式系列-消息模型(续)
在之前的akka设计模式系列-消息模型中,我们介绍了akka的消息设计方案,但随着实践的深入,发现了一些问题,这里重新梳理一下设计方法,避免之前的错误.不当的观点给大家带来误解. 命令和事件 我们仍然 ...
- akka设计模式系列-慎用ask
慎用ask应该是Akka设计的一个准则,很多时候我们应该禁用ask.之所以单独把ask拎出来作为一篇博文,主要是akka的初学者往往对ask的使用比较疑惑. "Using ask will ...
- akka设计模式系列
由于本人爱好Scala,顺便也就爱好Akka,但目前网上对Akka的介绍大多都是概念上或技术方向上的介绍,基本没有Akka设计模式或者Actor模型设计模式的资料.这对于Akka的普及非常不利,因为即 ...
- akka设计模式系列(Actor模型)
谈到Akka就必须介绍Actor并发模型,而谈到Actor就必须看一篇叫做<A Universal Modular Actor Formalism for Artificial Intellig ...
- akka设计模式系列-While模式
While模式严格来说是while循环在Akka中的合理实现.while是开发过程中经常用到的语句之一,也是绝大部分编程语言都支持的语法.但while语句是一个循环,如果循环条件没有达到会一直执行wh ...
- akka设计模式系列-Backend模式
上一节我们介绍了Akka使用的基本模式,简单点来说就是,发消息给actor,处理结束后返回消息.但这种模式有个缺陷,就是一旦某个消息处理的比较慢,就会阻塞后面所有消息的处理.那么有没有方法规避这种阻塞 ...
- akka设计模式系列-actor锚定
actor锚定模式是指使用actorSelection对acor进行锚定的设计模式,也可以说是一个对actor的引用技巧.在某些情况下,我们可能需要能够根据Actor的path锚定对应的实例.简单来说 ...
- akka设计模式系列-Chain模式
链式调用在很多框架和系统中经常存在,算不得上是我自己总结的设计模式,此处只是简单介绍在Akka中的两种实现方式.我在这边博客中简化了链式调用的场景,简化后也更符合Akka的设计哲学. trait Ch ...
- akka设计模式系列-akka在秒杀场景的应用
本博客讨论一下akka在秒杀场景下的应用,提出自己的见解,只做抛砖引玉,大神勿喷.秒杀活动涉及到前中后台各个阶段,为了说明问题,我们简化场景,只研究akka在后台如何处理秒杀业务. 秒杀活动 所谓的秒 ...
随机推荐
- [Luogu] P3701 「伪模板」主席树
题目背景 byx和手气君都非常都非常喜欢种树.有一天,他们得到了两颗奇怪的树种,于是各自取了一颗回家种树,并约定几年后比一比谁种出来的树更加牛x. 题目描述 很快,这棵树就开花结果了.byx和手气君惊 ...
- Spring 工厂方法创建Bean 学习(三)
1, 静态工厂方法创建Bean 调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节. 要声明通过静态方法创建 ...
- enum 的使用
public enum Color { RED(), GREEN(), BLANK(), YELLO(); // 成员变量 private String name; private int index ...
- 【Codeforces 486C】Palindrome Transformation
[链接] 我是链接,点我呀:) [题意] 光标一开始在p的位置 你可以用上下左右四个键位移动光标(左右)或者更改光标所在的字符(上下增加或减少ascill码) 问你最少要操作多少次才能使得字符串变成回 ...
- 这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化
感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM. 最最后还是要到SQL.....:( 这一关,慢慢练啦.. 实例详解Django的 select_related 和 p ...
- HDU1914(稳定婚姻)
http://acm.hdu.edu.cn/showproblem.php?pid=1914 思路:Gale-Shapley算法.算法过程是男士不停地求婚,女士不停地拒绝.在每一轮中,每个尚未订婚的男 ...
- T5090 众数 codevs
http://codevs.cn/problem/5090/ 时间限制: 1 s 空间限制: 1000 KB 题目等级 : 青铜 Bronze 题目描述 Description 由文件给出N个1到 ...
- 深度优先遍历DFS
深度优先遍历,这个跟树中的遍历类似,做深度遍历就是访问一个节点之后,在访问这个节点的子节点,依次下去是一个递归的过程. 具体代码: void DFS(MGraph g ,int i) { in ...
- NETCore项目报错 An error occurred while starting the application
在发布到IIS的webApi项目中,运行时报出以上错误, 解决方法: 1.打开发布目录文件夹,找到web.config文件 2.打开web.config找到stdoutLogEnabled=" ...
- 【python】蛋疼的中文乱码解决方案
转自: http://yooooo.us/2013/python-encoding-decoding?variant=zh-cn