Я запускаю приложение
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
Насколько мне известно, эта ошибка возникает, когда клиент пытается подключиться без 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, поскольку:
@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!"
Надеюсь, это поможет.
Потребовалось всего мгновение, чтобы придумать надежное воспроизведение: использование 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 :
Это также влияет на мою организацию в продакшене.
Я заметил, что исправление обнаружено в ветках 3.8 и 3.9, но они рассматривают <= 3.7 EOL, и мы все еще как бы застряли на 3.6. Есть ли в настоящее время известное решение этой проблемы в самом Gunicorn? Есть что-нибудь запланированное?
Мы изучаем, что могло вызвать эту службу так часто, чтобы вызвать это, но я просто пытаюсь выяснить, что можно сделать, поскольку это приводит к огромным скачкам ресурсов на затронутых узлах.
В дополнение к комментарию jriddy об отсутствии намерения выполнять бэкпорт до 3.8, если у кого-то еще есть эта проблема, также обратите внимание, что исправление настроено для включения в CPython 3.8.6 .
Возникли проблемы с определением того, откуда исходит эта трассировка - в моем случае, используя gevent
качестве сервера приложений WSGI напрямую, поэтому предполагая, что это вызов журнала где-то в gevent / greenlet, но пока не могу его найти. Для Gunicorn это происходит здесь, для синхронных рабочих:
В случае с 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
Самый полезный комментарий
Хм, после некоторых дополнительных исследований кажется, что на самом деле это может быть ошибка в том, как библиотека python
ssl
обрабатывает рваные EOF в Linux: https://bugs.python.org/issue31122