Requests: Слишком много открытых файлов

Созданный на 5 нояб. 2011  ·  81Комментарии  ·  Источник: psf/requests

Я создаю базовый генератор нагрузки и начал работать с ограничениями файловых дескрипторов, я не видел никакой документации, касающейся того, как освобождать ресурсы, поэтому либо я делаю это неправильно, и документы нуждаются в обновлении, либо запросы утекают дескрипторы файлов где-то (без поддержки для поддержки активности меня немного смущает, почему какие-либо файлы вообще остаются открытыми)

Bug Contributor Friendly

Самый полезный комментарий

«Слишком много открытых файлов» - это результат ошибки, вызванной тем, что сокеты остаются в CLOSE_WAIT.
Так что ulimit не исправит, просто найдет обходной путь.

Все 81 Комментарий

Где вы используете requests.async ?

нет, все запросы были достаточно простыми request.get / requests.post, я все еще вижу несколько там

$ lsof | grep localhost | wc -l
110

все, кроме 4/5, имеют формат

Python    82117 daleharvey  123u    IPv4 0xffffff800da304e0       0t0      TCP localhost:61488->localhost:http (CLOSE_WAIT)

Если честно, меня это немного сбивает с толку.

Привет, сделаю еще один шанс надежно воспроизвести его, если я не смогу закрыть

Я видел, как это происходит со мной, но только когда я использую асинхронный модуль с 200+ одновременными подключениями.

Здравствуй,
У меня точно такая же проблема с запросами и исправлением обезьян с помощью gevent: некоторые соединения остаются в CLOSE_WAIT.
Может проблема с gevent так.

Это может быть проблема ulimit -n. Попробуйте с более высоким значением.

«Слишком много открытых файлов» - это результат ошибки, вызванной тем, что сокеты остаются в CLOSE_WAIT.
Так что ulimit не исправит, просто найдет обходной путь.

@tamiel, как это исправить?

Я сделаю больше тестов как можно скорее и постараюсь исправить.

Я изучил это и, похоже, проблема со всеми библиотеками, использующими httplib.HTTPSConnection.

Разместил здесь пример:

https://gist.github.com/1512329

Я только что столкнулся с очень похожей ошибкой, используя асинхронный пул только с HTTP-соединениями - я все еще изучаю, но передача размера пула в async.map позволяет быстро воспроизвести ошибку.

Какие-нибудь исправления к этому? Это делает запросы непригодными для использования с gevent ..

Все дело в CLOSE_WAIT s. Просто надо их закрыть. Я не уверен, почему они все еще открыты.

Это проблема с urllib3? Мне кажется, что закрывать их самостоятельно - не лучшая идея.

Это скорее общая проблема. Мы можем продолжить разговор здесь.

Хорошо, просто чтобы дать вам представление, мы пытаемся перейти от httplib2 к запросам, и мы не видим этой проблемы с httplib2. Так что это точно не общая проблема.

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

так как мы это решим? мы действительно хотим использовать запросы + дремоту двигаться вперед

Я хотел бы знать ответ на этот вопрос.

Утечка, по-видимому, связана с обработкой внутреннего перенаправления, которая вызывает создание новых запросов до того, как ожидающие ответы будут использованы. При тестировании acdha @ 730c0e2e2bef77968a86962f9d5f2bebba4d19ec имеет

Это потребовало изменений в двух местах, из-за чего мне захотелось немного реорганизовать интерфейс, но сейчас у меня нет времени, чтобы продолжить.

