Gunicorn: OSError: [Errno 0] Kesalahan

Dibuat pada 8 Mei 2018  ·  30Komentar  ·  Sumber: benoitc/gunicorn

Saya menjalankan aplikasi
gunicorn -w 2 -b ' localhost:8585 ' --timeout=200 --certfile=crt.crt --keyfile=key.key service:app

Dan saya mendapatkan yang berikut, tetapi saya tidak selalu mendapatkan jawaban seperti itu, sebagian besar permintaan ditangani dengan benar, tetapi terkadang terjadi kesalahan

[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

Komentar yang paling membantu

Hmm, setelah beberapa penelitian tambahan, tampaknya ini sebenarnya adalah bug dalam cara pustaka python ssl menangani EOF yang compang-camping di linux: https://bugs.python.org/issue31122

Semua 30 komentar

Dari ingatan saya, kesalahan ini terjadi ketika klien mencoba terhubung tanpa SSL. Mungkinkah itu yang terjadi pada Anda?

Saya melihat posting Anda tentang masalah lain yang saya tutup. Saya minta maaf jika komentar saya bukan penyebabnya.

Apakah ada pola di mana permintaan gagal dengan cara ini?

@usmetanina klien seperti apa yang terhubung ke Gunicorn juga? APAKAH Anda memiliki opsi SSL yang digunakan secara eksplisit untuk menghubungkannya?

apakah ini sudah terpecahkan? @usmetanina , karena saya memiliki masalah yang persis sama

@benoitc Saya sering melihat kesalahan persis @usmetanina menggunakan python3.6 dan gunicorn 19.9.0 .

Saya menggunakan informasi di bawah ini untuk memulai gunicorn dengan aplikasi labu yang berjalan di dalam wadah buruh pelabuhan.

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

File konfigurasi terlihat seperti ini (domain-with-cert.com tentu saja adalah pengganti untuk nama domain yang sebenarnya):

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'

Setiap pemikiran tentang debugging ini akan sangat membantu. Jika Anda membutuhkan info lebih lanjut, beri tahu saya.

@willpatera , lihat komentar saya:

Dari ingatan saya, kesalahan ini terjadi ketika klien mencoba terhubung tanpa SSL. Mungkinkah itu yang terjadi pada Anda?

@tilgovi saya melihat komentar di atas. Saya cukup yakin bahwa klien terhubung melalui SSL. Ada saran debug?

@willpatera Saya akan mengatakan, nyalakan log akses dan lihat apakah Anda dapat menentukan permintaan mana yang menyebabkan masalah. Jika Anda memiliki proxy terbalik di depan gunicorn, pastikan ia memiliki log akses sehingga Anda mungkin dapat melihat permintaan mana yang menyebabkan kesalahan dengan gunicorn meskipun gunicorn tidak pernah mencatatnya.

@tilgovi Saya mengalami masalah yang sama. Harus mengedit sedikit informasi berikut karena salah:
Permintaan yang dilakukan kepada gunicorn selalu merupakan permintaan yang sama persis (tetapi dengan badan yang berbeda). Jadi tidak ada keraguan bahwa itu adalah https dan bukan http.
Apa yang saya perhatikan adalah bahwa itu selalu terjadi ketika jumlah permintaan naik. Ketika server sedang sibuk, tampaknya ada masalah dalam menangani permintaan dengan benar.

Mungkin ini ada hubungannya dengan para pekerja atau semacamnya? Jika Anda memiliki saran konfigurasi, saya dengan senang hati ingin mengujinya.

Hai guys, saya masih mencari cara untuk menyelesaikan ini. Saat ini satu-satunya pilihan yang kami miliki adalah menurunkan versi ke HTTP biasa, yang tidak layak sama sekali.

Saya pernah menyaksikan hal yang sama. Memiliki server produksi yang menjalankan Gunicorn + Flask (di belakang penyeimbang beban) yang berfungsi dengan baik selama berbulan-bulan, lalu tiba-tiba setiap permintaan menghasilkan kesalahan ini hingga saya memulai ulang 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

Tidak ada dalam log sebelum kesalahan ini yang menunjukkan pemicunya.

Ini dengan Gunicorn 19.9.0 berjalan dengan 3 pekerja di server berinti tunggal.

Karena ini adalah pertama kalinya saya melihat masalah ini, saya tidak bisa berjanji untuk mereproduksinya. Namun, jika ada jenis logging atau kode diagnostik lain yang ingin saya tambahkan di server kami yang mungkin memberikan beberapa informasi berguna jika hal ini terjadi lagi, saya setuju.

Apakah LB Anda memanggil titik akhir tertentu? Bagaimana cara menjawab permintaan LB?

Ketika saya mengatakan "Load Balancer", saya seharusnya mengatakan CDN atau lapisan caching. Khususnya: ini adalah Amazon Cloudfront. Itu hanya meneruskan permintaan ke server Gunicorn kami (berjalan pada instans EC2) dan menyimpan hasil untuk sementara waktu.

hrm tidakkah seharusnya amazon cloudfront menghentikan permintaan ssl untuk Anda? @ExplodingCabbage . Mengapa gunicorn harus mendengarkan ssl di belakang?

@benoitc Jadi, ada dua lapisan dengan SSL yang terlibat dalam arsitektur. Anggota publik terhubung ke situs web kami melalui domain CloudFront kami melalui HTTPS, dan kemudian CloudFront membuat permintaan ke node backend kami yang menjalankan Gunicorn, juga menggunakan HTTPS (dengan nama domain dan sertifikat yang berbeda), menyimpan hasil cache, dan menyajikannya ke publik.

Saya kira mungkin Anda bertanya-tanya apa gunanya menggunakan SSL untuk permintaan internal kedua itu? Ini tentu saja tidak ada gunanya (walaupun mungkin tidak - itu menghentikan Amazon mengintip komunikasi kami di jaringan internal mereka, dan ada juga alasan peraturan saya tidak akan membahas mengapa, mengingat industri perusahaan saya, kami mungkin perlu memastikan bahwa kami punya enkripsi sepanjang jalan di sepanjang pipa). Entah sia-sia atau tidak, kami melakukannya. \_(ツ)_/¯

mungkinkah cloudfront mengirim ke titik akhir Anda permintaan HTTP biasa? Jika Anda memiliki akses ke log cloudfront, Anda seharusnya dapat melihatnya.

@benoitc Saya tidak berpikir CloudFront memperlihatkan log apa pun yang akan berguna, tetapi saya yakin itu tidak mencoba terhubung melalui HTTP, karena:

  • Distribusi kami dikonfigurasi di konsol CloudFront untuk terhubung ke asal Gunicorn melalui "Hanya HTTPS"
  • Gunicorn tidak mendengarkan di port 80
  • Jika saya mencoba terhubung ke server backend kami melalui HTTP (termasuk memaksa HTTP pada port 443) itu tidak mereproduksi OSError yang dikutip di atas
  • Ketika saya mendapatkan OSError yang dikutip di atas, memulai ulang Gunicorn di server backend langsung memperbaiki masalah, yang menunjuk ke sesuatu yang salah di ujung Gunicorn, bukan ujung Cloudfront

@ExplodingCabbage ok saya akan melihatnya setelah 20.0.1 keluar. Satu hal terakhir, versi Python mana yang Anda gunakan?

3.6.8

Saya menyadari bahwa saya meninggalkan detail dari cerita saya di atas: sebelum memulai ulang Gunicorn, saya juga memperbarui sertifikat SSL yang digunakan Gunicorn dengan LetsEncrypt. Saya tidak berpikir untuk menyebutkan ini karena saya telah salah menyimpulkan kemarin bahwa tidak mungkin sertifikat akan kedaluwarsa pada hari kesalahan dimulai dan bahwa pembaruan sertifikat sebenarnya tidak relevan untuk memperbaiki masalah.

Namun, dari memeriksa beberapa log, saya sekarang menyadari bahwa kesalahan sebenarnya dimulai pada hari sertifikat sebelumnya akan kedaluwarsa.

Masih ada beberapa misteri di sini, dan beberapa ruang potensial untuk perbaikan (apa sebenarnya arti kesalahan ini, dan mengapa Gunicorn tidak dapat memberikan pesan yang lebih berguna?), tetapi narasi yang saya berikan sebelumnya - di mana kesalahan ini dimulai secara tiba-tiba tanpa penyebab yang jelas - tidak benar. Saya kira CloudFront memutuskan koneksi sebagai tanggapan atas melihat sertifikat kedaluwarsa dari server Gunicorn, dan bahwa Gunicorn, alih-alih dapat memahaminya dan melaporkannya secara bermakna, memungkinkan OSError tanpa pesan muncul.

Saya minta maaf karena tidak membuat bebek saya berturut-turut sebelum melaporkan. Di sisi lain, mungkin ini akan membuatnya lebih mudah untuk mereproduksi pengecualian ini sesuka hati jika Anda ingin mencoba dan menangani skenario dengan lebih elegan.

@ExplodingCabbage oh itu cukup menarik, itu harus direproduksi di beberapa titik. Terima kasih atas detail tambahannya!

Saya baru saja mengalami masalah yang sama dan saya agak yakin itu adalah konsekuensi dari semacam kelelahan sumber daya.

Bagi saya itu dipicu oleh lupa batas waktu pada panggilan pemblokiran dan permintaan yang menumpuk.

HTH

Halo! Saya mengalami masalah persis ini. Saya memiliki layanan gunicorn/flask yang berjalan di kluster ECS di belakang penyeimbang beban jaringan. Beberapa spesifikasi versi:

python    - 3.7.4
gunicorn  - 19.9.0
flask     - 1.0.4

Layanan ini dapat menanggapi permintaan yang datang dari klien menggunakan TLS tanpa masalah, namun log saya dibanjiri dengan OSErrors. Sejauh yang saya tahu, ini dihasilkan dari permintaan pemeriksaan kesehatan yang berasal dari penyeimbang beban (TCP).

Saya dapat mereproduksi kesalahan secara lokal dengan membuka dan menutup koneksi TCP secara manual pada port mendengarkan (8000 dalam kasus ini):

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

Yang mengakibatkan kesalahan berikut dilemparkan:

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

Semoga ini membantu!

Hmm, setelah beberapa penelitian tambahan, tampaknya ini sebenarnya adalah bug dalam cara pustaka python ssl menangani EOF yang compang-camping di linux: https://bugs.python.org/issue31122

Seperti yang disebutkan oleh @shevisjohnson jika Anda menjalankan "nc -vz hostname port_no" kesalahan ini muncul.
Kami dapat menekan kesalahan ini dalam file log dengan menggunakan mekanisme logging di bawah ini.

$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]

