使用 Java 的 Akka 远程路由

Posted

技术标签:

【中文标题】使用 Java 的 Akka 远程路由【英文标题】:Akka Remote Routing using Java 【发布时间】:2014-02-28 08:40:49 【问题描述】:

我正在尝试实现一个基本的广播路由器,其中路由位于远程机器上。

代码如下:

localApp.conf

akka 

    log-dead-letters = 10
    log-dead-letters-during-shutdown = off

    actor 
        provider = "akka.remote.RemoteActorRefProvider"
        serialize-messages = on

        serializers 
            java = "akka.serialization.JavaSerializer"
        

        serialization-bindings 
            "java.lang.String" = java
            "test.akkaLocal.LocalWrapper" = java
        

        deployment 
            /LocalMaster/broadcastRouter 
                router = "broadcast"
                nr-of-instances = 1
                target 
                    nodes = ["akka.tcp://RemoteApp@127.0.0.1:10175"]
                
            
        
    
    remote 
        enabled-transports = ["akka.remote.netty.tcp"]
        netty 
            tcp 
                hostname = "127.0.0.1"
                port = 10174
            
        
    

LocalApp.java

public class LocalApp

    public static void main(String[] args)
    
        LocalApp app = new LocalApp();
        app.executeLocal();
    

    private void executeLocal() 
        ActorSystem system = ActorSystem.create("LocalApp", ConfigFactory.load("localApp"));
        final ActorRef master = system.actorOf(Props.create(LocalMaster.class), "LocalMaster");
        master.tell(new LocalWrapper.Execute(), ActorRef.noSender());
    

    public static class LocalMaster extends UntypedActor 

        @Override
        public void onReceive(Object message) throws Exception 
            if (message instanceof LocalWrapper.Execute) 

                ActorSelection remoteActor =
                        getContext().actorSelection("akka.tcp://RemoteApp@127.0.0.1:10175/user/RemoteMaster");

                ActorRef remoteRouter = getContext().actorOf(
                        Props.create(RemoteActor.class).withRouter(new FromConfig()), "broadcastRouter");

                String msg = "Hello";
                // remoteActor.tell(msg, getSelf());
                remoteRouter.tell(msg, getSelf());
             else if (message instanceof String) 
                String response = (String) message;
                System.out.println(response);
            
        

    

    public static class RemoteActor extends UntypedActor 
        @Override
        public void onReceive(Object message) throws Exception 
            if (message instanceof String) 
                String msg = (String) message;
                System.out.println(msg);

                String resp = "World";
                getSender().tell(resp, getSelf());

            
        
    

在remoteApp.conf中,端口为10175

RemoteApp.java

public class RemoteApp

    public static void main(String[] args)
    
        RemoteApp app = new RemoteApp();
        app.executeRemote();
    

    private void executeRemote() 
        ActorSystem system = ActorSystem.create("RemoteApp", ConfigFactory.load("remoteApp"));
        system.actorOf(Props.create(RemoteMaster.class), "RemoteMaster");
    

    public static class RemoteMaster extends UntypedActor 

        @Override
        public void onReceive(Object message) throws Exception 
            if (message instanceof String) 
                String msg = (String) message;
                System.out.println(msg);
                String response = "World";
                getSender().tell(response, getSelf());
            
        
    


现在我无法理解远程路由的概念。它是在远程机器上部署本地actor然后向它们发送消息,还是连接到远程机器上的远程actor然后向它们发送消息?

使用我的代码,我可以向远程机器发送简单的消息(使用演员选择) LocalApp 中的 remoteActor.tell(msg, getSelf()) (注释代码)发送和接收消息并且没有给出任何错误。

但是当我使用本地 Actor 创建路由器时,出现死信错误。

[INFO] [02/04/2014 16:34:58.408] [RemoteApp-akka.actor.default-dispatcher-4] [akka://RemoteApp/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0/endpointWriter/endpointReader-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0] 
Message [akka.remote.transport.AssociationHandle$InboundPayload] from Actor[akka://RemoteApp/deadLetters] to Actor[akka://RemoteApp/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0/endpointWriter/endpointReader-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0#-288427524] was not delivered.
[1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

谁能告诉我我做错了什么?

---------更新----------

我发现了问题。远程和本地类在不同的项目中。在本地和远程项目之间的基本通信过程中,String 是传输对象的类型,这就是它成功的原因。有没有办法在两个不同的项目之间传输自定义类的对象?我尝试实现 Serializable 并将其添加到 conf 文件中,但它没有任何区别

【问题讨论】:

默认情况下,akka 会为自定义消息类使用 java 序列化。如果类定义在系统两侧(发送端和接收端)都可用(即在类路径中),那么您应该能够将其用于远程通信。 Akka 还允许您为不同的消息类类型使用不同的序列化器,因此您不会被 java 序列化所困,但如果您愿意,我建议先让它以这种方式工作,然后再尝试其他序列化器。 感谢您的回复。有效。我必须在两个项目中使用相同的包创建相同的类。把它写成答案,这样我就可以接受了。 作为答案添加... 【参考方案1】:

默认情况下,akka 将为自定义消息类使用 java 序列化。如果类定义在系统两侧(发送端和接收端)都可用(即在类路径中),那么您应该能够将其用于远程通信。我的建议是有一个 jar 文件来表示系统两侧的类路径中可用的消息类。

Akka 还允许您为不同的消息类类型使用不同的序列化程序,因此您不会被 java 序列化所困,但如果您愿意,我建议先让它以这种方式工作,然后再尝试其他序列化程序。

【讨论】:

以上是关于使用 Java 的 Akka 远程路由的主要内容,如果未能解决你的问题,请参考以下文章

使用 formFields 导致 UnsupportedRequestContentTypeRejection 的 Akka Http 路由测试

TL-WAR1200L如何设置远程管理路由器

Akka:跨参与者实例共享状态

Akka 集群单例Cluster Singleton

小米路由器远程登录WEB页面

Windows Server 2016 路由和远程访问