Akka-路由模式Group/Pool

2024-08-28 19:04
文章标签 模式 路由 group pool akka

本文主要是介绍Akka-路由模式Group/Pool,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为了文章好理解,我们先统一一下概念,在Akka中,Actor是一个高度抽象的概念,Akka的路由器也是一个Actor,所以我们把路由器,叫做路由Actor,接收消息(消费消息)的Actor,在本文中我们叫做消息Actor

Akka中有两种路由模式,分别是Group模式和Pool模式,如果我要将消息X通过路由Actor发送到多台机器,那么:
Pool: 在多台机器上,每台机器上的消息Actor都是由路由Actor创建的,也就是说,处理消息的这些Actor,是路由Actor的儿子,每台机器上的Actor可以通过parent()方法来测试,注意,路由Actor消息Actor可不一定在同一台机器上
Group: 多台机器上,每台机器上的消息Actor,都是我们程序员自己写代码创建好的,是通过actorOf创建的,路由Actor将消息X通过路径发送给这些处理消息的Actor

创建Akka项目

也可以参考本系列文章的环境搭建或者关于Akka的路由策略,可以参考这里,如果你已经搭建了akka环境,那么可跳过本段落,直接浏览下文的示例1
步骤1: Maven依赖

<dependency><groupId>com.typesafe.akka</groupId><artifactId>akka-actor_2.11</artifactId><version>2.4.20</version></dependency><dependency><groupId>com.typesafe.akka</groupId><artifactId>akka-remote_2.11</artifactId><version>2.4.20</version></dependency>

步骤2: 创建一个Actor

