一、介绍 

当您需要在集群中的多个节点之间分配Actor,并希望能够使用其逻辑标识符与它们进行交互时,集群分片是非常有用的。你无需关心Actor在集群中的物理位置,因为这可能也会随着时间的推移而发生变化。

例如,它可以是代表域驱动设计术语中聚合根的参与者。在这里,我们称这些Actore为“实体”。这些Actor通常具有持久状态,但此功能不仅限于具有持久化状态的Actor。

当你有一个很消耗资源的Actor,例如占内存或者CPU,把它放在一台机器上可能吃不消,这时候集群分片就能够提供很好的帮助,将这些Actor分散在集群中的多个结点上。

二、依赖

<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster-sharding_2.12</artifactId>
<version>2.5.18</version>
</dependency>

三、例子

假设我们有如下一个需要使用集群分片模式的实体Actor:

case object Increment
case object Decrement
final case class Get(counterId: Long)
final case class EntityEnvelope(id: Long, payload: Any) case object Stop
final case class CounterChanged(delta: Int) class Counter extends PersistentActor {
import ShardRegion.Passivate context.setReceiveTimeout(120.seconds) // self.path.name is the entity identifier (utf-8 URL-encoded)
override def persistenceId: String = "Counter-" + self.path.name var count = 0 def updateState(event: CounterChanged): Unit =
count += event.delta override def receiveRecover: Receive = {
case evt: CounterChanged ⇒ updateState(evt)
} override def receiveCommand: Receive = {
case Increment ⇒ persist(CounterChanged(+1))(updateState)
case Decrement ⇒ persist(CounterChanged(-1))(updateState)
case Get(_) ⇒ sender() ! count
case ReceiveTimeout ⇒ context.parent ! Passivate(stopMessage = Stop)
case Stop ⇒ context.stop(self)
}
}

上面这个Actor使用PersistActor中的事件来源模式存储其内部状态,当然其不一定需要是持久化的Actor。使用持久化的好处是,如果节点之间的实体发生故障或迁移,它能够恢复其状态。

我们要使用集群的分片模式,通常就需要在群集中每个节点上的系统启动时,使用ClusterSharding.start方法注册支持的实体类型,这样我们就能在所有将承载分片的节点上运行这个方法来部署分片。其中,ClusterSharding.start如下:

val counterRegion: ActorRef = ClusterSharding(system).start(
typeName = "Counter",
entityProps = Props[Counter],
settings = ClusterShardingSettings(system),
extractEntityId = extractEntityId,
extractShardId = extractShardId)

其中,start方法返回了ShardRegion,是个ActorRef类型。ShardRegion是一个特殊的Actor,负责管理可能多个分片(shard)内称为Entity的Actor实例。这些分片可能是分布在不同的集群节点上的,外界通过ShardRegion与其辖下Entities沟通。从start函数参数entityProps我们看到:每个分片中只容许一个种类的Actor;具体的Entity实例是由另一个内部Actor即shard构建的,shard可以在一个分片中构建多个Entity实例。多shard多entity的特性可以从extractShardId,extractEntityId这两个方法中得到一些信息。我们说过Actor自编码即entity-id是Cluster-Sharding的核心元素。在entity-id这个自编码中还包含了shard-id,所以用户可以通过entity-id的编码规则来设计整个分片系统包括每个ShardRegion下shard和entity的数量。当ShardRegion得到一个entity-id后,首先从中抽取shard-id,如果shard-id在集群中不存在的话就按集群各节点负载情况在其中一个节点上构建新的shard;然后再用entity-id在shard-id分片中查找entity,如果不存在就构建一个新的entity实例。整个shard和entity的构建过程都是通过用户提供的函数extractShardId和extractEntityId实现的,Cluster-Sharding就是通过这两个函数按用户的要求来构建和使用shard和entity的。下面我们看下这种自编码的例子:

val extractEntityId: ShardRegion.ExtractEntityId = {
case EntityEnvelope(id, payload) ⇒ (id.toString, payload)
case msg @ Get(id) ⇒ (id.toString, msg)
} val numberOfShards = 100 val extractShardId: ShardRegion.ExtractShardId = {
case EntityEnvelope(id, _) ⇒ (id % numberOfShards).toString
case Get(id) ⇒ (id % numberOfShards).toString
case ShardRegion.StartEntity(id) ⇒
// StartEntity is used by remembering entities feature
(id.toLong % numberOfShards).toString
}

在大多数情况下工作正常的简单分片算法是获取hashCode实体标识符的模数为分数的绝对值。下面我们可以通过如下程序测试:

val counterRegion: ActorRef = ClusterSharding(system).shardRegion("Counter")
counterRegion ! Get(123)
expectMsg(0) counterRegion ! EntityEnvelope(123, Increment)
counterRegion ! Get(123)
expectMsg(1)

最新文章

  1. 自定义view(一)
  2. dmidecode查看设备硬件信息
  3. js基础:函数表达式和函数声明
  4. kali linux 、 windows、ubuntu三系统的引导问题
  5. 十分钟学会mysql数据库操作
  6. HDU 1209
  7. phalcon: Windows 下 Phalcon dev-tools 配置 和 Phpstorm中配置Phalcon 代码提示, phalcon tools的使用
  8. .NET 托管堆和垃圾回收
  9. Strom-7 Storm Trident 详细介绍
  10. Android开发——fragment中数据传递与刷新UI(更改控件)
  11. nginx 安装php
  12. C# -- 使用Ping检查网络是否正常
  13. TOP按钮
  14. 20155205 郝博雅 Exp5 MSF基础应用
  15. 从前端中的IOC理念理解koa中的app.use()
  16. docker 清理容器的命令
  17. AICODER官方小程序和公众号上线了
  18. hdu5698瞬间移动-(杨辉三角+组合数+乘法逆元)
  19. Ionic 1 &amp; 2 开发常见问题 Q&amp;A
  20. (next_permutation) 排列2 hdu 1716

热门文章

  1. shell监控脚本
  2. Python网络编程(epoll内核监听,多任务多进程)
  3. packstack测试环境安装heat
  4. django的聚合函数和aggregate、annotate方法使用
  5. 洛谷 P2155 [SDOI2008]沙拉公主的困惑 解题报告
  6. gdb server调试步骤
  7. WebStrom Sass 编译配置 windows
  8. 70种简单常用的JS代码
  9. C++ primer 学习笔记之容器insert
  10. Vitamio介绍及使用