Ini file pythonnya.

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!"

Semoga membantu.

Kami sesekali mengamati beberapa aplikasi Gunicorn gagal dengan kesalahan ini dalam produksi saat sedang dimuat secara bersamaan.

Hanya butuh beberapa saat untuk menghasilkan reproduksi yang andal: menggunakan hey untuk mengirim 100 permintaan bersamaan ke Gunicorn terbaru (20.0.4) menggunakan gthread worker:

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

```
$ aplikasi gunicorn
...
[2020-07-11 19:10:58 +0000] [3628247] [ERROR] Permintaan pemrosesan kesalahan soket.
Traceback (panggilan terakhir terakhir):
kembalikan diri._sslobj.read(len)
OSError: [Errno 0] Kesalahan


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 ""

Dalam hal ini membantu juga!

Jika akar masalahnya sebenarnya https://bugs.python.org/issue31122 :

  • Ada perbaikan yang dikirimkan pada 4 Maret (python/cpython#18772), tetapi masih belum diakui oleh pengembang inti. Mungkin pengelola Gunicorn meninggalkan komentar di sana atau di BPO-31122 yang mengatakan bahwa itu memengaruhi pengguna gunicorn akan membantu?
  • Gunicorn masih perlu mengatasi ini untuk versi Python yang didukung sebelum perbaikan itu dirilis. Layak juga ditanyakan apakah ada solusi dalam komentar yang sama?

Ini mempengaruhi organisasi saya di prod juga.

Saya perhatikan bahwa perbaikan bug mendarat di cabang 3,8 dan 3,9, tetapi mereka mempertimbangkan <= 3,7 EOL dan kami masih terjebak di 3,6 untuk saat ini. Apakah ada solusi yang diketahui untuk masalah ini saat ini di gunicorn itu sendiri? Apakah ada yang direncanakan?

Kami sedang mencari tahu apa yang bisa memanggil layanan begitu banyak untuk memicu ini, tapi saya hanya mencoba mencari tahu apa yang bisa dilakukan, karena ini menghasilkan lonjakan sumber daya yang besar pada node yang terpengaruh.

Selain komentar jriddy mengenai tidak ada niat untuk melakukan backport sebelum 3.8, jika ada orang lain yang mengalami masalah ini, perhatikan juga bahwa perbaikan diatur untuk disertakan dalam CPython 3.8.6 .

Mengalami kesulitan mengatakan dengan tepat dari mana traceback ini berasal - dalam kasus saya, menggunakan gevent sebagai server aplikasi WSGI secara langsung, jadi dengan asumsi itu adalah panggilan logging di suatu tempat di dalam gevent/greenlet, tetapi belum dapat menemukannya. Untuk Gunicorn, itu terjadi di sini, untuk pekerja sinkron:

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

Dalam kasus Gunicorn, jika Anda hanya khawatir tentang kebisingan di log, mungkin dapat melakukan sesuatu seperti:

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())

Masalah gevent terkait: https://github.com/gevent/gevent/issues/1671

Apakah halaman ini membantu?
0 / 5 - 0 peringkat