399 имеет исправление, которое хорошо работает в моем генераторе асинхронной нагрузки (https://github.com/acdha/webtoolbox/blob/master/bin/http_bench.py) с тысячами запросов и низким ulimit fd

Я столкнулся с той же проблемой при использовании async - решил обходной путь, разбив запросы и удалив ответы / вызвав gc.collect

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

Используя async, я смог ПОЛУЧИТЬ только 4 вещи, прежде чем он приостановился на 60 секунд.

Используя обычный GET с потреблением, я мог получить около 150 вещей последовательно менее чем за 40 секунд.

Еще не сделал свой кладж с тех пор, как увидел эту проблему.

Только что получил эту ошибку при использовании ipython и получил это сообщение. Это просто выполнение каждого запроса по одному, но я думаю, что получил нечто подобное при использовании async.

ERROR: Internal Python error in the inspect module.
Below is the traceback from this internal error.
Traceback (most recent call last):
    File "/Library/Python/2.7/site-packages/IPython/core/ultratb.py", line 756, in structured_traceback
    File "/Library/Python/2.7/site-packages/IPython/core/ultratb.py", line 242, in _fixed_getinnerframes
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 1035, in getinnerframes
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 995, in getframeinfo
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 456, in getsourcefile
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 485, in getmodule
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 469, in getabsfile
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 347, in abspath
OSError: [Errno 24] Too many open files

Unfortunately, your original traceback can not be constructed.

Как ни странно, я думаю, что при использовании обычного интерпретатора Python я получаю «Max Retries Error», но я думаю, что это еще одна проблема, когда я выполняю запросы во всем том же домене, но не уверен.

Я столкнулся с этим в первом своем проекте, где allow_redirects был True; По всей видимости, это вызвано утечкой объектов ответа в цепочке перенаправления, которые не выпускаются даже с prefetch = True. Это исправило это в моем первоначальном тестировании:

        [i.raw.release_conn() for i in resp.history]
        resp.raw.release_conn()

Хммм ..

Настройка @acdha :

requests.defaults.defaults['allow_redirects'] = False

прежде чем я сделаю какие-либо запросы, все равно приведет к той же ошибке, но я думаю, что это не вариант для моей реализации, поскольку все запросы, которые я делаю, потребуют перенаправления = /

@dalanmiller Как вы обрабатываете свои ответы? Раньше я использовал async.map с перехватчиком ответа, и он _ кажется_ более стабильным с помощью простого цикла над async.imap :

for resp in requests.async.imap(reqs, size=8):
    try:
        print resp.status_code, resp.url
    finally:
        [i.raw.release_conn() for i in resp.history]
        resp.raw.release_conn()

@acdha

Я просто использовал цикл for через список URL-адресов и делал request.get для каждого с моими настройками и т. Д.

for u in urls:
    response_list.append(requests.get(u))

Я пробовал использовать вашу пасту, и она работает примерно для 50 запросов в моем списке длиной 900, пока я не начну получать «максимальное количество ошибок превышено с URL-адресом» для остальных. Это довольно стандартная ошибка для многократного обращения к одному и тому же домену, не так ли?

Эй, я просматривал огромный список URL-адресов, 35 КБ, и получил ту же ошибку на _ некоторых_ запросов.

Я получаю URL-адреса кусками по 10, например:

responses = requests.async.map([requests.async.get(u, params=self.params()) for u in chunk]) # chunk is a list of 10

Где-то в диапазоне 20k я начал получать ошибку 24, затем все было нормально через 30k, а затем снова.

Есть дополнительная информация, которая может вас заинтересовать, чтобы сузить круг вопросов?

requests.async больше нет. Вы можете подумать о переходе на grequests.

Все хорошо, спасибо. Было бы хорошо упомянуть об этом в документации.

Что-то вроде новичка, когда дело доходит до запросов на вытягивание и написания документации, но я попробовал и отправил. Прокомментируйте или покритикуйте :)

https://github.com/kennethreitz/requests/pull/665

Хорошо, это происходит даже без использования async, с помощью только requests.get, после 6K запросов.

Я подозревал это.

Для меня ошибка «Слишком много открытых файлов» возникла после загрузки ровно 1k файлов. Мое решение заключалось в том, чтобы отключить свойство keep-alive, когда-либо получать запросы кусками ( @acdha спасибо за подсказку). lsof -p PID | wc -l показывает, что количество подключений во время выполнения не увеличивается.

rsess = requests.session()
rsess.config['keep-alive'] = False

rs = [grequests.get(l, session=rsess) for l in links]

for s in chunks(rs,100):
    responses = grequests.map(s, size=concurrency)
    for r in responses:
        try:
            print(r.status_code, r.url)
        finally:
            r.raw.release_conn()

[1] фрагменты: http://stackoverflow.com/a/312464

Закрытие с отложенным исправлением urllib3.

@kennethreitz Какой номер выпуска у urllib3?

Похоже, это проблема http://bugs.python.org/issue16298

