Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумСети и протоколы

Keep-alive и долгие сессии: где рвётся

iron_shell
iron_shell
Знаток
сообщений 1050
с июн
8 октября, 11:57первое сообщение

Держу долгий сеанс к одному узлу: вхожу один раз, дальше за смену дёргаю его сотню раз по мелочи. Между дёрганьями бывает пауза минут в десять.

И вот после каждой такой паузы первый запрос падает. Всегда первый, всегда после паузы, второй тут же проходит как ни в чём не бывало. В логе видно обрыв со стороны собеседника, будто трубку положили и мне об этом сказать забыли.

Пока прикрутил повтор с одной попыткой, оно работает, но это заметание под ковёр. Хочу понять, кто именно кладёт трубку: посредник, узел или что-то по дороге.

requests.exceptions.ConnectionError: ('Connection aborted.',
  RemoteDisconnected('Remote end closed connection without response'))
queue_master
queue_master
Участник
сообщений 410
с ноя
15 марта, 14:14#2

Классика пула соединений. У вас в кармане лежит открытый сокет, вы про него думаете, что он живой и тёплый. Собеседник закрыл его десять минут назад по своему таймауту простоя, уведомление либо не дошло, либо дошло и было проглочено пулом.

Дальше вы пишете в мёртвый сокет и получаете ровно эту строчку. Тут не поломка сети, тут расхождение в бухгалтерии между вами и дальним концом.

очередь длиннее памяти
loginless
loginless
Новичок
сообщений 130
с мая, второй сезон
22 августа, 17:31#3

а таймаут простоя где смотреть, у себя или у них

iron_shell
iron_shell
Знаток
сообщений 1050
с июн
1 января, 08:48#4
queue_master: расхождение в бухгалтерии между вами и дальним концом

Хорошая формулировка, забираю. loginless, я тоже сначала копал у себя, потом насчитал в цепочке целых три места, где висит свой таймер.

Максим Юрьев
Максим Юрьев
Знаток
сообщений 1720
с апр
8 июня, 11:05#5

Три места это ещё скромно, обычно их больше. Разложу столбиком, кто первым кладёт трубку.

Кто держит паузуГде смотретьОбычная величина
Ваша библиотекасрок жизни сокета в пулебез ограничения
Посредникпростой туннеля в настройкахминута или две
Веб-сервер узлаkeepalive_timeoutсекунд пять
Таблица трансляции по дорогеconntrack на шлюзепара минут
Ядро вашей машиныtcp_keepalive_timeдва часа
через сколько секунд простоя закрывают
через сколько секунд простоя закрывают

Побеждает самая короткая строка. Когда узел рвёт через пять секунд, всё остальное в списке роли не играет. Ядро с его двумя часами вступает в дело только там, где вся цепочка выше молчит и терпит.

Иногда узел прямо пишет в ответе, сколько времени вам дали:

Keep-Alive: timeout=5, max=100
ostrov
ostrov
Участник
сообщений 505
с окт
15 ноября, 14:22#6

Посмотреть можно на живой машине, гадать необязательно: ss -tno рисует таймер по каждому соединению. Если в колонке timer стоит keepalive и число тикает вниз, сокет держит ядро.

batchrunner
batchrunner
Участник
сообщений 470
с окт
22 апреля, 17:39#7

У себя лечил в два касания. Ограничил срок жизни сокета в пуле и добавил один вежливый повтор именно на такой обрыв.

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

s = requests.Session() r = Retry(total=2, backoff_factor=0.4, status_forcelist=[502, 503, 504]) s.mount("https://", HTTPAdapter(max_retries=r, pool_maxsize=20)) ```

Повтор на оборванный сокет срабатывает сам, urllib3 считает такой случай пригодным для второй попытки. Сверху раз в пять минут дёргаю самую лёгкую страницу узла, чтобы соединение не успевало остыть.

loginless
loginless
Новичок
сообщений 130
с мая, второй сезон
1 сентября, 08:56#8

понял, забрал себе, спасибо

Оксана В.
Оксана В.
Участник
сообщений 350
с дек
8 февраля, 11:13#9

Добавлю про ядро, раз его помянули. Когда сеанс правда долгий и молчаливый, включайте пробы на сокете и опускайте их время ниже самой короткой паузы в цепочке.

sudo sysctl -w net.ipv4.tcp_keepalive_time=90
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=20

Иначе ядро проснётся через два часа и обнаружит обрыв, случившийся полутора часами раньше.

iron_shell
iron_shell
Знаток
сообщений 1050
с июн
15 июля, 14:30#10

Померил через ss, рвётся у меня раньше всех сам узел. В заголовке ответа честно написаны те самые пять секунд.

queue_master
queue_master
Участник
сообщений 410
с ноя
22 декабря, 17:47#11

Тогда повтор останется у вас навсегда, и это нормальная жизнь. Пять секунд означают, что узел хочет короткие соединения и долгих гостей не любит. Держать поверх него длинный сеанс смысла мало: дешевле открывать заново. Пул при этом оставьте, внутри пачки запросов он сэкономит вам сотню рукопожатий.

очередь длиннее памяти
iron_shell
iron_shell
Знаток
сообщений 1050
с июн
1 мая, 08:04#12

Собрал итог для тех, кто придёт сюда поиском.

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