AKKA(V2.3.9)Spring Integration :: Cluster Remote由于Spring Class Serialization错误而导致故障转移

时间:2016-08-24 11:00:36

标签: spring akka akka-cluster akka-remoting

我正在设置akka集群(使用akka库版本2.3.9),其中包含一个主actor和多个worker actor。 Master Actor配置了池集群感知路由器。

部署具有4个集群节点的应用程序。最初所有节点都正确加入群集,但几分钟后节点就解除了与群集的关联并形成了自己的群集。

**Getting below warn message logged when enabling remote debug logging -**

**ERROR] []** [ClusterSystem-akka.remote.default-remote-dispatcher-23] [akka.tcp://ClusterSystem
@localhost:2551/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FClusterSystem%40localhost%3A2552-0/en
dpointWriter] AssociationError [akka.tcp://ClusterSystem@localhost:2551] -> [akka.tcp://ClusterSystem@localhost:2552
]: **Error [Failed to write message to the transport] [
akka.remote.EndpointException: Failed to write message to the transport
Caused by: java.lang.IllegalArgumentException: Can't serialize object of type class org.springframework.context.supp
ort.ClassPathXmlApplicationContext**
    at akka.cluster.protobuf.ClusterMessageSerializer.toBinary(ClusterMessageSerializer.scala:74)
    at akka.serialization.Serialization$$anonfun$serialize$1.apply(Serialization.scala:90)
    at akka.serialization.Serialization$$anonfun$serialize$1.apply(Serialization.scala:90)
    at scala.util.Try$.apply(Try.scala:161)
    at akka.serialization.Serialization.serialize(Serialization.scala:90)
    at akka.remote.serialization.DaemonMsgCreateSerializer.serialize(DaemonMsgCreateSerializer.scala:107)
    at akka.remote.serialization.DaemonMsgCreateSerializer$$anonfun$propsProto$1$1.apply(DaemonMsgCreateSerializ
er.scala:56)
    at akka.remote.serialization.DaemonMsgCreateSerializer$$anonfun$propsProto$1$1.apply(DaemonMsgCreateSerializ
er.scala:56)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
    at scala.collection.AbstractTraversable.map(Traversable.scala:105)
    at akka.remote.serialization.DaemonMsgCreateSerializer.propsProto$1(DaemonMsgCreateSerializer.scala:56)
    at akka.remote.serialization.DaemonMsgCreateSerializer.toBinary(DaemonMsgCreateSerializer.scala:62)
    at akka.remote.MessageSerializer$.serialize(MessageSerializer.scala:36)
    at akka.remote.EndpointWriter$$anonfun$serializeMessage$1.apply(Endpoint.scala:842)
    at akka.remote.EndpointWriter$$anonfun$serializeMessage$1.apply(Endpoint.scala:842)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
    at akka.remote.EndpointWriter.serializeMessage(Endpoint.scala:841)
    at akka.remote.EndpointWriter.writeSend(Endpoint.scala:742)
    at akka.remote.EndpointWriter$$anonfun$2.applyOrElse(Endpoint.scala:717)
    at akka.actor.Actor$class.aroundReceive(Actor.scala:465)
    at akka.remote.EndpointActor.aroundReceive(Endpoint.scala:410)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)
    at akka.actor.ActorCell.invoke(ActorCell.scala:487)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:254)
    at akka.dispatch.Mailbox.run(Mailbox.scala:221)
    at akka.dispatch.Mailbox.exec(Mailbox.scala:231)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.pollAndExecAll(ForkJoinPool.java:1253)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

1 个答案:

答案 0 :(得分:1)

我在java-spring-akka应用程序中遇到了同样的问题。我使用IndirectActorProducer将actor实例化为bean(带范围原型)。这个生成器包含Spring ApplicationContext。这种方式适用于群集分片。但是集群环境中的简单池路由器(在我的情况下是循环池)尝试通过集群发送带有IndirectActorProducer(和ApplicationContext)的Props。 我可以建议一些hack的解决方法,它适用于我:创建自定义序列化程序并将其定义为“ConfigurableApplicationContext”类。请参阅以下示例:

public class SpringContextSerializer extends JSerializer {
private static ConfigurableApplicationContext configurableApplicationContext;

public static void init(ConfigurableApplicationContext configurableApplicationContext) {
    SpringContextSerializer.configurableApplicationContext = configurableApplicationContext;
}

public SpringContextSerializer() {
    if (configurableApplicationContext == null) {
        throw new RuntimeException("Serializer mist be initialized before creating.");
    }
}

@Override
public int identifier() {
    return getClass().toString().hashCode();
}

@Override
public byte[] toBinary(Object o) {
    return new byte[0];
}

@Override
public boolean includeManifest() {
    return false;
}

@Override
public Object fromBinaryJava(byte[] bytes, Class<?> manifest) {
    return configurableApplicationContext;
}
}

配置:

akka.actor {
serializers {
  context = "ru.ddg.elleps.hubcache.integration.SpringContextSerializer"
}

serialization-bindings {
  "org.springframework.context.annotation.AnnotationConfigApplicationContext" = context
}
}

此外,您必须在启动ActorSystem的情况下使用容器初始化序列化程序。