简体   繁体   English

无法从Akka群集客户端发送协议缓冲区消息

[英]Could not send Protocol Buffer message from Akka Cluster Client

I am trying to use Play Framework (Scala) as Akka Cluster client to send messages to another Akka Cluster running my app services. 我正在尝试将Play Framework(Scala)用作Akka Cluster客户端,以将消息发送到另一个运行我的应用程序服务的Akka Cluster。

Here is what I did: 这是我所做的:

  1. I defined messages in different module using Protocol Buffer and shared between project running Services and Play app (using git submodules) 我使用协议缓冲区在其他模块中定义了消息,并在运行Services和Play应用的项目之间共享消息(使用git子模块)

     syntax = "proto2"; option java_package = "com.myproject.api.common.messages"; option java_outer_classname = "IsValidClientMessage"; message IsValidClient { required int32 clientId = 1; required string clientSecret = 2; } 
  2. Started Services in port 2560 在端口2560中启动服务

     akka { remote.netty.tcp.port=${?AKKA_REMOTE_PORT} remote.netty.tcp.hostname=127.0.0.1 cluster { seed-nodes = [ "akka.tcp://ApiServiceActorSystem@127.0.0.1:2560" ] auto-down-unreachable-after = 10s } extensions = ["akka.cluster.client.ClusterClientReceptionist"] loglevel = DEBUG actor { serializer { proto = "akka.remote.serialization.ProtobufSerializer" } serialization-bindings { "com.myproject.api.common.messages.IsValidClientMessage$IsValidClient" = proto } serialize-messages = on provider = "akka.cluster.ClusterActorRefProvider" debug { receive = on } } } 
  3. And ran Play App using below Akka config: 并使用以下Akka配置运行Play应用:

     akka { remote.netty.tcp.port=2552 remote.netty.tcp.hostname=127.0.0.1 remote.enabled-transports = ["akka.remote.netty.tcp"] cluster { seed-nodes = [ "akka.tcp://Api@127.0.0.1:2552" ] auto-down-unreachable-after = 10s } extensions = ["akka.cluster.client.ClusterClientReceptionist"] loglevel = DEBUG actor { serializer { proto = "akka.remote.serialization.ProtobufSerializer" } serialization-bindings { "com.myproject.api.common.messages.IsValidClientMessage$IsValidClient" = proto } serialize-messages = on provider = "akka.cluster.ClusterActorRefProvider" debug { receive = on } } } 

This is the code I have been trying to send message to ApiServiceSystem : 这是我一直尝试向ApiServiceSystem发送消息的ApiServiceSystem

package com.myproject.api.akka.actors.socket

import ...

class ClientActor extends Actor with ActorLogging {

  ClusterClientReceptionist(context.system).registerService(self)

  val outActors: ArrayBuffer[ActorRef] = ArrayBuffer.empty
  val apiServiceClient = context.system.actorOf(ClusterClient.props(
    ClusterClientSettings(context.system).withInitialContacts(Set(ActorPath.fromString("akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist")))
  ))

  override def receive = {
    case WatchOutActor(a) =>
      context.watch(a)
      outActors += a
    case Terminated(a) =>
      context.unwatch(a)
      outActors.remove(outActors.indexOf(a))
    case other =>

      implicit val to: Timeout = 2 seconds

      val isValidClient = IsValidClient.newBuilder() // Protocol Buffer Message

      isValidClient.setClientId(1000)
      isValidClient.setClientSecret("notsosecret")

      (apiServiceClient ? ClusterClient.Send("/user/clientActor", isValidClient.build(), false)).mapTo[Future[Either[ServiceError, Boolean]]] map { f =>
        f map {
          case Left(e) =>
            outActors foreach { a => a ! e.msg }
          case Right(bool) =>
            outActors foreach { a => a ! bool.toString }
        }
      } recover {
        case e: Exception => println(s"-=> Exception ${e.getMessage}")
      }
  }
}

