LINUX.ORG.RU

Куча CLOSE_WAIT соединений

 , ,


1

1

Добрый день! Возникла такая проблема в проекте. Используется requests для запросов. Создается отдельная Session и через нее делается куча запросов к API. Проблема состоит в том, что через некоторые время появляется очень много CLOSE_WAIT соединений и вылетает Too many open files. Увеличивать лимит - временное решение. Пробовал менять Keep-alive на Close. Не помогло. response.content читается. Как понимаю, urllib должен при этом сам закрыть соединение. Но что-то явно не то.

В какую сторону копать? В TCP не настолько силен.

Ответ на: комментарий от xpahos

SO_LINGER поставь. Это решит твое проблемы, но позже все потребуется почитать как работает TCP.

Как это сделать в requests? Там вроде как прямого доступа к сокету нет.

crarkie ()
Последнее исправление: crarkie (всего исправлений: 1)
Ответ на: комментарий от xpahos

SO_LINGER поставь. Это решит твое проблемы, но позже все потребуется почитать как работает TCP.

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

crarkie ()
Ответ на: комментарий от xpahos

SO_LINGER вообще про другое. TIME_WAIT != CLOSE_WAIT.

Вообще, задача ТСа странная, если уже используется asyncio, вместо того, чтобы загонять requests в отдельные потоки, можно перейти на aiohttp.

requests по умолчанию резервирует до 10 коннектов в пуле. Можно уменьшить это до 1, используя свой инстанс HTTPAgent, проинициализированный с нужными параметрами.

Еще можно попробовать явно вызывать close над объектами ответов (и сессии, когда она становится не нужна).

Возможно где-то остается лишняя ссылка, из-за чего коннекты не утилизируются сборщиком мусора, можно через pympler поискать утечки.

anonymous ()
Ответ на: комментарий от anonymous

Вообще, задача ТСа странная, если уже используется asyncio, вместо того, чтобы загонять requests в отдельные потоки, можно перейти на aiohttp.

Проблема в том, что это legacy-govno, которое переписывать все у меня нет желания. Какой-то мудак сделал asyncio. В нем запускает таски в executor, а в таске делает для каждой new_event_loop. Ну не мудак ли?

Еще можно попробовать явно вызывать close над объектами ответов (и сессии, когда она становится не нужна).

Вроде как везде, где только можно засунул. А все равно течет.

Возможно где-то остается лишняя ссылка, из-за чего коннекты не утилизируются сборщиком мусора, можно через pympler поискать утечки.

Можно по подробнее?

crarkie ()
Ответ на: комментарий от anonymous

SO_LINGER вообще про другое. TIME_WAIT != CLOSE_WAIT.

Там как повезет. Если он успевает сделать RST, то все будет ок. Но судя по-другому посту не успевает. close конечно правильнее, но я не уверен что requests даст возможность так глубоко влезть. Если адреса одни и те же, то наоборот имеет смысл держать keep-alive соединение.

xpahos ★★★★★ ()
Ответ на: комментарий от crarkie

Ну не мудак ли? Однозначно Ж)

в таске делает для каждой new_event_loop requests по дефолту не закрывает сокет, а возвращает его обратно в пул для повторного использования (до 10 коннектов), но возможно что для каждого потока пул оказывается своим.

А вариант с кастомным HTTPAgent пробовал? что-то типа такого:

import requests
import requests.adapters

session = requests.session()
session.mount("http://", requests.adapters.HTTPAdapter(pool_connections=0, pool_maxsize=0))

# ... и то же самое для https

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

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

anonymous ()
Ответ на: комментарий от anonymous

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

Session сохраняется в обьекте таски, и переиспользуется для каждой отдельной задачи много раз. Разве не так должно быть?

crarkie ()
Ответ на: комментарий от turtle_bazon

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

crarkie ()

У меня в проекте на java с использованием apache client была подобная проблема. Я выставил свойства connectTimeout, connectionRequestTimeout и socketTimeout в конфиге для запросов, и проблема решилась. Как это сделать в python я не знаю.

pol01 ()