AKKA集群中的分布式发布订阅
集群中的分布式发布订阅
如何向一个不知道在哪个节点上运行的actor发送消息呢?
如何向集群中的所有actor发送感兴趣的主题的消息?
这种模式提供了一个中介actor,akka.cluster.pubsub.DistributedPubSubMediator,它管理actor引用的注册,复制所有集群节点或者特定角色节点的对等actor的条目。
DistributedPubSubMediator actor应该在所有的节点上或者特定角色的节点上启动。中介可以由DistributedPubSub扩展启动或者作为普通的actor启动。
注册最终是一致的,即变化不会被其它的节点立即看到,但是通常它们会在几秒之后被完全复制到所有的节点上。只在自己的注册部分执行变化,这些变化被版本化了。变化的增量用gossip协议以可伸缩的方式传播到其它的节点。
WeaklyUp状态的集群成员,如果这个特性使能了,将会参与到分布式发布订阅,即WeaklyUp状态节点的订阅者会收到发布的消息,如果发布者和订阅者在同一个网络分区。
你可以通过任意节点上的中介者向任何其它节点注册的actor发送消息。
有两种不同的消息投递模式,分别在发布和发送章节进行解释。
发布Publish
这是真正的发布订阅模式。这种模式的一种典型用法就是即时消息应用中的聊天室。
Actor注册到被命名的主题。这将使能每一个节点上的多个订阅者。消息将会投递到这个主题的所有订阅者。
为了提高效率,消息只会通过这个wire向每一个节点发送一次(有匹配的主题)然后就被投递到本地主题的所有订阅者。
你用DistributedPubSubMediator.Subscribe方法将actor注册到本地中介者。成功的订阅和取消订阅由DistributedPubSubMediator.SubscribeAck和 DistributedPubSubMediator.UnsubscribeAck应答确认。这个确认消息意味着订阅已经注册了,但是它仍然需要花费一些时间复制到其它的节点上。
你通过向本地的中介者发送DistributedPubSubMediator.Publish消息来发布消息。
当actor终止时,它们会自动从注册表移除,或者你可以明确的使用DistributedPubSubMediator.Unsubscribe移除。
订阅actor的一个例子:
- import akka.actor.ActorRef;
- import akka.actor.UntypedActor;
- import akka.cluster.pubsub.DistributedPubSub;
- import akka.cluster.pubsub.DistributedPubSubMediator;
- import akka.event.Logging;
- import akka.event.LoggingAdapter;
- publicclass Subscriber extends UntypedActor {
- LoggingAdapter log = Logging.getLogger(getContext().system(), this);
- public Subscriber() {
- ActorRef mediator = DistributedPubSub.get(getContext().system()).mediator();
- // subscribe to the topic named "content"
- mediator.tell(new DistributedPubSubMediator.Subscribe("content", getSelf()), getSelf());
- }
- @Override
- publicvoid onReceive(Object msg) {
- if (msginstanceof String)
- log.info("Got: {}", msg);
- elseif (msginstanceof DistributedPubSubMediator.SubscribeAck)
- log.info("subscribing");
- else
- unhandled(msg);
- }
- }
订阅者可以再集群的多个节点上启动,所有的订阅者都会收到发布到"content"主题的消息:
system.actorOf(Props.create(Subscriber.class), "subscriber1");
//another node
system.actorOf(Props.create(Subscriber.class), "subscriber2");
system.actorOf(Props.create(Subscriber.class), "subscriber3");
一个发布消息到"content"主题的简单actor:
- import akka.actor.ActorRef;
- import akka.actor.UntypedActor;
- import akka.cluster.pubsub.DistributedPubSub;
- import akka.cluster.pubsub.DistributedPubSubMediator;
- publicclass Publisher extends UntypedActor {
- // activate the extension
- ActorRef mediator = DistributedPubSub.get(getContext().system()).mediator();
- @Override
- publicvoid onReceive(Object msg) {
- if (msginstanceof String) {
- String in = (String) msg;
- String out = in.toUpperCase();
- mediator.tell(new DistributedPubSubMediator.Publish("content", out), getSelf());
- } else {
- unhandled(msg);
- }
- }
- }
它可以从集群中的任何地方发布消息到这个主题:
//somewhere else
ActorRef publisher = system.actorOf(Props.create(Publisher.class), "publisher");
// after a while the subscriptions are replicated
publisher.tell("hello", null);
主题分组
具有groupid的Actor也订阅被命名的主题。如果用group Id订阅,那么每一个发布到该主题(sendOneMessageToEachGroup标记为true)的消息都通过RoutingLogic(默认是随机的)投递到每一个订阅组的一个actor。
如果所有的订阅actor都具有相同的group id,那么它工作起来就像Send(发送),每一个消息只投递到一个订阅者。
如果所有的订阅actor具有不同的group名字,那么它工作起来就跟正常的Publish(发布)一样了,每一个消息都广播到所有的订阅者。
注意:如果使用group id,那么它将是主题标识符的一部分。用sendOneMessageToEachGroup=false发送的消息将不会投递到以group id订阅的订阅者。用sendOneMessageToEachGroup=true发布的消息不会投递到没有用group id订阅的订阅者。
发送Send
这是点到点模式,每一个消息都投递到一个目的地,但是你仍然不知道目的地位于哪儿。这种模式的典型用法是即时消息应用中的私有聊天。它可以被用于发布任务到注册的worker,就像感知集群的router那样,routee会动态注册自己。
消息会被投递到一个匹配路径的接收者,如果注册表中存在这样的接收者。如果多个条目匹配这个路径,因为它注册到了多个节点上,那么消息会通过提供的RoutingLogic (默认是随机的)投递到目的地。消息的发送者可以指定偏好本地近亲,即消息发送到一个相同的本地actor系统中的中介者actor,如果他存在的话,否则就会路由到其它匹配的条目。
你会用DistributedPubSubMediator.Put 注册actor到本地的中介者。Put中的ActorRef必须与中介者属于相同的本地actor系统。没有地址信息的路径就是你发送消息的关键字。在每一个节点上,只有一个给定路径的actor,因为一个本地actor系统中的路径是唯一的。
你用DistributedPubSubMediator.Send消息发送消息到具有目的actor路径(没有地址信息)的本地中介者。
当actor终止时,它们自动从注册表中移除,或者你可以明确地使用DistributedPubSubMediator.Remove移除。
目的actor的示例:
- import akka.actor.ActorRef;
- import akka.actor.UntypedActor;
- import akka.cluster.pubsub.DistributedPubSub;
- import akka.cluster.pubsub.DistributedPubSubMediator;
- import akka.event.Logging;
- import akka.event.LoggingAdapter;
- publicclass Destination extends UntypedActor {
- LoggingAdapter log = Logging.getLogger(getContext().system(), this);
- public Destination() {
- ActorRef mediator = DistributedPubSub.get(getContext().system()).mediator();
- // register to the path
- mediator.tell(new DistributedPubSubMediator.Put(getSelf()), getSelf());
- }
- @Override
- publicvoid onReceive(Object msg) {
- if (msginstanceof String)
- log.info("Got: {}", msg);
- elseif (msginstanceof DistributedPubSubMediator.SubscribeAck)
- log.info("subscribing");
- else
- unhandled(msg);
- }
- }
Subscriber actors can be started on several nodes in the cluster, and all will receive messages published to the "content" topic.
system.actorOf(Props.create(Destination.class), "destination");
//another node
system.actorOf(Props.create(Destination.class), "destination");
向"content"主题发送消息的简单actor:
- import akka.actor.ActorRef;
- import akka.actor.UntypedActor;
- import akka.cluster.pubsub.DistributedPubSub;
- import akka.cluster.pubsub.DistributedPubSubMediator;
- publicclass Sender extends UntypedActor {
- // activate the extension
- ActorRef mediator = DistributedPubSub.get(getContext().system()).mediator();
- @Override
- publicvoid onReceive(Object msg) {
- if (msginstanceof String) {
- String in = (String) msg;
- String out = in.toUpperCase();
- booleanlocalAffinity = true;
- mediator.tell(new DistributedPubSubMediator.Send("/user/destination",out,
- localAffinity), getSelf());
- } else {
- unhandled(msg);
- }
- }
- }
可以从集群的任何地方向主题发布消息:
//somewhere else
ActorRef sender = system.actorOf(Props.create(Publisher.class), "sender");
// after a while the destinations are replicated
sender.tell("hello", null);
向用Put注册的actor广播消息也是可能的。向本地的中介者发送 DistributedPubSubMediator.SendToAll消息,包装消息会被投递到匹配路径的所有接收者。具有相同path的actor,没有地址信息,可以在不同的节点上注册。每一个节点只能有一个这样的actor,因为一个本地actor系统的路径是唯一的。
这种模式的典型用法是广播消息给相同路径的接收者,例如不同节点上的3个actor执行相同的动作来实现冗余。你可以指定一个属性(allButSelf)来决定是否消息应该发送到自己节点上的匹配路径。
Distributed发布订阅扩展
在上面的例子中,中介者是通过akka.cluster.pubsub.DistributedPubSub扩展启动和访问的。在大多数场景下,这都是很方便的,也是极好的,但是最好要知道中介者actor也可以作为普通的actor启动,你可以具有多个不同中介者actor,这能够将大量的actor/主题分到不同的中介者。例如,你可能想要使用不同的集群角色的中介者。
DistributedPubSub扩展可以用如下的属性进行配置:
# Settings for the DistributedPubSub extension
akka.cluster.pub-sub {
# Actor name of the mediator actor, /system/distributedPubSubMediator
name = distributedPubSubMediator
# Start the mediator on members tagged with this role.
# All members are used if undefined or empty.
role = ""
# The routing logic to use for 'Send'
# Possible values: random, round-robin, broadcast
routing-logic = random
# How often the DistributedPubSubMediator should send out gossip information
gossip-interval = 1s
# Removed entries are pruned after this duration
removed-time-to-live = 120s
# Maximum number of elements to transfer in one message when synchronizing the registries.
# Next chunk will be transferred in next round of gossip.
max-delta-elements = 3000
# The id of the dispatcher to use for DistributedPubSubMediator actors.
# If not specified default dispatcher is used.
# If specified you need to define the settings of the actual dispatcher.
use-dispatcher = ""
}
推荐当actor系统启动时加载这个扩展,这需要定义akka.extensions配置属性。否则它在第一次使用时激活,然后过一会儿才能使用。
akka.extensions = ["akka.cluster.pubsub.DistributedPubSub"]
投递保证
正如Akka的消息投递可靠性所言,在分布式发布订阅模式中的消息投递保证是最多一次投递at-most-once delivery。换句话说,消息可能会丢失。
如果你正在寻找at-least-once投递保证,我们推荐Kafka Akka Streams integration。
依赖
要使用分布式发布订阅,你得工程必须添加如下的依赖:
sbt:
"com.typesafe.akka" %% "akka-cluster-tools" % "2.4.16"
maven:
- <dependency>
- <groupId>com.typesafe.akka</groupId>
- <artifactId>akka-cluster-tools_2.11</artifactId>
- <version>2.4.16</version>
- </dependency>
AKKA集群中的分布式发布订阅的更多相关文章
- AKKA 集群中的发布与订阅Distributed Publish Subscribe in Cluster
Distributed Publish Subscribe in Cluster 基本定义 在单机环境下订阅与发布是很常用的,然而在集群环境是比较麻烦和不好实现的: AKKA已经提供了相应的实现,集群 ...
- Akka系列(十):Akka集群之Akka Cluster
前言........... 上一篇文章我们讲了Akka Remote,理解了Akka中的远程通信,其实Akka Cluster可以看成Akka Remote的扩展,由原来的两点变成由多点组成的通信网络 ...
- 如果Apache Spark集群中没有分布式系统,则会?
若当连接到Spark的master之后,若集群中没有分布式文件系统,Spark会在集群中每一台机器上加载数据,所以要确保Spark集群中每个节点上都有完整数据. 通常可以选择把数据放到HDFS.S3或 ...
- 一脸懵逼学习KafKa集群的安装搭建--(一种高吞吐量的分布式发布订阅消息系统)
kafka的前言知识: :Kafka是什么? 在流式计算中,Kafka一般用来缓存数据,Storm通过消费Kafka的数据进行计算.kafka是一个生产-消费模型. Producer:生产者,只负责数 ...
- Hadoop学习笔记—13.分布式集群中节点的动态添加与下架
开篇:在本笔记系列的第一篇中,我们介绍了如何搭建伪分布与分布模式的Hadoop集群.现在,我们来了解一下在一个Hadoop分布式集群中,如何动态(不关机且正在运行的情况下)地添加一个Hadoop节点与 ...
- redis/分布式文件存储系统/数据库 存储session,解决负载均衡集群中session不一致问题
先来说下session和cookie的异同 session和cookie不仅仅是一个存放在服务器端,一个存放在客户端那么笼统 session虽然存放在服务器端,但是也需要和客户端相互匹配,试想一个浏览 ...
- 分布式集群中,设定时间同步服务器,以及ntpd与ntpdate的区别
什么时候配置时间同步? 当分布式集群配置好了以后,马上配置的是SSH无密钥配置,然后就是配置时间同步. 时间同步在集群中特别重要. 一:时间同步 1.时间同步 集群中必须有一个统一的时间 如果是内网, ...
- 030 分布式集群中,设定时间同步服务器,以及ntpd与ntpdate的区别
什么时候配置时间同步? 当分布式集群配置好了以后,马上配置的是SSH无密钥配置,然后就是配置时间同步. 时间同步在集群中特别重要. 一:时间同步 1.时间同步 集群中必须有一个统一的时间 如果是内网, ...
- Hadoop学习之路(十二)分布式集群中HDFS系统的各种角色
NameNode 学习目标 理解 namenode 的工作机制尤其是元数据管理机制,以增强对 HDFS 工作原理的 理解,及培养 hadoop 集群运营中“性能调优”.“namenode”故障问题的分 ...
随机推荐
- iOS APP网络分析之rvictl(可以捕捉除了Wifi以外的网络类型)
From: http://danqingdani.blog.163.com/blog/static/18609419520135204934551/ wireshark亲测可用. ********** ...
- mysql视图 新手的问答
☺ζั͡ޓއއއ๓º♥双٩(•(365335093) 16:03:02 创建的视图能保存多长时间,保存在哪啊 上天&宠儿(961431958) 16:08:59 数据库 上天&宠儿(9 ...
- 【Active入门-2】ActiveMQ学习-生产者与消费者
1个生产者,1个消费者,使用Queue: 方式1: 生产者将消息发送到Queue中,退出: 然后运行消费者: . 可以看到,可以接收到消息. 方式2: 先运行消费者程序: 然后运行生产者: 消费者见下 ...
- 创建一个包括菜单栏,工具栏,状态栏,文本编辑部件的经典GUI应用程序的骨架
效果如下: 代码如下: #!/usr/bin/python3 # -*- coding: utf-8 -*- """ This program creates a ske ...
- 1110 Complete Binary Tree (25 分)
1110 Complete Binary Tree (25 分) Given a tree, you are supposed to tell if it is a complete binary t ...
- 搭建OpenStack先电云平台
实际操作示意图 在VMware里面创建两台centos7的虚拟机作为搭建云平台的两节点配置如下: 1.第一台虚拟机 作为控制节点 2CPU 3G以上内存 硬盘50G 网络适配器一个nat 一个仅主 ...
- Python3 os.stat() 方法
概述 os.stat() 方法用于在给定的路径上执行一个系统 stat 的调用.语法 stat()方法语法格式如下: os.stat(path) 参数 path -- 指定路径 返回值 stat 结构 ...
- lambda,sorted(),filter(),map(),递归,二分法
1. lambda 匿名函数 语法: lambda 参数:返回值 不能完成复杂的操作例 # li=['21','asdd','weqeqw','wqf']# # it=iter(li)# # prin ...
- DistCp 集群之间数据拷贝工具
DistCp(分布式拷贝)是用于大规模集群内部和集群之间拷贝的工具.可以将数据拷贝到另个一集群,也可以将另一个集群的数据拷贝到本集群.
- 黑盒测试用例设计——PICT(QQ实践)
以QQ的状态设置来做一次实践.QQ用户可以对如下的状态方面的设置.后两张图是登录后的状态的可选项和鼠标键盘无动作后将状态切换至的可选项.默认的自动回复有三种,默认的快捷回复有四种.对于自动回复和快捷 ...