Как установить TCP, чтобы сохранить Alive в Java от httpclient - PullRequest
0 голосов
/ 19 ноября 2018

Мое java-приложение, которое находится в частной подсети AWS, подключается к http-серверу через шлюз AWS Nat. Я вызываю запрос POST через httpclient к серверу HTTP. Этот запрос займет более 10 минут. Я настроил время ожидания сокета и время соединения 1 час, так как это фоновая задача. Но промежуточный шлюз AWS NAT отправит обратно пакет RST через 300 секунд [5 минут] и приведет к сбросу соединения, поэтому я не могу увеличить время ожидания шлюза NAT. Поэтому мне нужно решить проблему со стороны приложения.

Моя стратегия - использовать время поддержки tcp, которое будет отправлять пакет, скажем, каждые 240 секунд, чтобы поддерживать соединение активным. Я настроил это как показано ниже

CloseableHttpClient httpClient = HttpClients.createDefault()
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 3600000); //connection Timeout
HttpConnectionParams.setSoTimeout(params, 3600000); // Socket Time out
HttpConnectionParams.setSoKeepalive(params, true); //Enable Socket level keep alive time

, а затем вызвать почтовый запрос с помощью метода execute

HttpPost post = new HttpPost("http://url");
HttpResponse response = httpClient.execute(post);

Поскольку я использую систему Linux, я настроил сервер со следующими значениями Sysctl

sysctl -w net.ipv4.tcp_keepalive_time=240 
sysctl -w net.ipv4.tcp_keepalive_intvl=240
sysctl -w net.ipv4.tcp_keepalive_probes=10

Но во время выполнения программы поддержка активности не активируется, и соединение завершается неудачно, как и раньше.

Я проверил это с помощью опции netstat -o и, как показано ниже, keep alive выключен

tcp        0      0 192.168.1.141:43770     public_ip:80          ESTABLISHED 18134/java           off (0.00/0/0)

Есть ли какой-нибудь способ, которым я могу установить поддержку TCP по Java-коду, используя httpclient. Также я вижу, что HttpConnectionParams устарели. Но я не смог найти ни одного нового класса, который мог бы поддерживать жизнь

Спасибо

Ответы [ 3 ]

0 голосов
/ 20 ноября 2018

Сохранение HTTP-соединения открытым, но неактивным в течение длительного периода - плохой выбор дизайна.HTTP - это протокол запроса-ответа, подразумевающий, что запросы и ответы быстрые.

При открытом соединении хранятся ресурсы.С точки зрения сервера (и сетевых брандмауэров и маршрутизаторов) клиент, который открывает соединение и начинает запрос (POST в вашем случае), но не отправляет байты в течение длительного периода, неотличим от клиента, который будет никогда не отправляйте больше данных, потому что они неисправны или злонамеренны (проводят DOS-атаку).Сервер (и сетевое оборудование) вправе сделать вывод, что правильное решение - отключить соединение и освободить ресурсы, используемые для него.Вы пытаетесь бороться с правильным поведением, которое происходит по уважительным причинам.Даже если вам удастся обойти отключение TCP, вы обнаружите другие проблемы, такие как тайм-ауты сервера HTTP и тайм-ауты базы данных.

Вместо этого вам следует пересмотреть схему связи между двумя компонентами.То есть это выглядит как проблема XY.Вы могли бы подумать

  • Чтобы клиент дождался полной загрузки, чтобы выполнить , прежде чем запустит POST.
  • Разделение загрузок на более мелкие и более частые загрузки.
  • Использовать протокол, отличный от HTTP.
0 голосов
/ 01 марта 2019

Подход, описанный выше с Socket, прекрасно работал со сбросом значения tcp_keepalive_intvl ниже тайм-аута AWS Network Load Balancer. Используя оба, сбросьте таймаут простоя tcp NLB, который разрешил java hour + соединения.

0 голосов
/ 20 ноября 2018

Я нашел решение проблемы. Любопытно, что я не могу использовать какой-то класс построителя в httpclient для передачи активности сокета. Один метод, как я указал в вопросе, использует HttpConnectionParams, как показано ниже, но это не работает, и этот класс устарел.

HttpParams params = httpClient.getParams();
HttpConnectionParams.setSoKeepalive(params, true);

Итак, при проверке apache http-документов я вижу, что теперь параметры соединения передаются httpclient через класс RequestConfig. Разработчики этого класса предоставляют решение для установки connection_time_out и socket_time_out. Но, проверяя этот код, я не смог увидеть опцию включения SocketKeepAlive, чего мы и хотим. Таким образом, единственным решением является непосредственное создание Socket с использованием класса SocketBuilder и передача его в HttpClientBuilder.

Ниже приводится рабочий код

SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setSoTimeout(3600000).build(); //We need to set socket keep alive
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(3600000).build();
        CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).
                                           setDefaultSocketConfig(socketConfig).build();
HttpPost post = new HttpPost(url.toString());
HttpResponse response = httpClient.execute(post);

Выполняя выше, я вижу, что keep keep правильно установлен в сокете на основе значений sysctl, которые я установил в ядре linux

tcp        0      0 localip:48314     public_ip:443     ESTABLISHED 14863/java          keepalive (234.11/0/0)

Если у кого-то есть лучшее решение для включения поддержки Socket Keep из класса Requestconfig или любого другого класса построителя высокого уровня, я открыт для предложений.

...