@silvexis вполне может быть связана с ошибкой urllib3, теперь я просто хочу, чтобы кто-нибудь ответил на @ piotr-dobrogost: P

Кто-нибудь еще сталкивается с этой проблемой?

Я не слышал об этом. Ты?

Это проблема конфигурации коробки, а не фреймворка. Посмотрите конфигурацию ядра вашей ОС. В BSD это называется kern.maxfiles . В системах Linux есть поток о ulimit : http://stackoverflow.com/questions/34588/how-do-i-change-the-number-of-open-files-limit-in-linux
Надеюсь, это поможет, и я не знаю, как изменить этот параметр в Windows.

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

    if self._current_response is not None:
            # Requests doesn't have a clean API to actually close the
            # socket properly. Dig through multiple levels of private APIs
            # to close the socket ourselves. Icky.
            self._current_response.raw.release_conn()
            if self._current_response.raw._fp.fp is not None:
                sock = self._current_response.raw._fp.fp._sock
                try:
                    logger.debug('Forcibly closing socket')
                    sock.shutdown(socket.SHUT_RDWR)
                    sock.close()
                except socket.error:
                    pass

(Я думаю, что self._current_response - это объект ответа на запросы)

Хм, а где оборвана цепочка замыканий? У нас есть метод Response.close() который вызывает release_conn() , так что же должно произойти в release_conn() чтобы это сработало?

@Lukasa, это было определенно исправлено в urllib3, поскольку я участвовал в обсуждении. Склоняясь к консерватизму в моих оценках, я бы сказал, что он есть, поскольку запросы 1.2.x, если не 1.1.x.

Да, я действительно думал, что это было исправлено. Если мы не увидим чего-то в 1.2.3, я буду продолжать считать, что это исправлено.

Я вижу утечку CLOSE_WAIT в версии 2.0.2. Есть ли у вас модульные тесты, чтобы убедиться, что по теме нет регресса?

Нет, не делаем. AFAIK urllib3 тоже не работает. Сможете ли вы легко воспроизвести утечку?

Мы используем request в нашем внутреннем приложении с понедельника и сегодня достигли 1024 maxfiles.

Через 2 часа после перезагрузки у нас 40 CLOSE_WAIT, как сообщает lsof.

Так что я думаю, что мы сможем воспроизводить в среде разработки, да. Я буду держать тебя на связи

@tardyp тоже, как вы устанавливали запросы? Я думаю, что все разработчики пакетов ОС убирают urllib3. Если они не обновляют это, и вы используете старую версию, это может быть причиной. Если вы используете pip, не стесняйтесь открывать новую проблему, чтобы отслеживать это, вместо того, чтобы добавлять обсуждение к этому.

Я установил с помощью pip, но я использую python 2.6, я видел исправление на python2.7 для
этот баг. Вы обновляете более старую версию?

Пьер

Пт, 29 ноября 2013 г., в 17:33, Ян Кордаско [email protected] написал:

@tardyp https://github.com/tardyp тоже, как вы устанавливали запросы? я
думаю, что все разработчики пакетов ОС вырезают urllib3. Если они этого не сделают
обновляйте его, и вы используете старую версию, это может быть
причина вместо этого. Если вы используете pip, не стесняйтесь открывать новый выпуск в
отслеживайте это с помощью вместо добавления обсуждения к этому.

-
Ответьте на это письмо напрямую или просмотрите его на Gi tHubhttps: //github.com/kennethreitz/requests/issues/239#issuecomment -29526302
.

@tardyp, пожалуйста, откройте новую проблему с как можно более подробной информацией, в том числе о том, имеют ли ваши запросы перенаправления и используете ли вы gevent. Кроме того, любые подробности об операционной системе и пример того, как ее воспроизвести, были бы фантастическими.

К вашему сведению, https://github.com/shazow/urllib3/issues/291 был отменен из-за ошибок.

Должны ли мы снова открыть это?
У меня такая же проблема!

@polvoazul Нет никакого

@Lukasa, мне нужна твоя помощь。 я использую eventlet + запросы ,, которые всегда создают так много sock, которые не могут идентифицировать протокол。 мои запросы - 2.4.3, это eventlet + запросы вызывают эту проблему?

