Distributed Publish Subscribe in Cluster

基本定义

在单机环境下订阅与发布是很常用的,然而在集群环境是比较麻烦和不好实现的;

AKKA已经提供了相应的实现,集群环境各节点之间的actor相互订阅发布感兴的主题的消息,

关键依赖媒介actor: akka.cluster.pubsub.DistributedPubSubMediator


订阅:

DistributedPubSubMediator.Subscribe方法将actor注册到本地中介者。
成功的订阅和取消订阅由DistributedPubSubMediator.SubscribeAck和DistributedPubSubMediator.UnsubscribeAck应答确认。这个确认消息意味着订阅已经注册了,但是它仍然需要花费一些时间复制到其它的节点上。节点之间发现与注册会有一定延迟,可能造成消息不会立即送达!

发布:

你通过向本地的中介者发送DistributedPubSubMediator.Publish消息来发布消息。
当actor终止时,它们会自动从注册表移除,或者你可以明确的使用DistributedPubSubMediator.Unsubscribe移除。

实现示例

package pubsub

import akka.actor.AbstractActor
import akka.actor.ActorRef
import akka.actor.ActorSystem
import org.slf4j.LoggerFactory
import scala.PartialFunction
import scala.runtime.BoxedUnit
import akka.cluster.pubsub.DistributedPubSubMediator
import akka.actor.Nobody.tell
import akka.actor.Props
import java.time.Clock.system
import akka.cluster.pubsub.DistributedPubSub
import akka.actor.Nobody.tell
import com.typesafe.config.ConfigFactory /**
* Created by: tankx
* Date: 2019/7/16
* Description: 发布订阅模式
*/
/**
* 定义发布者
*/
class Pub() : AbstractActor() { private var log = LoggerFactory.getLogger(Pub::class.java) var mediator: ActorRef = DistributedPubSub.get(context.system).mediator() override fun createReceive(): Receive {
return receiveBuilder().matchAny(this::receive).build()
} private fun receive(msg: Any) { log.info("派发事件:$msg")
if (msg is String) {
mediator.tell(DistributedPubSubMediator.Publish(topA, msg), self)
} } } /**
* 定义订阅者
*/
class Sub() : AbstractActor() { private var log = LoggerFactory.getLogger(Sub::class.java) override fun preStart() {
//注册订阅
var mediator = DistributedPubSub.get(getContext().system()).mediator()
mediator.tell(DistributedPubSubMediator.Subscribe(topA, self), self) println("注册订阅")
//ActorRef.noSender()不会接收订阅信息DistributedPubSubMediator.SubscribeAck
//mediator.tell(DistributedPubSubMediator.Subscribe(topA, self), ActorRef.noSender()) //移除订阅
//DistributedPubSub.get(getContext().system()).mediator().tell(DistributedPubSubMediator.Unsubscribe(topA, self), ActorRef.noSender())
} override fun createReceive(): Receive {
return receiveBuilder().matchAny(this::receive).build()
} private fun receive(msg: Any) { when (msg) {
is String -> log.info("收到事件: $msg")
is DistributedPubSubMediator.SubscribeAck -> log.info("订阅事件:$msg")
else -> log.info("无对应类型")
} } } //定义主题
var topA: String = "topa" fun getSystem(port: Int): ActorSystem { val config = ConfigFactory.parseString(
"akka.remote.netty.tcp.port=$port"
).withFallback(
ConfigFactory.load("application_pub.conf")
) var actorSystem = ActorSystem.create("custerPubSystem", config); return actorSystem
} fun main() { var system = getSystem(3660); var subActor = system.actorOf(Props.create(Sub::class.java))
Thread.sleep(1000)//让sub 完全起来 // var pubActor = system.actorOf(Props.create(Pub::class.java))
// pubActor.tell("hello", ActorRef.noSender())
//
// pubActor.tell("world", ActorRef.noSender())
//
// Thread.sleep(3000) }

上面订阅启动后,再启动一个节点派发事件

package pubsub

import akka.actor.ActorRef
import akka.actor.Props
import akka.cluster.pubsub.DistributedPubSub
import akka.cluster.pubsub.DistributedPubSubMediator /**
* Created by: tankx
* Date: 2019/7/18
* Description:
*/
fun main() { var system = getSystem(3661); Thread.sleep(3000) var mediator: ActorRef = DistributedPubSub.get(system).mediator()
  
for (i in 1..1000) {
mediator.tell(DistributedPubSubMediator.Publish(topA, "消息XXXXXX"), ActorRef.noSender()) Thread.sleep(2000)
} }

配置文件

akka {
actor {
provider = "akka.cluster.ClusterActorRefProvider"
} cluster {
seed-nodes = [
"akka.tcp://custerPubSystem@127.0.0.1:3660"
]
} remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port = 0
}
} }

依赖JAR

    compile("com.typesafe.akka:akka-actor_2.13:$akkaVersion")
compile("com.typesafe.akka:akka-remote_2.13:$akkaVersion")
compile("com.typesafe.akka:akka-cluster-tools_2.13:$akkaVersion")

结果:

2019-07-18 20:19:55.941 [custerPubSystem-akka.actor.default-dispatcher-4] INFO  pubsub.Sub 77- 收到事件: 消息XXXXXX
2019-07-18 20:19:55.942 [custerPubSystem-akka.actor.default-dispatcher-4] INFO pubsub.Sub 77- 收到事件: 消息XXXXXX

结论:

AKKA 集群中的发布与订阅在节点之间的Actor之间广播消息,监听自己关心的主题消息做相应逻辑,是非常方便与很多场景适用的

