收到响应后,Netty ChannelFuture超时

时间:2019-04-04 12:58:15

标签: java spring netty future

我是netty的新手,我有一个用netty开发的tcp客户端应用程序。当我使用future从服务器获取异步响应时,一些响应会返回,但是future尚未完成。 TCPClient类如下;

public TcpClient {
    public boolean connect(Host host) {
        try {
            Bootstrap clientBootstrap = new Bootstrap()
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE,true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 50)
                    .remoteAddress(new InetSocketAddress(host.getIp(), host.getPort()))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) {
                            socketChannel.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(2146));
                            FalconClientHandler falconClientHandler = new FalconClientHandler(host);
                            host.setFalconClientHandler(falconClientHandler);
                            socketChannel.pipeline().addLast(falconClientHandler);
                        }
                    });

            channelFuture = clientBootstrap.connect().sync(); //BAŞARI İLE BAĞLANDI

            channelFuture.channel().closeFuture().sync();

            return host.isActive();
        } catch (Exception e) {
            log.info("Connection timed out --> " + e);
            host.setActive(false);
            return false;
        } finally {
            host.setActive(false);
        }
    }

public synchronized ResponseFuture send(long transactionId,String message) {
    final Map<Long,ResponseFuture> responseFuture = new ConcurrentHashMap<>();
    responseFuture.put(transactionId,new ResponseFuture());
    if (!hostSelector.getUpHostList().isEmpty()) {
        int hostCount = hostSelector.getUpHostList().size();
        Host host;

        host = hostSelector.getUpHostList().get(index.incrementAndGet() % hostCount);
        if (host.isActive()) {
            int headerLength = Integer.parseInt(message.substring(8, 12));
            log.info("[{}] Host {} Tcp Request",message.substring(52, 52 + headerLength),host.getIp());
            channelFuture.addListener((GenericFutureListener<ChannelFuture>) future -> {
                log.info("[{}] Tcp request added to map",transactionId);
                channelFuture.channel().pipeline().get(FalconClientHandler.class).setResponseFuture(responseFuture);
                byte[] byteBuffer = message.getBytes();
                channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer(byteBuffer));
            });
        }
    } else {
        log.error("AYAKTA HOST YOK");
    }
    return responseFuture.get(transactionId);
}

}

发送方法具有transactionId和请求消息,当我发送带有事务ID的消息时,响应将返回此事务ID。我称这个发送如下:

    ResponseFuture responseFuture = falconClient.send(Long.valueOf(transactionId), finalMessage);
    try {
        Object obj = responseFuture.get(ddaTimeoutParam, TimeUnit.MILLISECONDS);
        if(obj!=null) {
            response = obj.toString();
            ddaDelta = System.currentTimeMillis()-ddaRequestStartTime;
        }
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        log.warn("[{}] DDA timeout. Timeout parameter: {}",transactionId,ddaTimeoutParam);
        responseFuture.cancel(true);
        response = "TIMEOUT";
        ddaDelta = System.currentTimeMillis()-ddaRequestStartTime;
    } 

响应将来是基本的将来实现类。放置和获取类似的方法;

public class ResponseFuture implements Future<String> {

    private volatile State state = State.WAITING;
    ArrayBlockingQueue<String> blockingResponse = new ArrayBlockingQueue<String>(1);

    private enum State {
        WAITING,
        DONE
    }

    @Override
    public String get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        final String responseAfterWait = blockingResponse.poll(timeout, unit);
        if (responseAfterWait == null) {
            throw new TimeoutException();
        }
        return responseAfterWait;
    }

    public void set(String msg) {
        if (state == State.DONE) {
            return;
        }

        try {
            blockingResponse.put(msg);
            state = State.DONE;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


    My Handler class for receive server response message like following;


public class FalconClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    private ChannelHandlerContext ctx;

    private Map<Long,ResponseFuture> responseFuture;

    public synchronized void setResponseFuture(Map<Long,ResponseFuture> responseFuture) {
        log.info("{} ResponseFuture setted",responseFuture.keySet());
        this.responseFuture = responseFuture;
    }

    @Override
    public void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf in) {
        String input = in.toString(CharsetUtil.UTF_8);
        String transactionKey = input.substring(52, 66).trim();
        if(responseFuture.get(Long.valueOf(transactionKey))!=null)
            responseFuture.get(Long.valueOf(transactionKey)).set(input);
        else
            log.info("[{}] Tcp Response map is empty",transactionKey);
        }
}

当我在每秒30笔事务的高负载下运行此代码时,tcp响应从netty服务器返回,但将来的get方法收到超时。这种情况不会发生在30 tps%50请求失败时每个请求(例如%20请求)都失败40 tps。在负载下会发生什么?

0 个答案:

没有答案
相关问题