Мне очень жаль, @mygoda , но это невозможно узнать. Если вы не ограничиваете количество запросов, которые могут быть невыполненными в любой момент времени, это, безусловно, возможно, но это архитектурная проблема, выходящая за рамки компетенции запросов.

@Lukasa, спасибо。 я думаю, что моя проблема с этим похожа。 мой проект - pyvmomi . это соединение долгое. Я всегда не понимал, почему так много не может идентифицировать протокольный носок

Имея такую ​​же проблему сейчас, при запуске 120 потоков, вызывающих более 100000 открытых файлов, есть ли решение прямо сейчас?

@mygoda, у тебя

@ 1a1a11a _Какие_ файлы у вас открыты? Это было бы первым полезным шагом к пониманию этой проблемы.

@ 1a1a11a какую версию запросов вы используете? Какая версия питона? Какая операционная система? Можем ли мы получить какую-нибудь информацию?

Я использую запрос 2.9.1, python 3.4, ubuntu 14.04, в основном я пишу краулер, использующий 30 потоков с прокси для сканирования какого-либо веб-сайта. В настоящее время я установил ограничение на количество файлов для каждого процесса до 655350, в противном случае будет отображаться сообщение об ошибке.

Я все еще получаю сообщение об ошибке «Не удалось установить новое соединение: [Errno 24] Слишком много открытых файлов» из requests.packages.urllib3.connection.VerifiedHTTPSConnection. «Я использую Python 3.4, запросы 2.11.1 и запросы-фьючерсы» 0.9.7. Мне нравится, что запросы-фьючерсы - это отдельная библиотека, но похоже, что ошибка возникает из-за запросов. Я пытаюсь выполнить 180 тыс. Асинхронных запросов через SSL. Я разделил эти запросы на сегменты по 1000, поэтому я переходите к следующей 1000 только после того, как все будущие объекты будут разрешены. Я использую Ubuntu 16.04.2, и мое ограничение на количество открытых файлов по умолчанию - 1024. Было бы хорошо понять основную причину этой ошибки. Создает ли библиотека запросов открыть файл для каждого отдельного запроса? И если да, то почему? Является ли это файлом сертификата SSL? И закрывает ли библиотека запросов автоматически эти открытые файлы при разрешении будущего объекта?

Запросы открывает много файлов. Некоторые из этих файлов открываются для сертификатов, но они открываются OpenSSL, а не запросами, поэтому они не обслуживаются. Кроме того, запросы также при необходимости открывают файл .netrc файл hosts и многие другие.

Лучше всего использовать такой инструмент, как strace чтобы определить, какие файлы открываются. Существует строгий список системных вызовов, которые приводят к выделению файловых дескрипторов, поэтому вы должны достаточно быстро уметь их перечислить. Это также позволит вам узнать, есть ли проблема. Но да, я ожидал, что если вы активно устанавливаете 1000 подключений по HTTPS, то при пиковой нагрузке мы могли бы легко использовать более 1000 FD.

Я тоже боролся с этой проблемой и обнаружил, что использование opensnoop в OS X отлично работает, позволяя мне видеть, что происходит, если кто-то сталкивается с теми же проблемами.

Я также часто вижу эту ошибку при многократном вызове requests.post(url, data=data) на сервер HTTP (не HTTPS). Работает на Ubuntu 16.04.3, Python 3.5.2, запросы 2.9.1

Что такое data ?

Текст в несколько сотен килобайт

Не файловый объект?

Нет, формирую в памяти большой запрос.

Вы запускаете этот код в нескольких потоках?

Нет, один поток, отправка на localhost

В таком случае кажется почти невозможным утечка такого количества FD: мы должны многократно использовать одно и то же TCP-соединение или агрессивно его закрывать. Хотите узнать, чем занимается ваш сервер?

У меня такая проблема. Python 2.7, запросы 2.18.4, urllib3 1.22.
Запуск многопоточного кода (не многопоточного). Подключение максимум к 6 URL-адресам за один раз, создание и закрытие нового сеанса для каждого вручную.

У меня такая же проблема с Python 3.5 , requests==2.18.4

@mcobzarenco , вы уверены, что (неявно) закрываете базовое соединение ответа? Простой возврат ответа не приведет к закрытию соединения. При чтении response.content данные фактически считываются, и после этого сокет не останется в CLOSE_WAIT.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги