Gunicorn: OSError: خطأ [Errno 0]

تم إنشاؤها على ٨ مايو ٢٠١٨  ·  30تعليقات  ·  مصدر: benoitc/gunicorn

أنا أقوم بتشغيل التطبيق
gunicorn -w 2 -b ' localhost: 8585 ' - timeout = 200 --certfile = crt.crt --keyfile = key.key service: app

وأحصل على ما يلي ، لكنني لا أحصل دائمًا على مثل هذه الإجابة ، يتم التعامل مع معظم الطلبات بشكل صحيح ، ولكن في بعض الأحيان يحدث خطأ

[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 مع EOFs الممزقة على نظام Linux: https://bugs.python.org/issue31122

ال 30 كومينتر

من ذاكرتي ، يحدث هذا الخطأ عندما يحاول العميل الاتصال بدون SSL. هل يمكن أن يكون هذا هو الحال بالنسبة لك؟

أرى رسالتك حول المشكلة الأخرى التي أغلقتها. اعتذاري إذا لم يكن تعليقي هو السبب.

هل هناك نمط تفشل فيه الطلبات بهذه الطريقة؟

usmetanina ما نوع العملاء الذين يتصلون بـ Gunicorn أيضًا؟ هل لديك أي خيارات SSL مستخدمة صراحة للاتصال به؟

هل تم حل هذا بالفعل؟ usmetanina ، لأن لدي نفس المشكلة بالضبط

benoitc أرى خطأusmetanina الدقيق كثيرًا باستخدام python3.6 و gunicorn 19.9.0 .

أستخدم المعلومات أدناه لبدء تشغيل برنامج gunicorn باستخدام تطبيق flask يعمل داخل حاوية عامل إرساء.

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؟

عندما قلت "Load Balancer" ، كان علي حقًا أن أقول CDN أو طبقة التخزين المؤقت. على وجه التحديد: إنها Amazon Cloudfront. يقوم فقط بإعادة توجيه الطلبات إلى خادم Gunicorn الخاص بنا (يعمل على مثيل EC2) ويخزن النتائج مؤقتًا لفترة من الوقت.

ألا يجب على شركة أمازون كلاود فرونت إنهاء طلب SSL نيابةً عنك؟ تضمين التغريدة لماذا يجب على Gunicorn الاستماع على ssl behind؟

benoitc إذن ، هناك طبقتان مع SSL متضمنة في البنية. يتصل أعضاء الجمهور بموقعنا على الويب عبر مجال CloudFront الخاص بنا عبر HTTPS ، ثم تقدم CloudFront طلبًا إلى العقدة الخلفية التي تشغل Gunicorn ، باستخدام HTTPS أيضًا (باسم مجال وشهادة مختلفين) ، وتخزين النتيجة مؤقتًا ، وتقديمها إلى عام.

أعتقد أنك ربما تتساءل ما هو الهدف من استخدام طبقة المقابس الآمنة للطلب الداخلي الثاني؟ من المؤكد أنه لا جدوى من الجدال (على الرغم من أنه قد لا يكون كذلك - فهو يوقف تطفل أمازون على اتصالاتنا في شبكتهم الداخلية ، وهناك أيضًا أسباب تنظيمية لن أخوض في السبب ، نظرًا لصناعة شركتي ، قد نحتاج إلى التأكد من حصولنا على التشفير على طول خط الأنابيب). سواء كان ذلك بلا معنى أم لا ، نحن نفعل ذلك. ¯ \ _ (ツ) _ / ¯

هل يمكن أن تكون واجهة Cloudfront ترسل طلب HTTP عاديًا إلى نقطة النهاية الخاصة بك؟ إذا كان لديك وصول إلى سجلات cloudfront ، فيجب أن تكون قادرًا على رؤيتها.

benoitc لا أعتقد أن CloudFront تعرض أي سجلات قد تكون مفيدة ، لكنني متأكد من أنها لم تكن تحاول الاتصال عبر HTTP ، حيث:

  • تم تكوين التوزيع الخاص بنا في وحدة تحكم CloudFront للاتصال بأصل Gunicorn عبر "HTTPS فقط"
  • Gunicorn لا يستمع على المنفذ 80
  • إذا حاولت الاتصال بخادم الواجهة الخلفية لدينا أكثر من HTTP (بما في ذلك إجبار HTTP على المنفذ 443) أنه لا يتم إنتاج OSError المذكورة أعلاه
  • عندما كنت أحصل على خطأ OSE المقتبس أعلاه ، أدت إعادة تشغيل Gunicorn على خادم الواجهة الخلفية إلى إصلاح المشكلة على الفور ، مما يشير إلى خطأ ما في نهاية Gunicorn ، وليس نهاية Cloudfront

ExplodingCabbage حسنًا ،

3.6.8

أدرك أنني تركت بعض التفاصيل من قصتي أعلاه: قبل إعادة تشغيل Gunicorn ، قمت أيضًا بتحديث شهادة SSL التي يستخدمها Gunicorn مع LetsEncrypt. لم أفكر في ذكر هذا لأنني خلصت بشكل خاطئ بالأمس إلى أنه لا توجد طريقة لانتهاء صلاحية الشهادة في اليوم الذي بدأت فيه الأخطاء وأن تحديث الشهادة لم يكن في الواقع ذا صلة بإصلاح المشكلة.

ومع ذلك ، من خلال فحص بعض السجلات ، أدرك الآن أن الأخطاء بدأت في الواقع في اليوم الذي كان من المقرر أن تنتهي صلاحية الشهادة السابقة.

لا يزال هناك بعض الغموض هنا ، وهناك مجال محتمل للتحسين (ما الذي يشير إليه هذا الخطأ بالضبط ، ولماذا لا يستطيع Gunicorn تقديم رسالة أكثر فائدة؟) ، ولكن السرد الذي قدمته من قبل - حيث بدأ هذا الخطأ فجأة بدون سبب واضح - ليس صحيحًا. أعتقد أن CloudFront كان ينهي الاتصال ردًا على رؤية شهادة منتهية الصلاحية من خادم Gunicorn ، وأن Gunicorn ، بدلاً من أن يكون قادرًا على فهم ذلك والإبلاغ عنه بشكل هادف ، يسمح لظهور خطأ OSE بلا رسائل.

أعتذر عن عدم وجود بطي على التوالي قبل الإبلاغ. من ناحية أخرى ، ربما سيسهل هذا إعادة إنتاج هذا الاستثناء حسب الرغبة إذا كنت ترغب في محاولة التعامل مع السيناريو بشكل أكثر أناقة.

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 مع EOFs الممزقة على نظام Linux: https://bugs.python.org/issue31122

كما ذكر shevisjohnson إذا قمت بتنفيذ "nc -vz hostname port_no" يظهر هذا الخطأ.
يمكننا منع هذا الخطأ في ملف السجل باستخدام آلية التسجيل أدناه.

$ القط 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]

ها هو ملف بيثون.

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 :

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

""
تطبيق gunicorn $
...
[2020-07-11 19:10:58 +0000] [3628247] [خطأ] طلب معالجة خطأ مأخذ التوصيل.
Traceback (آخر مكالمة أخيرة):
عودة self._sslobj.read (لين)
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 بشأن عدم وجود نية لـ backport قبل 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 التقييمات