akka cluster sharding
cluster sharding 的目的在于提供一个框架,方便实现 DDD,虽然我至今也没搞明白 DDD 到底适用于是什么场合,但是 cluster sharding 却是我目前在做的一个 project 扩展到集群上非常需要的工具。
sharding 要做这么几件事
1. 对于每一个 entity,创建一个 actor。该 entity 有 Id 作为唯一标示。该 entity 的所有消息都由此 actor 来处理
2. 该 actor 在一段时间内不工作时,会超时并 kill self
3. 当一个集群中加入新的节点时,新的 actor 会被自动创建到新 node 上,或者老的actor 会负载均衡,迁移到新 node 上。同样的,当节点挂掉时,挂掉的 actor 会迁移到新的
在 sharding 被提出之前,google group 和 stackoverflow 上有很多人希望有这么一个东西,那时候还是 2011 年,现在已经 2015 年了。
sharding 的原理和用法 doc 都有比较详细的说明,下面做个小测试:
首先是 entity actor 的定义:
object ActionWorker {
def props(): Props = Props(new ActionWorker)
//must return s: Command
val idExtractor: ShardRegion.IdExtractor = {
case s: Command => (s.id, s)
}
val shardResolver: ShardRegion.ShardResolver = msg => msg match {
case s: Command => (math.abs(s.id.hashCode) % 100).toString
}
val shardName: String = "ActionWorker"
}
idExtractor 会从 message 中抽取 id,作为路由的依据,而返回值的第二项是 actor 收到的消息
shardResolver 根据 id 确定 shard 所在的位置,哈希函数的设定方式我也没有自习研究,doc 说是 id 的十倍就可以。
class ActionWorker extends Actor {
val log = Logging(context.system, this)
println("action worker is created")
context.setReceiveTimeout(30 seconds)
override def receive: Receive = {
case Command(id, payload) =>
val selfDesc = self.path.parent.name + "-" + self.path.name
println("here i am, working: " + selfDesc)
log.info("here i am, working: " + selfDesc)
case ReceiveTimeout =>
log.info("nothing to do, better kill myself")
val selfDesc = self.path.parent.name + "-" + self.path.name
println("here i am, working: " + selfDesc)
println("nothing to do, better kill myself")
context.stop(self)
}
actor 的定义没有特别之处,需要注意的是
1. actor 收到的消息是 idExtract 的第二项,而不是 s: Command 那个东西
2. actor 没有一个正常的途径得到自己的id,一个 workaroud 的办法是通过 self.path.name 来得到自己的id,再据此完成某些初始化操作
worker 处理数据,生成数据的 actor 叫做 Bot
class Bot extends Actor {
val log = Logging(context.system, this)
val tickTask = context.system.scheduler.schedule(3.seconds, 10.seconds, self, Command(""))
def receive = create
val postRegion = ClusterSharding(context.system).shardRegion(ActionWorker.shardName)
val create: Receive = {
case Command(id, payload) =>
val postId = Random.nextInt(5).toString
log.info("bot create new command and received: " + postId)
println("new command postID = " + postId)
postRegion ! Command(postId, postId)
}
}
Bot 生成的数据要传到 worker actor,注意 postRegion 的获得方式,它首先从 actorSystem 中得到 ClusterSharding 集合(一个 actorSystem 可能会有多个 shard),然后根据 shardName 定位到唯一的 shard。最后把需要发送的消息传给 postRegin,postRegin 会完成转发。
Main 方法的 startUp 函数
def startup(ports: Seq[String]): Unit = {
ports foreach { port =>
// Override the configuration of the port
val config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port).
withFallback(ConfigFactory.load())
// Create an Akka system
val system = ActorSystem("ClusterSystem", config)
startupSharedJournal(system, startStore = (port == "2551"), path =
ActorPath.fromString("akka.tcp://ClusterSystem@127.0.0.1:2551/user/store"))
ClusterSharding(system).start(
typeName = ActionWorker.shardName,
entryProps = Some(ActionWorker.props()),
idExtractor = ActionWorker.idExtractor,
shardResolver = ActionWorker.shardResolver)
if (port != "2551" && port != "2552")
system.actorOf(Props[Bot], "bot")
}
}
def startupSharedJournal(system: ActorSystem, startStore: Boolean, path: ActorPath): Unit = {
// Start the shared journal on one node (don't crash this SPOF)
// This will not be needed with a distributed journal
if (startStore)
system.actorOf(Props[SharedLeveldbStore], "store")
// register the shared journal
import system.dispatcher
implicit val timeout = Timeout(15.seconds)
val f = (system.actorSelection(path) ? Identify(None))
f.onSuccess {
case ActorIdentity(_, Some(ref)) => SharedLeveldbJournal.setStore(ref, system)
case _ =>
system.log.error("Shared journal not started at {}", path)
system.shutdown()
}
f.onFailure {
case _ =>
system.log.error("Lookup of shared journal at {} timed out", path)
system.shutdown()
}
}
startupSharedJournal 是必须要执行的,不然 cluster 跑不起来。(后面测试了下,发现能跑起来)
ClusterSharding 在本 actorSystem 启动,参数比较直观。
需要注意的是:
1. sharedJournal 是在测试情况下才用得到的,在 prod 环境下应该使用 journal
2. cluster sharding 借助 cluster singleton 实现
akka cluster sharding的更多相关文章
- akka cluster sharding source code 学习 (1/5) 替身模式
为了使一个项目支持集群,自己学习使用了 akka cluster 并在项目中实施了,从此,生活就变得有些痛苦.再配上 apache 做反向代理和负载均衡,debug 起来不要太酸爽.直到现在,我还对 ...
- akka cluster sharding source code 学习 (2/5) handle off
一旦 shard coordinator(相当于分布式系统的 zookeeper) 启动,它就会启动一个定时器,每隔一定的时间尝试平衡一下集群中各个节点的负载,平衡的办法是把那些负载较重的 actor ...
- Akka Cluster简介与基本环境搭建
akka集群是高容错.去中心化.不存在单点故障以及不存在单点瓶颈的集群.它使用gossip协议通信以及具备故障自动检测功能. Gossip收敛 集群中每一个节点被其他节点监督(默认的最大数量为 ...
- akka cluster 初体验
cluster 配置 akka { actor { provider = "akka.cluster.ClusterActorRefProvider" } remote { log ...
- Akka系列(十):Akka集群之Akka Cluster
前言........... 上一篇文章我们讲了Akka Remote,理解了Akka中的远程通信,其实Akka Cluster可以看成Akka Remote的扩展,由原来的两点变成由多点组成的通信网络 ...
- Run a task only once in (akka) cluster
在stackOverflow网站上看到这一提问,下文是部分摘抄问题简述: Java cluster, run task only once We have a java process, which ...
- akka cluster singleton
cluster singleton 需要注意的一点是 ClusterSingletonProxy 必须和 ClusterSingletonManager 一起工作 尝试过通过 path 来获得 sin ...
- Akka Cluster之集群分片
一.介绍 当您需要在集群中的多个节点之间分配Actor,并希望能够使用其逻辑标识符与它们进行交互时,集群分片是非常有用的.你无需关心Actor在集群中的物理位置,因为这可能也会随着时间的推移而发生变 ...
- akka-typed(7) - cluster:sharding, 集群分片
在使用akka-typed的过程中发现有很多地方都简化了不少,变得更方便了,包括:Supervision,只要用Behaviors.supervise()把Behavior包住,很容易就可以实现这个a ...
随机推荐
- 树莓派.Qt.打包开发好的程序并运行的方法
Qt开发的软件, 想要部署在树莓派上运行, 需要进行打包和发布 主要步骤如下: 1. 找1个树莓派用于开发与打包, 所以需要在它上面安装Qt开发环境 树莓派上安装Qt的方法, 可以看这里>> ...
- 【转】Angular之constructor和ngOnInit差异及适用场景
原文:http://liuwenzhuang.github.io/2016/03/04/angular2-constructor-versus-ngOnInit.html -------------- ...
- Java循环一个对象的所有属性,并通过反射给这些属性赋值/取值
Java循环一个对象的所有属性,并通过反射给这些属性赋值/取值 说到循环遍历,最常见的遍历数组/列表.Map等.但是,在开发过程中,有时需要循环遍历一个对象的所有属性.遍历对象的属性该如何遍历呢?查了 ...
- Python:提取网页中的电子邮箱
import requests, re #regex = r"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)"#这个正则表达式过滤 ...
- ASP.NET CORE 之 在IIS上部署MVC项目
与ASP.NET时代不同,ASP.NET Core不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是作为反向代理的角色转发请求到Kestrel ...
- 解决nginx access日志中400 bad request 错误(转)
在access.log中有大量400错误,并以每天几百M的速度增加,占用大量空间.tail -f /opt/nginx/logs/access.log 116.236.228.180 - - [15/ ...
- [Aaronyang] 写给自己的WPF4.5 笔记13[二维自定义控件技巧-可视化状态实战,自定义容器,注册类命令,用户控件补充]
我的文章一定要做到对读者负责,否则就是失败的文章 --------- www.ayjs.net aaronyang技术分享 博文摘要:欢迎大家来支持我的<2013-2015 Aar ...
- css组合选择器
组合选择器:1,后代选择器 .main h2 {...}, 使用空格表示 IE6+2,子选择器 .main>h2 {...}, 使用 > 表示 IE7+3,兄弟选择器 h2+p {...} ...
- 关于dealloc 注意事项
以下讨论在 MRC 下. 1,不要在init和dealloc函数中使用accessor Don’t Use Accessor Methods in Initializer Methods and de ...
- [svc]HTTPS证书生成原理和部署细节
参考: http://www.barretlee.com/blog/2015/10/05/how-to-build-a-https-server/ 今天摸索了下 HTTPS 的证书生成,以及它在 Ng ...