BT

您是否属于早期采用者或者创新人士?InfoQ正在努力为您设计更多新功能。了解更多

以Akka为示例,介绍Actor模型

| 作者 Jan Stenberg ,译者 邵思华 发布于 2014年11月3日. 估计阅读时间: 不到一分钟 | 智能化运维、Serverless、DevOps......2017年有哪些最新运维技术趋势?CNUTCon即将为你揭秘!

许多开发者在创建和维护多线程应用程序时经历过各种各样的问题,他们希望能在一个更高层次的抽象上进行工作,以避免直接和线程与锁打交道。为了帮助这些开发者,Arun Manivannan编写了一系列的博客帖子,在目前总共六篇帖子中,他通过大量的图片及一些简单的Akka示例,解释了Actor模型的原理,并进一步探索了Akka工具所提供的各种特性。

Arun首先从整体上对Actor进行了介绍,他在示例中将Actor比作了一群人:

你可以将Actor当作是一群人,他们互相之间不会面对面地交流,而只是通过邮件的方式进行沟通。

传递消息是Actor模型的基础,Arun以一名学生和一位教师举例,描述了以下基础流程:

  • 一名学生给一位教师发送了一封邮件,邮件一旦发送之后,就不能够修改了。
  • 该教师会在她认为适合的时机去检查她的邮箱,从而收到这封邮件。
  • 该教师稍后会寄一封回信给该学生,这封回信也是一旦发送就不可变的。
  • 该学生在一段时间后决定去检查一下他的邮箱,从而收到了回信,(他可没有一直守候在邮箱旁等待回信哦)。

如果信息是单向的,那么它一旦送出之后并不会期待或等待任何响应。除了这种情况之外,Actor都能够在一个请求-响应周期内,为发送者发回一个响应消息。

接下来的示例讲解了并发的情况,示例中包含了多名学生和多位教师,每一名学生都会向所有教师发送邮件。这种情况与之前的示例并没有不同,因为每个参与者都分别拥有自己的邮箱,而且每封邮件都会按照它们到达邮箱的顺序被阅读。如果发生了某位教师不能接收邮件的情况,那么一位新的教师会替代他进行接收,从而实现故障转移。

一个Actor的生命周期并不复杂,首先通过构造函数进行创建,随后调用它的preStart方法,而Actor准备开始接收消息时,再调用它的receive方法。最后,调用postStop方法将Actor置为终结状态。Arun还提到,Actor的生命周期与一个Java servlet非常相似,仅存在着一些细微的差异。

Actor之间的关系是层次结构型的,每个Actor都从属于另外一个Actor。Arun将这种结构与文件系统进行了比较,在文件系统中存在着一些顶层文件夹,而当你依照文件夹的层次结构进入内部时,文件夹的总数也在不断上升。通常来说,父Actor创建子Actor以处理一些子任务,或者是让子Actor在隔离的情况下去处理一些特别容易出错的任务,这样可以保证系统在故障发生时能够恢复状态。Actor的容错性的关键部分来自于父Actor管理子Actor生命周期的能力。

Arun还描述了一些其它方面的内容,包括日志记录、测试与配置。你可以从Github下载一个包含了完整源代码的示例项目。

除了用于Java与Scala的Akka项目之外,还有支持其它平台的Actor模型的实现,比如在.NET平台下就存在着两种不同实现方式的Actor项目。

查看英文原文:An Introduction to Actor Model, with Examples in Akka

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

actor多状态实例 by 金 鑫

HI,请教一个问题
假设有一个ActorBiz类,它的内部一个MAP集合需要维护。
当想进行扩展这个ActorBiz的伸缩性,以充分利用多核能力,同时降低单一ActorBiz的负载压力。除了为ActorBiz做集群,还有什么办法?
因为java的并发包比较容易,只要开n个线程,并对map集合进行加锁访问即可。
akka中如何实现?

Re: actor多状态实例 by roger byers

我觉得多个Actor维护同一个MAP可能就和Scala与AKKA所强调的消息、函数式与不变量的概念有所冲突,是否有可能每个Actor维护一个私有的MAP,在必要的时候由一个总的Actor做一个合并?

Re: actor多状态实例 by 金 鑫

好像没有好办法。
我把需求再细化一下吧。
这是面向银行,超市,客户的。
首先银行有数以亿计的客户银行卡
其次,超市全国也有数以万计,每一个超市都有多个pos机,pos机都有特定的ID,可以对银行卡进行读写(即刷卡)
现在银行的服务端需要开发一个服务端应用A。
1、用户到任意超市选购商品
2、用户持银行卡到超市的任意一台pos机(收银机)上刷卡,
3、pos机与银行服务器通讯,扣款,形成销售单,以及流水号
4、结束(密码省略不描述了)
5、同一个顾客有可能在一个超市一天内多次购买,其中甚至还会有多次在同一台POS机上结算刷卡
因为超市的每一台POS机,为了便于对帐,它的交易流水号应该是连续的,出现断号则会不方便在出现错误时能高效对帐。所以一般每一台POS机的交易流水号都是连续的。隔天,交易流水号又从1开始
银行服务端A与核心交易系统之间也会有交互,为了减少与核心交易系统之间的交互,服务端应用A希望对posid上的每一天的交易流水号进行管理,很自然的想法就是创建一个ActorPosId1,内部有一个map(posId,transNumber);每一天晚上24时,开始清零0,之后,该posid上发生的每一笔交易都会自动加1,返回给超市的pos终端上(收银机),并打印在小票上。
很显然,这个ActorPosId1内部的map会比较大,所以,请求量会很大,负载很快过载的。
因此,解决方案一般有三个,
方案一
1)可以根据posid分组,形成ActorPosId1-groupA,ActorPosId1-groupB,等等。
但目前没有找到比较好的分组方案,假设暂不可行
方案二
2)ActorPosId1可以部署成集群,形成10个节点
可以扩展并发量,但问题在于,这个MAP是个频繁更新量很大,数百万的银行卡在POS设备上交易,流水号都要递増更新,从而导致集群的节点之间复制太频繁了,反过来,极大的影响甚至降低性能了
方案三
3)ActorPosId1可以在多个线程上跑,可以适当分流,由于MAP的内部机制,本身会根据HASH值将MAP集合分成一个个小段来操作,以减少锁定的数量集。
方案三也不理想,但至少不需要向集群一样那么复杂,比较轻量级

实际上,这个例子,举的不太合适,而是想以此表明,面对这种情况,akka实践中,有没有什么好的设计模式的解决方案?

Re: actor多状态实例 by roger byers

首先声明我没有用过akka,所以我的想法是很有问题的。
我觉得首先用一个MAP保存所有的PosId的想法可能就是有问题的。如果是我,我会选择为每一个Pos创建一个Actor,每个Actor仅对自身对应的PosId负责。这个PosId可以是放在一个Redis里,同一台Pos所有的取号动作都是通过一个Actor在Redis上一个Key做自增操作,我想性能应该是足够用的,至多取号后异步地写一个日志,在Redis崩溃后可以从日志恢复出来。不成熟的想法,请轻拍。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

4 讨论

深度内容

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT