【问题标题】:Spring integration: Container application hangs for a few seconds during connection stepSpring集成:容器应用程序在连接步骤期间挂起几秒钟
【发布时间】:2022-06-22 01:32:14
【问题描述】:

简而言之,我有一个使用 spring 实现的套接字应用程序,我分享以下代码:

@SpringBootApplication
public class ExampleApp {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApp.class, args);
    }

    @Bean
    public AbstractServerConnectionFactory serverConnectionFactory() {
        TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(1234);
        return tcpNetServerConnectionFactory;
    }

    @Bean
    public MessageChannel requestChannel() {
        return new DirectChannel();
    }

    @Bean
    public MessageChannel replyChannel() {
        return new DirectChannel();
    }

    @Bean
    public TcpReceivingChannelAdapter receivingChannelAdapter(AbstractServerConnectionFactory serverConnectionFactory, MessageChannel requestChannel) {
        TcpReceivingChannelAdapter tcpReceivingChannelAdapter = new TcpReceivingChannelAdapter();
        tcpReceivingChannelAdapter.setConnectionFactory(serverConnectionFactory);
        tcpReceivingChannelAdapter.setOutputChannel(requestChannel);
        return tcpReceivingChannelAdapter;
    }

    @Bean
    @ServiceActivator(inputChannel = \"replyChannel\")
    public TcpSendingMessageHandler tcpSendingMessageHandler(AbstractServerConnectionFactory serverConnectionFactory) {
        TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
        tcpSendingMessageHandler.setConnectionFactory(serverConnectionFactory);
        return tcpSendingMessageHandler;
    }

    @ServiceActivator(inputChannel = \"requestChannel\", outputChannel = \"replyChannel\")
    public Message<String> processMessage(Message<String> message) {
        Message<String> reply = MessageBuilder
                .withPayload(\"OK\")
                .setHeader(IpHeaders.CONNECTION_ID, message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class))
                .build();
        return reply;
    }

    @Bean
    public ApplicationListener<TcpConnectionEvent> listener(MessageChannel replyChannel) {
        return tcpConnectionEvent -> {
            if (tcpConnectionEvent instanceof TcpConnectionOpenEvent) {
                Message<String> message = MessageBuilder
                        .withPayload(\"Hello client\")
                        .setHeader(IpHeaders.CONNECTION_ID, tcpConnectionEvent.getConnectionId())
                        .build();
                replyChannel.send(message);
            }
        };
    }
}

当我在本地运行这个应用程序时,一切都很好:

我只是使用 telnet(用于手动连接)并在那里连接,连接后几乎立即看到我的服务器问候语,并且我能够通过命令 -> 响应与服务器通信。

当我在 docker 容器中运行我的应用程序时 - 它有一些麻烦。基本上,它会立即将我连接到服务器,但我会看到延迟 6 秒的问候消息。它也不会回复我的命令,只是在此期间忽略它们。当它打印问候语时 - 它也会显示我的请求的响应。之后,我可以毫无问题地与服务器合作。

有没有人遇到过同样的问题?

UPD:仅作记录,该应用程序没有使用任何数据库,因此非常轻量级

UPD1:也许,问题出在我的 docker compose 文件中,看起来很简单:

  app:
    image: me/app:v1
    container_name: app
    build:
      context: *ToAppRootDir*
      dockerfile: *pathToDockerFile*
    restart: always
    environment:
      - SERVER_PORT: 8080
      - SOCKET_PORT: 8081
    ports:
      - \"8080:8080\"
      - \"8081:8081\"

UPD2:最长的延迟是在首次连接期间,通常需要6秒。下一个连接也会有延迟,但最多需要 2 秒。

UPD3:而且,这个问题存在于容器内部通信中。我仅使用此应用程序进行了简单的 springBoot 集成测试-当我尝试连接并从套接字读取时-我正在接收 ReadTimeoutConnection

  • 有机会从你那里看到一个简单的项目来玩吗?
  • @ArtemBilan 我将在接下来的 20 分钟内为它创建一份报告
  • @ArtemBilan 这里是一个 github 存储库 - github.com/Dexx322/sockets.demo
  • 我必须在我的环境中等待 20 秒才能从 Docker 中的容器中获取 Hello client ......看起来 Docker 中存在一些网络延迟,同时它试图解决它与客户端建立的套接字的问题。
  • @ArtemBilan 这很奇怪。容器内部通信也存在这个问题,我已经更新了帖子

标签: spring-boot docker-compose spring-integration telnet


【解决方案1】:

这为我解决了问题:

@Bean
public AbstractServerConnectionFactory serverConnectionFactory() {
    TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(port);
    tcpNetServerConnectionFactory.setLookupHost(false);
    return tcpNetServerConnectionFactory;
}

请参阅我禁用的选项:

/**
 * If true, DNS reverse lookup is done on the remote ip address.
 * Default true.
 * @param lookupHost the lookupHost to set
 */
public void setLookupHost(boolean lookupHost) {

这个到底是这样使用的:

    InetAddress inetAddress = socket.getInetAddress();
    if (inetAddress != null) {
        this.hostAddress = inetAddress.getHostAddress();
        if (lookupHost) {
            this.hostName = inetAddress.getHostName();
        }
        else {
            this.hostName = this.hostAddress;
        }
    }

所以,显然inetAddress.getHostName() 在 Docker DNS 中解析确实需要一些时间。

【讨论】:

  • 我的言语无法表达我的感激之情……
猜你喜欢
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
相关资源
最近更新 更多