Gunicorn: OSError: [Errno 0] Ошибка

Созданный на 8 мая 2018  ·  30Комментарии  ·  Источник: benoitc/gunicorn

Я запускаю приложение
gunicorn -w 2 -b ' localhost: 8585 ' --timeout = 200 --certfile = crt.crt --keyfile = key.key сервис: приложение

И я получаю следующее, но не всегда получаю такой ответ, большинство запросов обрабатываются правильно, но иногда возникает ошибка

[2018-05-08 14:53:36 +0500] [11227] [ERROR] Socket error processing request.
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/gunicorn/workers/sync.py", line 134, in handle
    req = six.next(parser)
  File "/usr/lib/python3/dist-packages/gunicorn/http/parser.py", line 41, in __next__
    self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
  File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 153, in __init__
    super(Request, self).__init__(cfg, unreader)
  File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 53, in __init__
    unused = self.parse(self.unreader)
  File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 165, in parse
    self.get_data(unreader, buf, stop=True)
  File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 156, in get_data
    data = unreader.read()
  File "/usr/lib/python3/dist-packages/gunicorn/http/unreader.py", line 38, in read
    d = self.chunk()
  File "/usr/lib/python3/dist-packages/gunicorn/http/unreader.py", line 65, in chunk
    return self.sock.recv(self.mxchunk)
  File "/usr/lib/python3.5/ssl.py", line 922, in recv
    return self.read(buflen)
  File "/usr/lib/python3.5/ssl.py", line 799, in read
    return self._sslobj.read(len, buffer)
  File "/usr/lib/python3.5/ssl.py", line 585, in read
    v = self._sslobj.read(len)