AKKA 集群中的发布与订阅Distributed Publish Subscribe in Cluster的更多相关文章

  1. AKKA集群中的分布式发布订阅

    集群中的分布式发布订阅 如何向一个不知道在哪个节点上运行的actor发送消息呢? 如何向集群中的所有actor发送感兴趣的主题的消息? 这种模式提供了一个中介actor,akka.cluster.pu ...

  2. RabbitMQ官方中文入门教程(PHP版) 第三部分:发布/订阅(Publish/Subscribe)

    发布/订阅 在上篇教程中,我们搭建了一个工作队列.每个任务之分发给一个工作者(worker).在本篇教程中,我们要做的之前完全不一样——分发一个消息给多个消费者(consumers).这种模式被称为“ ...

  3. RabbitMQ 入门教程(PHP版) 第三部分:发布/订阅(Publish/Subscribe)

    发布/订阅 在上篇第二部分教程中,我们搭建了一个工作队列.每个任务之分发给一个工作者(worker).在本篇教程中,我们要做的之前完全不一样——分发一个消息给多个消费者(consumers).这种模式 ...

  4. Akka系列(十):Akka集群之Akka Cluster

    前言........... 上一篇文章我们讲了Akka Remote,理解了Akka中的远程通信,其实Akka Cluster可以看成Akka Remote的扩展,由原来的两点变成由多点组成的通信网络 ...

  5. 借 redis cluster 集群,聊一聊集群中数据分布算法

    Redis Cluster 集群中涉及到了数据分布问题,因为 redis cluster 是多 master 的结构,每个 master 都是可以提供存储服务的,这就会涉及到数据分布的问题,在新的 r ...

  6. Akka源码分析-Cluster-Distributed Publish Subscribe in Cluster

    在ClusterClient源码分析中,我们知道,他是依托于“Distributed Publish Subscribe in Cluster”来实现消息的转发的,那本文就来分析一下Pub/Sub是如 ...

  7. 手把手教你在 TKE 集群中实现简单的蓝绿发布和灰度发布

    概述 如何在腾讯云 Kubernetes 集群实现蓝绿发布和灰度发布?通常要向集群额外部署其它开源工具来实现,比如 Nginx Ingress,Traefik 等,或者让业务上 Service Mes ...

  8. apache tomcat搭建负载均衡(实现集群中的session同步)

    原理:tomcat 做个WEB服务器有它的局限性,处理能力低,效率低.承受并发小(1000左右).但目前有不少网站或者页面是JSP的.并采用了tomcat做为WEB,因此只能在此基础上调优. 目前采取 ...

  9. docker swarm英文文档学习-8-在集群中部署服务

    Deploy services to a swarm在集群中部署服务 集群服务使用声明式模型,这意味着你需要定义服务的所需状态,并依赖Docker来维护该状态.该状态包括以下信息(但不限于): 应该运 ...

随机推荐

  1. Win10的UWP之进度条

    原文:Win10的UWP之进度条 关于UWP的进度条的处理的方案有两种方案 我们新建一个项目,然后处理的界面如下的代码 <Grid.RowDefinitions> <RowDefin ...

  2. ef 查询总结

    1.Linq 查询两张表:a表和b表,要得到的数据是a表数据b表没有 例如:a表有5条数据1,2,3,4,5:b表有2条数据1,3:那么就用dataGridView1输出2,4,5:link语句要怎么 ...

  3. PRML Chapter3

    曲线拟合的几种方法 最大似然估计MLE,最大后验概率MAP:MLE和MAP MLE 给定一堆数据,假如我们知道它是从某一种分布中随机取出来的,可是我们并不知道这个分布具体的参,即"模型已定, ...

  4. Ptypes一个开源轻量级的c++库,包括对一些I/O操作、网络通信、多线程和异常处理的封装

    C++开源项目入门级:Ptypes    Ptypes一个开源轻量级的c++库,包括对一些I/O操作.网络通信.多线程和异常处理的封装.虽然代码有限,包括的内容不少,麻雀虽小,五脏俱全.    提高: ...

  5. Qt5.5以来对Network的改进(包括对SSL的功能支持,HTTP的重定向等等)

    Qt Network New SSL back-end for iOS and OS X based on Secure Transport. Note that in Qt 5.6 this wil ...

  6. 通过使用URLEncoder与URLDecoder进行编码和解码

    使用改方法必须导入 java.net包 <%@page import="java.net.*" %> 编码: 当要存储或者发送数据的时候使用,将编码后的字符串再发送或者 ...

  7. Delphi产生任务栏图标【TNotifyIconData】

    一.新建一个应用程序:File->New Applicaton 在Interface部分要放在Uses Message之后,定义一个消息常量:const WM_NID=WM_USER+1000; ...

  8. c# 9png实现(图片缩放)

    跟据9png的实现原理自己写了个生成图片的函数,9png的原理是将图片切成9块如下 其中1.3.7.9不进行缩放,2,4,5,6,8进行缩放,这样就防止了放大后导致边界出现锯齿的问题 在实现过程中主要 ...

  9. qt 自动重启(两种方法)

    所谓自动重启就是程序自动关闭后在重新打开: 一般一个qt程序main函数如下: int main(int argc, char* argv[]) { QApplication app(argc, ar ...

  10. git初学【常用命令、上传项目到码云或从码云拉取、克隆项目】

    1.下载git.https://git-scm.com/   注册码云:https://gitee.com/2.安装git:  默认安装即可:  安装完成之后打开git bash进行最后一步配置  输 ...