当被调用方成员发生序列化异常时,Hazelcast调用方成员将引发超时异常

时间:2018-09-25 13:39:29

标签: java hazelcast unparseable

在具有 2个成员的情况下,我正在使用 Hazelcast (JAVA,版本3.7.5)。第一个成员通过IExecutorService将任务委托给第二个成员。经过一些处理后,第二个成员尝试发送回无法序列化的回复

由于不可能发送回响应,因此第二个成员打印与HazelcastSerializationException相关的堆栈跟踪。

由于没有响应,第一个成员在达到 operation-heartbeat-timeout 时抛出OperationTimeoutException

当前,当IExecutorService解析Callable结果失败时,它将打印一个堆栈跟踪(在被调用方)。 假设我有一个简单的呼叫者:

private Future<Object> startFlow() {
    //This throws an OperationTimeoutException
    return hazelcastInstance.getExecutorService("myExecutor").submit(myRunnable);
}

哪个叫一个简单的被叫者:

@Override
public Object call() throws Exception {
    //The object returned is not serializable, therefore an HazelcastSerializationException is thrown
    return service.execute();
}

被调用方在解析响应失败后将打印一个堆栈跟踪记录(请参阅发布结尾)。

在我的情况下,无法知道service可能返回哪种对象,也无法信任service来发回可序列化的对象。

我希望能够在呼叫方知道超时的原因。

经过一些搜索,我发现当IExecutorService无法序列化响应时,没有配置/ API可用于拦截IExecutorService引发的异常。

因此,我试图查看是否可以通过Hazelcast来检查对象是否可解析,再次失败。

有什么想法吗?

谢谢


被调用方打印的堆栈跟踪将如下所示:

Exception in thread "hz._hzInstance_1_dev.cached.thread-1" com.hazelcast.nio.serialization.HazelcastSerializationException: Failed to serialize 'com.hazelcast.spi.impl.operationservice.impl.responses.NormalResponse'
    at com.hazelcast.internal.serialization.impl.SerializationUtil.handleSerializeException(SerializationUtil.java:73)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toBytes(AbstractSerializationService.java:143)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toBytes(AbstractSerializationService.java:124)
    at com.hazelcast.spi.impl.operationservice.impl.OperationServiceImpl.send(OperationServiceImpl.java:427)
    at com.hazelcast.spi.impl.operationservice.impl.RemoteInvocationResponseHandler.sendResponse(RemoteInvocationResponseHandler.java:51)
    at com.hazelcast.spi.Operation.sendResponse(Operation.java:291)
    at com.hazelcast.executor.impl.DistributedExecutorService$CallableProcessor.sendResponse(DistributedExecutorService.java:269)
    at com.hazelcast.executor.impl.DistributedExecutorService$CallableProcessor.run(DistributedExecutorService.java:253)
    at com.hazelcast.util.executor.CachedExecutorServiceDelegate$Worker.run(CachedExecutorServiceDelegate.java:212)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at com.hazelcast.util.executor.HazelcastManagedThread.executeRun(HazelcastManagedThread.java:76)
    at com.hazelcast.util.executor.HazelcastManagedThread.run(HazelcastManagedThread.java:92)
Caused by: com.hazelcast.nio.serialization.HazelcastSerializationException: Failed to serialize 'com.myomain.UnserialiableObject'
    at com.hazelcast.internal.serialization.impl.SerializationUtil.handleSerializeException(SerializationUtil.java:73)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.writeObject(AbstractSerializationService.java:236)
    at com.hazelcast.internal.serialization.impl.ByteArrayObjectDataOutput.writeObject(ByteArrayObjectDataOutput.java:371)
    at com.hazelcast.spi.impl.operationservice.impl.responses.NormalResponse.writeData(NormalResponse.java:91)
    at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.write(DataSerializableSerializer.java:189)
    at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.write(DataSerializableSerializer.java:54)
    at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.write(StreamSerializerAdapter.java:43)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toBytes(AbstractSerializationService.java:140)
    ... 12 more
Caused by: com.hazelcast.nio.serialization.HazelcastSerializationException: There is no suitable serializer for class com.myomain.UnserialiableObject
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.serializerFor(AbstractSerializationService.java:469)
    at com.hazelcast.internal.serialization.impl.AbstractSerializationService.writeObject(AbstractSerializationService.java:232)
    ... 18 more

编辑(解决方案)

所以我最终注册了一个全局序列化器,该序列化器将在每次调用时仅发送一个异常。像这样:

public class GlobalSerializerException  implements StreamSerializer<Object> {

    @Override
    public void write(ObjectDataOutput out, Object object) throws IOException {
        String objectInfo;
        if(object == null){
            objectInfo = "Object was null.";
        }else{
            objectInfo = String.format("Object of class %s and printed as String gives %s", object.getClass().getCanonicalName(), object.toString());
        }
        objectInfo = "Hazelcast was unable to serialize an object. " + objectInfo;
        out.writeUTF(objectInfo);
    }

    @Override
    public Object read(ObjectDataInput in) throws IOException {
        String message = in.readUTF();
        HazelcastSerializationException hazelcastSerializationException = new HazelcastSerializationException(message);
        return hazelcastSerializationException;
    }

    @Override
    public int getTypeId() {
        return 63426;
    }

    @Override
    public void destroy() {

    }
} 

1 个答案:

答案 0 :(得分:1)

呼叫者由于超时而失败,因为它没有收到目标的响应。目标节点未能序列化响应,原因是发送响应失败。这是当前行为,但我认为也可以发送特殊异常来表示响应失败。

默认情况下,Hazelcast能够对实现java.io.Serializablejava.io.Externalizable和某些Hazelcast特定接口(例如DataSerializablePortable)的类进行序列化。也可以定义自定义序列化程序或委托给另一个序列化库。有关更多信息,请参见Hazelcast Reference Manual - Serialization部分。

在分布式系统中,节点之间交换的消息必须可序列化为二进制形式才能通过网络传输。因此,参与分布式系统的实体/服务必须确保其消息可以某种形式可序列化。

如果您不知道消息的类型,则可以向Hazelcast注册global serializer,该方法首先尝试使用已知格式(SerializableExternalizable等进行序列化),如果类型未知,则会写一条自定义错误消息。 或者,您可以使用自定义的可序列化包装器对象包装服务执行的结果。序列化期间,如果原始包装的结果未能序列化,则您将再次编写自定义错误消息。

例如;

class NonSerializableResponseException extends Exception {}

class ServiceResponseWrapper implements DataSerializable {

    private Object response;

    @Override
    public void writeData(ObjectDataOutput out) throws IOException {
        try {
            out.writeObject(response);
        } catch (HazelcastSerializationException e) {
            out.writeObject(new NonSerializableResponseException());
        }
    }

    @Override
    public void readData(ObjectDataInput in) throws IOException {
        response = in.readObject();
    }
}