OSError: [Errno 0] Error
( FeaturSSL

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

Хм, после некоторых дополнительных исследований кажется, что на самом деле это может быть ошибка в том, как библиотека python ssl обрабатывает рваные EOF в Linux: https://bugs.python.org/issue31122

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

Насколько мне известно, эта ошибка возникает, когда клиент пытается подключиться без SSL. Может ли это иметь место для вас?

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

Есть ли закономерность, по которой запросы терпят неудачу?

@usmetanina, какие клиенты тоже подключаются к Gunicorn? Есть ли у вас какие-либо параметры SSL, используемые явно для подключения к нему?

это уже решено? @usmetanina , потому что у меня точно такая же проблема

@benoitc я вижу @usmetanina «S точная ошибка часто используя python3.6 и gunicorn 19.9.0 .

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

gunicorn --workers=3 --bind=0.0.0.0:8000 --config=gunicorn_config.py --preload main

Файл конфигурации выглядит следующим образом (domain-with-cert.com, конечно же, является заполнителем для фактического имени домена):

workers = 3
bind = '0.0.0.0:443'
certfile = '/etc/letsencrypt/live/domain-with-cert.com/fullchain.pem'
keyfile = '/etc/letsencrypt/live/domain-with-cert.com/privkey.pem'

Любые мысли по поводу отладки были бы полезны. Если вам нужна дополнительная информация, просто дайте мне знать.

@willpatera , см. мой комментарий:

Насколько мне известно, эта ошибка возникает, когда клиент пытается подключиться без SSL. Может ли это иметь место для вас?

@tilgovi Я видел вышеупомянутый комментарий. Я почти уверен, что клиент подключается через SSL. Есть предложения по отладке?

@willpatera Я бы сказал, включите журналы доступа и посмотрите, сможете ли вы определить, какой запрос вызывает проблему. Если у вас есть обратный прокси перед Gunicorn, убедитесь, что у него есть журналы доступа, чтобы вы могли видеть, какой запрос вызывает ошибку с Gunicorn, даже если Gunicorn никогда не регистрирует его.

@tilgovi У меня такие же проблемы. Пришлось немного отредактировать следующую информацию, поскольку она была неверной:
Запрос к Gunicorn всегда является одним и тем же запросом (но с другим телом). Так что нет никаких сомнений в том, что это https, а не http.
Что я действительно замечаю, так это то, что это всегда происходит, когда количество запросов увеличивается. Когда сервер занят, у него возникают проблемы с правильной обработкой запросов.

Может это связано с рабочими или что-то в этом роде? Если у вас есть предложения по настройке, я с удовольствием их протестирую.

Привет, ребята, я все еще ищу способ решить эту проблему. В настоящее время у нас есть единственный вариант - перейти на простой HTTP, что вообще невозможно.

Я был свидетелем того же. Если бы производственный сервер работал под управлением Gunicorn + Flask (за балансировщиком нагрузки), который работал нормально в течение нескольких месяцев, затем внезапно каждый запрос выдавал эту ошибку, пока я не перезапустил Gunicorn:

[2019-11-21 07:27:36 +0000] [24245] [ERROR] Socket error processing request.
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/workers/sync.py", line 134, in handle
    req = six.next(parser)
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/parser.py", line 41, in __next__
    self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 181, in __init__
    super(Request, self).__init__(cfg, unreader)
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 54, in __init__
    unused = self.parse(self.unreader)
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 193, in parse
    self.get_data(unreader, buf, stop=True)
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 184, in get_data
    data = unreader.read()
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/unreader.py", line 38, in read
    d = self.chunk()
  File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/unreader.py", line 65, in chunk
    return self.sock.recv(self.mxchunk)
  File "/usr/lib/python3.6/ssl.py", line 997, in recv
    return self.read(buflen)
  File "/usr/lib/python3.6/ssl.py", line 874, in read
    return self._sslobj.read(len, buffer)
  File "/usr/lib/python3.6/ssl.py", line 633, in read
    v = self._sslobj.read(len)
OSError: [Errno 0] Error

Ничто в журналах, предшествующих этим ошибкам, не намекает на то, что могло быть триггером.

Это было с Gunicorn 19.9.0, работающим с 3 рабочими на сервере с одним ядром.

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

Ваш LB вызывает конкретную конечную точку? Как он отвечает на запрос LB?

Когда я сказал «Балансировщик нагрузки», я действительно должен был сказать «CDN» или уровень кеширования. В частности: это Amazon Cloudfront. Он просто перенаправляет запросы на наш сервер Gunicorn (работающий на экземпляре EC2) и на некоторое время кэширует результаты.

хрм, не следует ли Amazon Cloudfront прекращать за вас ssl-запрос? @ExplodingCabbage . Почему Gunicorn должен слушать по ssl сзади?

@benoitc Итак, в архитектуре задействованы два уровня SSL. Члены сообщества подключаются к нашему веб-сайту через наш домен CloudFront через HTTPS, а затем CloudFront делает запрос к нашему внутреннему узлу, на котором запущен Gunicorn, также используя HTTPS (с другим именем домена и сертификатом), кэширует результат и передает его в общественные.

Думаю, может быть, вам интересно, в чем смысл использования SSL для этого второго внутреннего запроса? Это, конечно, спорно, это бессмысленно (хотя, возможно, и нет - это останавливает Amazon, отслеживающую наши каналы связи во внутренней сети, а также существуют нормативные причины, по которым я не буду вдаваться в подробности, почему, учитывая отрасль моей компании, нам может потребоваться убедиться, что у нас есть шифрование на всем протяжении конвейера). Бессмысленно или нет, мы это делаем. ¯ \ _ (ツ) _ / ¯

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

@benoitc Я не думаю, что CloudFront предоставляет какие-либо журналы, которые были бы полезны, но я уверен, что он не пытался подключиться через HTTP, поскольку:

  • Наш дистрибутив настроен в консоли CloudFront для подключения к источнику Gunicorn через "только HTTPS"
  • Gunicorn не прослушивает порт 80
  • Если я попытаюсь подключиться к нашему внутреннему серверу через HTTP (включая принудительное использование HTTP на порту 443), он не воспроизведет ошибку OSError, указанную выше.
  • Когда я получал приведенную выше ошибку OSError, перезапуск Gunicorn на внутреннем сервере мгновенно устранил проблему, которая указывает на что-то не так на стороне Gunicorn, а не на стороне Cloudfront.

@ExplodingCabbage хорошо, я посмотрю на него после выхода 20.0.1. И последнее: какую версию Python вы используете?

3.6.8

Я понимаю, что упустил деталь из моего рассказа выше: перед перезапуском Gunicorn я также обновил SSL-сертификат, который Gunicorn использует с LetsEncrypt. Я не подумал упомянуть об этом, потому что вчера я ошибочно пришел к выводу, что срок действия сертификата не может истечь в тот день, когда возникла ошибка, и что обновление сертификата на самом деле не имело отношения к устранению проблемы.

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

Здесь все еще есть некоторая загадка и некоторые потенциальные возможности для улучшения (что именно означает эта ошибка и почему Gunicorn не может дать более полезное сообщение?), Но рассказ, который я дал ранее, в котором эта ошибка началась совершенно неожиданно без видимой причины - неправильно. Я предполагаю, что CloudFront разрывает соединение в ответ на просроченный сертификат с сервера Gunicorn, и что Gunicorn вместо того, чтобы понять это и осмысленно сообщить об этом, вызывает всплытие ошибки OSError без сообщений.

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

@ExplodingCabbage о, это довольно интересно, тогда он должен быть воспроизведен в какой-то момент. Спасибо за дополнительную информацию!

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

Для меня это было вызвано тем, что я забыл о тайм-ауте при блокирующем вызове и накоплении запросов.

HTH

Привет! У меня именно такая проблема. У меня есть служба gunicorn / flask, работающая в кластере ECS за балансировщиком сетевой нагрузки. Некоторые особенности версии:

python    - 3.7.4
gunicorn  - 19.9.0
flask     - 1.0.4

Служба может без проблем отвечать на запросы, поступающие от клиента, с использованием TLS, однако мои журналы переполнены OSErrors. Насколько я могу судить, они возникают в результате запросов на проверку работоспособности, поступающих от балансировщика нагрузки (TCP).

Мне удалось воспроизвести ошибку локально, открыв и закрыв TCP-соединение вручную на порте прослушивания (в данном случае 8000):

$ nc -vz 127.0.0.1 8000
localhost [127.0.0.1] 8000 (irdmi) open

В результате возникла следующая ошибка:

Traceback (most recent call last):
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/workers/sync.py" line 134 in handle
        req = six.next(parser)
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/parser.py" line 41 in __next__
        self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 181 in __init__
        super(Request, self).__init__(cfg, unreader)
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 54 in __init__
        unused = self.parse(self.unreader)
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 193 in parse
        self.get_data(unreader, buf, stop=True)
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 184 in get_data
        data = unreader.read()
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/unreader.py" line 38 in read
        d = self.chunk()
    File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/unreader.py" line 65 in chunk
        return self.sock.recv(self.mxchunk)
    File "/nix/store/azwzsm1pkbzjxpkiq88w68p4jdghgasl-python3-3.7.4/lib/python3.7/ssl.py" line 1056 in recv
        return self.read(buflen)
    File "/nix/store/azwzsm1pkbzjxpkiq88w68p4jdghgasl-python3-3.7.4/lib/python3.7/ssl.py" line 931 in read
        return self._sslobj.read(len)
OSError: [Errno 0] Error

Надеюсь это поможет!

Хм, после некоторых дополнительных исследований кажется, что на самом деле это может быть ошибка в том, как библиотека python ssl обрабатывает рваные EOF в Linux: https://bugs.python.org/issue31122

Как упомянул @shevisjohnson, если вы выполните команду «nc -vz hostname port_no», появится эта ошибка.
Мы можем подавить эту ошибку в файле журнала, используя нижеприведенный механизм ведения журнала.

$ cat logging_config.yml

version: 1

formatters:
  simple:
    format: " %(asctime)s || %(name)s || %(levelname)s || %(message)s"

  test_api:
    format: "[%(asctime)s] [%(process)s] [%(levelname)s] %(message)s"

handlers:

  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout

  test_api_file_handler:
     class: logging.handlers.RotatingFileHandler
     level: DEBUG
     formatter: test_api
     filename: logs/test.log
     maxBytes: 2000000000
     backupCount: 1
     encoding: utf8

loggers:

  test_api: 
    level: DEBUG
    handlers: [test_api_file_handler]
    propagate: 0

root:
  level: DEBUG
  handlers: [console]

Вот файл python.

import logging
import yaml
from flask import Flask

app = Flask(__name__)

def logSetter(logger_name:str) -> logging:
    with open("logging_config.yml", 'r') as f:
        config = yaml.safe_load(f)
    logging.config.dictConfig(config)
    logger = logging.getLogger(logger_name)
    return logger

logger=logSetter(logger_name="test_api")

@app.route("/api/test")
def hello():
     app.logger.info("hey from api")
     return "Hello from Python!"

Надеюсь, это поможет.

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

Потребовалось всего мгновение, чтобы придумать надежное воспроизведение: использование hey для отправки 100 одновременных запросов к последней версии Gunicorn (20.0.4) с использованием gthread worker:

$ hey -n 100 -c 100 https://127.0.0.1:8000

`` ''
$ gunicorn app: app -k gthread --certfile = ... --keyfile = ...
...
[2020-07-11 19:10:58 +0000] [3628247] [ERROR] Запрос обработки ошибки сокета.
Отслеживание (последний вызов последний):
вернуть self._sslobj.read (len)
OSError: [Errno 0] Ошибка


Using a Debian 9 / Linux 4.14.67 based environment.

The WSGI app to reproduce need not be anything beyond:
```python
# app.py
def app(environ, start_response):
    start_response("200 OK", [])
    return ""

В случае, если это тоже поможет!

Если основная причина на самом деле https://bugs.python.org/issue31122 :

  • 4 марта было отправлено исправление (python / cpython # 18772), но оно все еще не было подтверждено основным разработчиком. Может быть, специалист по сопровождению Gunicorn, оставивший комментарий там или к BPO-31122, в котором говорится, что он влияет на пользователей Gunicorn, поможет?
  • Gunicorn все равно придется работать над этим для поддерживаемых версий Python, предшествующих выпуску этого исправления. Стоит также спросить, есть ли в том же комментарии обходной путь?

Это также влияет на мою организацию в продакшене.

Я заметил, что исправление обнаружено в ветках 3.8 и 3.9, но они рассматривают <= 3.7 EOL, и мы все еще как бы застряли на 3.6. Есть ли в настоящее время известное решение этой проблемы в самом Gunicorn? Есть что-нибудь запланированное?

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

В дополнение к комментарию jriddy об отсутствии намерения выполнять бэкпорт до 3.8, если у кого-то еще есть эта проблема, также обратите внимание, что исправление настроено для включения в CPython 3.8.6 .

Возникли проблемы с определением того, откуда исходит эта трассировка - в моем случае, используя gevent качестве сервера приложений WSGI напрямую, поэтому предполагая, что это вызов журнала где-то в gevent / greenlet, но пока не могу его найти. Для Gunicorn это происходит здесь, для синхронных рабочих:

https://github.com/benoitc/gunicorn/blob/e636bf81989bb833d2b99104feb11e86c3f2c43a/gunicorn/workers/sync.py#L150

В случае с Gunicorn, если вас беспокоит только шум в журналах, возможно, вы сможете сделать что-то вроде:

import logging

class HandshakeFilter(logging.Filter):
    # example: https://docs.python.org/3/howto/logging-cookbook.html
    # I have not tested this
    def filter(self, record):
        return "socket error processing request" in record.msg.casefold()

logging.getLogger("gunicorn").addFilter(HandshakeFilter())

Связанная проблема gevent: https://github.com/gevent/gevent/issues/1671

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