je lance l'application
gunicorn -w 2 -b ' localhost:8585 ' --timeout=200 --certfile=crt.crt --keyfile=key.key service:app
Et j'obtiens ce qui suit, mais je n'obtiens pas toujours une telle réponse, la plupart des demandes sont traitées correctement, mais parfois une erreur se produit
[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
De mémoire, cette erreur se produit lorsqu'un client essaie de se connecter sans SSL. Serait-ce le cas pour vous ?
Je vois votre message sur l'autre sujet que j'ai fermé. Mes excuses si mon commentaire n'est pas la cause.
Existe-t-il un modèle auquel les requêtes échouent de cette façon ?
@usmetanina quel type de clients se connecte également à Gunicorn ? Avez-vous des options SSL utilisées explicitement pour vous y connecter ?
c'est déjà résolu ? @usmetanina , car j'ai exactement le même problème
@benoitc Je vois @usmetanina « est une erreur exacte fréquemment en utilisant python3.6 et gunicorn 19.9.0
.
J'utilise les informations ci-dessous pour démarrer gunicorn avec une application de flacon s'exécutant dans un conteneur Docker.
gunicorn --workers=3 --bind=0.0.0.0:8000 --config=gunicorn_config.py --preload main
Le fichier de configuration ressemble à ceci (domain-with-cert.com est bien sûr un espace réservé pour le nom de domaine réel) :
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'
Toute réflexion sur le débogage serait utile. Si vous avez besoin de plus d'informations, faites le moi savoir.
@willpatera , voir mon commentaire :
De mémoire, cette erreur se produit lorsqu'un client essaie de se connecter sans SSL. Serait-ce le cas pour vous ?
@tilgovi J'ai vu le commentaire ci-dessus. Je suis à peu près sûr que le client se connecte via SSL. Des suggestions de débogage ?
@willpatera Je dirais, activez les journaux d'accès et voyez si vous pouvez déterminer quelle demande est à l'origine du problème. Si vous avez un proxy inverse devant gunicorn, assurez-vous qu'il dispose de journaux d'accès afin que vous puissiez peut-être voir quelle requête provoque une erreur avec gunicorn même si gunicorn ne l'enregistre jamais.
@tilgovi J'ai les mêmes problèmes. J'ai dû modifier un peu les informations suivantes car elles étaient incorrectes :
La demande qui est faite à gunicorn est toujours exactement la même demande (mais avec un corps différent). Il ne fait donc aucun doute qu'il s'agit de https et non de http.
Ce que je remarque, c'est que cela se produit toujours lorsque le nombre de demandes augmente. Lorsque le serveur est occupé, il semble avoir du mal à traiter correctement les demandes.
Peut-être que cela a à voir avec les travailleurs ou quelque chose comme ça? Si vous avez des suggestions de configuration, je serais ravi de les tester.
Salut les gars, je cherche toujours un moyen de résoudre ce problème. Actuellement, la seule option dont nous disposons est de rétrograder en HTTP simple, ce qui n'est pas du tout faisable.
J'ai été témoin de la même chose. J'avais un serveur de production exécutant Gunicorn + Flask (derrière un équilibreur de charge) qui fonctionnait correctement pendant des mois, puis soudain, chaque requête a généré cette erreur jusqu'à ce que je redémarre 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
Rien dans les journaux précédant ces erreurs n'indique ce que le déclencheur aurait pu être.
C'était avec Gunicorn 19.9.0 exécuté avec 3 travailleurs sur un serveur monocœur.
Comme c'est la première fois que je vois ce problème, je ne peux pas promettre que je le reproduirai un jour. Cependant, s'il existe un type de code de journalisation ou de diagnostic que quelqu'un aimerait que j'ajoute sur notre serveur qui pourrait fournir des informations utiles au cas où cela se reproduirait, je suis tout ouïe.
Votre LB appelle-t-il un point de terminaison spécifique ? Comment répond-il à la requête LB ?
Quand j'ai dit "Load Balancer", j'aurais vraiment dû dire CDN ou couche de mise en cache. Plus précisément : c'est Amazon Cloudfront. Il transmet simplement les demandes à notre serveur Gunicorn (s'exécutant sur une instance EC2) et met en cache les résultats pendant un certain temps.
hrm ne devrait-il pas amazon cloudfront terminer la demande ssl pour vous ? @ExplodingCabbage . Pourquoi gunicorn doit écouter sur ssl derrière ?
@benoitc Donc, il y a deux couches avec SSL impliquées dans l'architecture. Les membres du public se connectent à notre site Web via notre domaine CloudFront via HTTPS, puis CloudFront fait une demande à notre nœud principal exécutant Gunicorn, également en utilisant HTTPS (avec un nom de domaine et un certificat différents), met en cache le résultat et le sert au Publique.
Je suppose que vous vous demandez peut-être quel est l'intérêt d'utiliser SSL pour cette seconde demande interne? On peut certainement soutenir que c'est inutile (bien que peut-être pas - cela empêche Amazon d'espionner nos communications dans leur réseau interne, et il y a aussi des raisons réglementaires pour lesquelles je n'expliquerai pas pourquoi, étant donné le secteur de mon entreprise, nous devrons peut-être nous assurer que nous avons chiffrement tout au long du pipeline). Que ce soit inutile ou non, nous le faisons. \_(ツ)_/¯
se pourrait-il que cloudfront envoie à votre point de terminaison une simple requête HTTP ? Si vous avez accès aux journaux cloudfront, vous devriez pouvoir les voir.
@benoitc Je ne pense pas que CloudFront expose des journaux qui seraient utiles, mais je suis sûr qu'il n'essayait pas de se connecter via HTTP, car :
@ExplodingCabbage ok, j'y
3.6.8
Je me rends compte que j'ai omis un détail de mon histoire ci-dessus : avant de redémarrer Gunicorn, j'ai également mis à jour le certificat SSL que Gunicorn utilise avec LetsEncrypt. Je n'avais pas pensé à le mentionner car j'avais conclu à tort hier qu'il n'y avait aucun moyen qu'un certificat ait expiré le jour où les erreurs ont commencé et que la mise à jour du certificat n'avait en fait pas été pertinente pour résoudre le problème.
Cependant, en vérifiant certains journaux, je me rends compte maintenant que les erreurs ont en fait commencé le jour où un certificat précédent devait expirer.
Il y a encore un peu de mystère ici, et une marge d'amélioration potentielle (que signifie exactement cette erreur, et pourquoi Gunicorn ne peut-il pas donner un message plus utile ?), mais le récit que j'ai donné auparavant - dans lequel cette erreur a commencé à l'improviste sans cause apparente - n'est pas juste. Je suppose que CloudFront mettait fin à la connexion en réponse à la vue d'un certificat expiré du serveur Gunicorn, et que Gunicorn, plutôt que de pouvoir le comprendre et le signaler de manière significative, laisse apparaître une erreur OSE sans message.
Je m'excuse de ne pas avoir aligné mes canards avant de signaler. D'un autre côté, cela facilitera peut-être la reproduction à volonté de cette exception si vous voulez essayer de gérer le scénario avec plus d'élégance.
@ExplodingCabbage oh c'est assez intéressant, ça devrait être reproductible à un moment donné alors. Merci pour les détails supplémentaires !
Je viens de rencontrer le même problème de manière reproductible et je suis un peu confiant que c'est la conséquence d'une sorte d'épuisement des ressources.
Pour moi, cela a été déclenché par l'oubli d'un délai d'attente sur un appel bloquant et les demandes s'accumulent.
HTH
Salut! Je rencontre exactement ce problème. J'ai un service gunicorn/flask exécuté sur un cluster ECS derrière un équilibreur de charge réseau. Quelques spécificités de version :
python - 3.7.4
gunicorn - 19.9.0
flask - 1.0.4
Le service est capable de répondre aux demandes provenant d'un client utilisant TLS sans problème, mais mes journaux sont inondés d'erreurs OSE. Pour autant que je sache, ceux-ci résultent des demandes de vérification de l'état provenant de l'équilibreur de charge (TCP).
J'ai pu reproduire l'erreur localement en ouvrant et fermant une connexion TCP manuellement sur le port d'écoute (8000 dans ce cas) :
$ nc -vz 127.0.0.1 8000
localhost [127.0.0.1] 8000 (irdmi) open
Ce qui a donné lieu à l'erreur suivante :
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
J'espère que cela t'aides!
Hmm, bien après quelques recherches supplémentaires, il semble que cela puisse en fait être un bogue dans la façon dont la bibliothèque python ssl
gère les EOF en lambeaux sur Linux : https://bugs.python.org/issue31122
Comme mentionné par @shevisjohnson, si vous exécutez "nc -vz hostname port_no", cette erreur apparaît.
Nous pouvons supprimer cette erreur dans le fichier journal en utilisant le mécanisme de journalisation ci-dessous.
$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]
Voici le fichier 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!"
J'espère que ça aide.
Il n'a fallu qu'un instant pour arriver à une reproduction fiable : en utilisant hey
pour envoyer 100 requêtes simultanées au dernier Gunicorn (20.0.4) en utilisant le 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] [ERREUR] Demande de traitement d'erreur de socket.
Traceback (appel le plus récent en dernier) :
return self._sslobj.read(len)
OSError : [Errno 0] Erreur
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 ""
Au cas où cela aiderait aussi !
Si la cause première est en fait https://bugs.python.org/issue31122 :
Cela affecte également mon organisation en prod.
J'ai remarqué que la correction de bogues a atterri dans les branches 3.8 et 3.9, mais ils envisagent <= 3.7 EOL et nous sommes toujours un peu bloqués sur 3.6 pour le moment. Existe-t-il actuellement une solution de contournement connue à ce problème dans gunicorn lui-même ? Y a-t-il quelque chose de prévu ?
Nous examinons ce qui pourrait tant appeler le service pour déclencher cela, mais j'essaie simplement de comprendre ce qui pourrait être fait, car cela entraîne d'énormes pics de ressources sur les nœuds affectés.
En plus du commentaire de jriddy concernant l'absence d'intention de rétroporter avant la version 3.8, si quelqu'un d'autre rencontre ce problème, notez également que le correctif est défini pour être inclus dans CPython 3.8.6 .
Avoir du mal à dire exactement d'où émane ce retraçage - dans mon cas, en utilisant directement gevent
comme serveur d'applications WSGI, donc en supposant qu'il s'agit d'un appel de journalisation quelque part dans gevent/greenlet, mais je ne peux pas le trouver pour le moment. Pour Gunicorn, cela se passe ici, pour les travailleurs synchrones :
Dans le cas de Gunicorn, si vous êtes simplement préoccupé par le bruit dans les journaux, vous pourrez peut-être faire quelque chose comme :
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())
Problème gevent connexe : https://github.com/gevent/gevent/issues/1671
Commentaire le plus utile
Hmm, bien après quelques recherches supplémentaires, il semble que cela puisse en fait être un bogue dans la façon dont la bibliothèque python
ssl
gère les EOF en lambeaux sur Linux : https://bugs.python.org/issue31122