package akka.demo.actor;import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.routing.FromConfig;public class MyActor extends UntypedActor {@Overridepublic void onReceive(Object o) throws Throwable {// getSelf()方法表示了我是谁// getSender()方法表示了谁发的消息System.out.println(getSelf() + "收到了来自:" + getSender().path() + "消息内容:" + o);}
}

步骤3: 在Resource文件夹下创建一个叫做application.conf的文件,至于文件的内容,下面示例中再给出

示例1:Pool模式

下面的代码演示了名字为"abc"的路由Actor创建了3个子Actor,然后通过广播的策略方式,给3个子Actor发送消息,子Actor接收到消息之后,打印消息内容

步骤1: 首先在配置文件application.conf中写如下内容

akka{actor{provider="akka.remote.RemoteActorRefProvider"deployment{# 定义一个叫做abc的路由Actor,它包含一个池,池子里有3个子Actor(也就是上文中的消息Actor)/abc{# 这个路由Actor使用的路由策略是broadcast-pool广播router = broadcast-pool# abc中包含3个处理消息的Actornr-of-instances = 3}}}# 自己的IP端口remote{enabled-transports=["akka.remote.netty.tcp"]netty.tcp{hostname="127.0.0.1"port=2551}}
}

步骤2: 写个main方法

public static void main(String[] args) throws Throwable {ActorSystem system = ActorSystem.create("sys");ActorRef routeActorRef = system.actorOf(FromConfig.getInstance().props(Props.create(MyActor.class)), "abc");System.out.println(routeActorRef.path());for (int i = 0; i < 20; i++) {Thread.sleep(3000);routeActorRef.tell("内容" + i, ActorRef.noSender());}}

步骤3: 运行main方法,打印内容如下

// 循环,第1次打印3条数据,说明广播策略生效,3个子actor都接到了消息
Actor[akka://sys/user/abc/$c#-119781784]收到了来自:akka://sys/deadLetters消息内容:内容0
Actor[akka://sys/user/abc/$b#2011987574]收到了来自:akka://sys/deadLetters消息内容:内容0
Actor[akka://sys/user/abc/$a#-755258569]收到了来自:akka://sys/deadLetters消息内容:内容0
// 循环,第2次打印3条数据,说明广播策略生效,3个子actor再次都接到了消息
Actor[akka://sys/user/abc/$a#-755258569]收到了来自:akka://sys/deadLetters消息内容:内容1
Actor[akka://sys/user/abc/$b#2011987574]收到了来自:akka://sys/deadLetters消息内容:内容1
Actor[akka://sys/user/abc/$c#-119781784]收到了来自:akka://sys/deadLetters消息内容:内容1

到这里pool模式演示完毕,需要注意的时候,由于我是一台机器,而且只开了一个服务,所以这3个子Actor都是在同一台机器上的同一个JVM下,实际的集群情况,这3个子Actor会分配到不同的机器上,不过这是后话了,后续文章会有专门的集群配置

示例1:Group模式

group示例需要开3个服务,并且每个服务的conf文件内容都不一样,如果没理解什么意思,你可以参考关于Akka的路由策略这篇文章起3个服务

下面的示例通过服务1,通过广播的路由策略,给服务2和服务3发送消息
步骤1:
服务1的配置文件application.conf中写如下内容

akka{actor{provider="akka.remote.RemoteActorRefProvider"deployment{/abc{# 使用广播的路由策略,注意,这个地方是-group,上一个例子是-poolrouter = broadcast-group# 下面的代码我们要通过服务1的路由Actor(名字叫abc),给服务2的消息Actor(名字叫actor02)和# 服务3的消息Actor(名字叫actor3)发消息# 后文的main方法中会创建actor02和actor03,而上文的Pool示例中是Akka自动创建的消息Actor# 并且自动创建的消息Actor的名字是随机的,从上文示例中可以看到名字类似"$a#-755258569"# 一个手动创建,一个自动创建,这也是group和pool的明显区别之一routees.paths = ["akka.tcp://sys@127.0.0.1:2552/user/actor02","akka.tcp://sys@127.0.0.1:2553/user/actor03"]}}}# 自己的IP端口remote{enabled-transports=["akka.remote.netty.tcp"]netty.tcp{hostname="127.0.0.1"port=2551}}
}

服务2的配置文件application.conf中写如下内容

akka{actor{provider="akka.remote.RemoteActorRefProvider"}remote{enabled-transports=["akka.remote.netty.tcp"]netty.tcp{hostname="127.0.0.1"port=2552}}
}

服务3的配置文件application.conf中写如下内容

akka{actor{provider="akka.remote.RemoteActorRefProvider"}remote{enabled-transports=["akka.remote.netty.tcp"]netty.tcp{hostname="127.0.0.1"port=2553}}
}

步骤2: 创建main方法
服务1的main方法

public static void main(String[] args) throws Throwable {ActorSystem system = ActorSystem.create("sys");// FromConfig.getInstance().props()// 通过配置文件,创建一个叫做abc的路由ActorActorRef routeActorRef = system.actorOf(FromConfig.getInstance().props(Props.create(MyActor.class)), "abc");System.out.println(routeActorRef.path());for (int i = 0; i < 20; i++) {Thread.sleep(3000);// 由于配置文件中定义了abc要给名字为actor02和actor03的消息Actor发消息,所以// 下面这行代码会根据IP端口号,然后给它俩发消息,前提是必须通过IP和端口号能找到// 这俩Actor才行routeActorRef.tell("内容" + i, ActorRef.noSender());}}

服务2的main方法

public static void main(String[] args) throws Throwable {ActorSystem system = ActorSystem.create("sys");// 为了能让服务1(abc)找到actor02,所以我们创建一个叫做actor02的消息ActorActorRef actorReference = system.actorOf(Props.create(MyActor.class), "actor02");System.out.println(actorReference.path());System.out.println("sys系统创建完毕");
}

服务3的main方法

public static void main(String[] args) throws Throwable {ActorSystem system = ActorSystem.create("sys");// 为了能让服务1(abc)找到actor03,所以我们创建一个叫做actor03的消息ActorActorRef actorReference = system.actorOf(Props.create(MyActor.class), "actor03");System.out.println(actorReference.path());System.out.println("sys系统创建完毕");
}

步骤3: 先启动服务2和服务3,最后启动服务1,会发现服务2和服务3控制台打印如下

消息来自:akka.tcp://sys@127.0.0.1:2551/deadLetters消息内容:内容0

本文演示完毕,已经从技术角度说明了group模式和pool模式的区别,主要就是Actor的生命周期归谁管的问题,是程序员硬编码控制,还是通过路由Actor自己控制,关于生命周期的话题,后续文章会有

有一说一,具体的使用场景我还没有想出来,因为根据现有的结果来看,似乎任何情况都可以使用group的方式,而不用pool的方式,因为我也是调研akka,所以没有真正意义上的实战,也是摸着石头过河,目前我能想到的应该是需要动态拓容的场景,或许能需要pool模式????

下一篇文章:Akka的集群搭建(还没开始写 TODO)

这篇关于Akka-路由模式Group/Pool的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115625

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

matlab读取NC文件(含group)

matlab读取NC文件(含group): NC文件数据结构: 代码: % 打开 NetCDF 文件filename = 'your_file.nc'; % 替换为你的文件名% 使用 netcdf.open 函数打开文件ncid = netcdf.open(filename, 'NC_NOWRITE');% 查看文件中的组% 假设我们想读取名为 "group1" 的组groupName

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易