object ClientActor {

  case class WatchOutActor(actorRef: ActorRef)
}

As I see from below log, that my api has connected to cluster running service: 从下面的日志中可以看到,我的api已连接到集群运行服务:

[DEBUG] [08/11/2016 10:11:05.936] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-24] [akka.remote.Remoting] Associated [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560] <- [akka.tcp://Api@127.0.0.1:2552]
[DEBUG] [08/11/2016 10:11:05.998] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-24] [akka.serialization.Serialization(akka://ApiServiceActorSystem)] Using serializer[akka.cluster.client.protobuf.ClusterClientMessageSerializer] for message [akka.cluster.client.ClusterReceptionist$Internal$GetContacts$]
[DEBUG] [08/11/2016 10:11:06.000] [ApiServiceActorSystem-akka.actor.default-dispatcher-4] [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] Client [akka.tcp://Api@127.0.0.1:2552/user/$a] gets contactPoints [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] (all nodes)
[DEBUG] [08/11/2016 10:11:06.002] [ApiServiceActorSystem-akka.actor.default-dispatcher-4] [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] Client [akka.tcp://Api@127.0.0.1:2552/user/$a] gets contactPoints [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] (all nodes)
[DEBUG] [08/11/2016 10:11:06.002] [ApiServiceActorSystem-akka.actor.default-dispatcher-4] [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] Client [akka.tcp://Api@127.0.0.1:2552/user/$a] gets contactPoints [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] (all nodes)
[DEBUG] [08/11/2016 10:11:06.002] [ApiServiceActorSystem-akka.actor.default-dispatcher-4] [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] Client [akka.tcp://Api@127.0.0.1:2552/user/$a] gets contactPoints [akka.tcp://ApiServiceActorSystem@127.0.0.1:2560/system/receptionist] (all nodes)
[DEBUG] [08/11/2016 10:11:06.004] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-76] [akka.serialization.Serialization(akka://ApiServiceActorSystem)] Using serializer[akka.cluster.client.protobuf.ClusterClientMessageSerializer] for message [akka.cluster.client.ClusterReceptionist$Internal$Contacts]
[DEBUG] [08/11/2016 10:11:06.033] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-76] [akka.serialization.Serialization(akka://ApiServiceActorSystem)] Using serializer[akka.serialization.JavaSerializer] for message [akka.actor.Identify]
[DEBUG] [08/11/2016 10:11:06.037] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-24] [akka.serialization.Serialization(akka://ApiServiceActorSystem)] Using serializer[akka.serialization.JavaSerializer] for message [akka.actor.ActorIdentity]
[DEBUG] [08/11/2016 10:11:06.126] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-76] [akka.serialization.Serialization(akka://ApiServiceActorSystem)] Using serializer[akka.serialization.JavaSerializer] for message [akka.remote.EndpointWriter$AckIdleCheckTimer$]
[DEBUG] [08/11/2016 10:11:07.749] [ApiServiceActorSystem-akka.remote.default-remote-dispatcher-76] [akka.serialization.Serialization(akka://ApiServiceActorSystem)] Using serializer[akka.cluster.client.protobuf.ClusterClientMessageSerializer] for message [akka.cluster.client.ClusterReceptionist$Internal$Heartbeat$]

But whenever I try to send message, I get this error: 但是每当我尝试发送消息时,都会出现此错误:

java.lang.RuntimeException: Unable to find proto buffer class: com.myproject.api.common.messages.IsValidClientMessage$IsValidClient
  at com.google.protobuf.GeneratedMessageLite$SerializedForm.readResolve(GeneratedMessageLite.java:1192)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:497)
  at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1104)
  at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1810)
  at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
  at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
  at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1918)
  at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
  at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
  at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
  at akka.serialization.JavaSerializer$$anonfun$1.apply(Serializer.scala:241)
  at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
  at akka.serialization.JavaSerializer.fromBinary(Serializer.scala:241)
  at akka.serialization.Serialization$$anonfun$deserialize$3.apply(Serialization.scala:142)
  at scala.util.Try$.apply(Try.scala:192)
  at akka.serialization.Serialization.deserialize(Serialization.scala:142)
  at akka.actor.dungeon.Dispatch$class.sendMessage(Dispatch.scala:128)
  at akka.actor.ActorCell.sendMessage(ActorCell.scala:374)
  at akka.actor.Cell$class.sendMessage(ActorCell.scala:295)
  at akka.actor.ActorCell.sendMessage(ActorCell.scala:374)
  at akka.actor.RepointableActorRef.$bang(RepointableActorRef.scala:169)
  at akka.actor.ActorRef.tell(ActorRef.scala:128)
  at akka.pattern.AskableActorRef$.internalAsk$extension(AskSupport.scala:295)
  at akka.pattern.AskableActorRef$.$qmark$extension1(AskSupport.scala:281)
  at com.myproject.api.akka.actors.socket.ClientActor$$anonfun$receive$1.applyOrElse(ClientActor.scala:43)
  at akka.actor.Actor$class.aroundReceive(Actor.scala:480)
  at com.myproject.api.akka.actors.socket.ClientActor.aroundReceive(ClientActor.scala:16)
  at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)
  at akka.actor.ActorCell.invoke(ActorCell.scala:495)
  at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
  at akka.dispatch.Mailbox.run(Mailbox.scala:224)
  at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
  at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
  at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
  at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
  at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: java.lang.ClassNotFoundException: com.myproject.api.common.messages.IsValidClientMessage$IsValidClient
  at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
  at java.lang.Class.forName0(Native Method)
  at java.lang.Class.forName(Class.java:264)
  at com.google.protobuf.GeneratedMessageLite$SerializedForm.readResolve(GeneratedMessageLite.java:1183)
  ... 38 common frames omitted

How can I serialize my message? 如何序列化我的消息? Why is that ClassNotFoundException occurring at run time? 为什么在运行时发生ClassNotFoundException Any help will be much appreciated 任何帮助都感激不尽

It seems there is a class loading issue with akka-remote and protobuf 3.x generated classes (even if you use proto2 definitions). 似乎akka-remote和protobuf 3.x生成的类存在类加载问题(即使您使用proto2定义也是如此)。 Could solve it using the protobuf 2.5 compiler istead of 3.x: https://github.com/google/protobuf/releases/tag/v2.5.0 可以使用protobuf 2.5编译器而不是3.x来解决它: https : //github.com/google/protobuf/releases/tag/v2.5.0

You have to compile it yourselve, because there are no precompiled binaries. 您必须自己编译,因为没有预编译的二进制文件。 Just head to the downloaded directory and run the following commands: 只需转到下载的目录并运行以下命令:

./configure
make
make install

After compiling the v2.5 protoc binary, use it to rebuild your java classes and use them. 编译v2.5 protoc二进制文件后,使用它来重建Java类并使用它们。 Will open an issue to get proto 3 support in akka. 将打开一个问题以在akka中获得proto 3支持。

Clarification: It's not the protobuf-java version, but the classes generated by the protoc binary 3.0 说明:它不是protobuf-java版本,而是protoc二进制3.0生成的类

You need to explicitly bind Lite and V3 classes to your proto serializer: 您需要将Lite和V3类显式绑定到原型串行器:

akka {
  loglevel = "INFO"

  actor {
    provider = "akka.remote.RemoteActorRefProvider"

    serializers {
      proto = "akka.remote.serialization.ProtobufSerializer" # or use your own..
    }

    serialization-bindings {
      "com.google.protobuf.Message" = proto
      "com.google.protobuf.GeneratedMessageLite" = proto
      "com.google.protobuf.GeneratedMessageV3" = proto
    }
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM