2008-12-20 10 views
28

Estamos desarrollando un servicio web de Python y un sitio web de cliente en paralelo. Cuando hacemos una petición HTTP desde el cliente al servicio, una llamada plantea sistemáticamente una socket.error en socket.py, en la lectura:104, error de socket de 'Restablecimiento de conexión por igual' o ¿Cuándo el cierre de un socket da como resultado un RST en vez de un FIN?

(104, 'Connection reset by peer')

Cuando escucho con Wireshark, el "bueno" y "malo "las respuestas se ven muy similares:

  • Debido al tamaño del encabezado OAuth, la solicitud se divide en dos paquetes. El servicio responde a ambos con ACK
  • El servicio envía la respuesta, un paquete por encabezado (HTTP/1.0 200 OK, luego el encabezado de fecha, etc.). El cliente responde a cada uno con ACK.
  • (Buena solicitud) el servidor envía un FIN, ACK. El cliente responde con un FIN, ACK. El servidor responde ACK.
  • (Solicitud incorrecta) el servidor envía un RST, ACK, el cliente no envía una respuesta TCP, el socket.error se genera en el lado del cliente.

Tanto el servicio web como el cliente se ejecutan en una caja de Gentoo Linux x86-64 ejecutando glibc-2.6.1. Estamos usando Python 2.5.2 dentro del mismo virtual_env.

El cliente es una aplicación Django 1.0.2 que llama a httplib2 0.4.0 para realizar solicitudes. Estamos firmando solicitudes con el algoritmo de firma OAuth, con el token OAuth siempre configurado en una cadena vacía.

El servicio ejecuta Werkzeug 0.3.1, que está utilizando el servidor wsgiref.simple_server de Python. Ejecuté la aplicación WSGI a través de wsgiref.validator sin problemas.

Parece que esto debería ser fácil de depurar, pero cuando rastreamos a través de una buena solicitud en el lado del servicio, se ve como la solicitud incorrecta, en la función socket._socketobject.close(), convirtiendo los métodos delegados en métodos ficticios. Cuando el método send o sendto (no se puede recordar) se apaga, se envía FIN o RST y el cliente comienza a procesar.

"Connection reset by peer" parece culpar al servicio, pero tampoco confío en httplib2. ¿Puede el cliente tener la culpa?

** Además depuración - Parece que el servidor en Linux **

Tengo un MacBook, así que traté de ejecutar el servicio en uno y el sitio web del cliente por el otro. El cliente Linux llama al servidor OS X sin el error (FIN ACK). El cliente de OS X llama al servicio de Linux con el error (RST ACK, y a (54, 'Restablecimiento de conexión por pares')). Entonces, parece que es el servicio que se ejecuta en Linux. ¿Es x86_64? Un mal glibc? wsgiref? Todavía estás ...

** La prueba adicional - wsgiref ve escamosa **

Hemos ido a la producción con Apache y mod_wsgi, y se repone de conexión han desaparecido. Vea mi respuesta a continuación, pero mi consejo es que registre el restablecimiento de la conexión y vuelva a intentarlo. Esto permitirá que su servidor funcione correctamente en modo de desarrollo y en producción sólida.

+0

La pregunta es, en efecto por qué el servidor envía los reques RST. El cliente debe restablecer la conexión e informar el mensaje 'Restablecimiento de conexión por pares'. Así que creo que está en el camino correcto –

Respuesta

15

He tenido este problema. Ver The Python "Connection Reset By Peer" Problem.

Es muy probable que tenga problemas pequeños de sincronización basados ​​en Python Global Interpreter Lock.

Puede (a veces) corregir esto con un time.sleep(0.01) colocado estratégicamente.

"¿Dónde?" usted pregunta. Me gana La idea es proporcionar una mejor concurrencia de subprocesos en y alrededor de las solicitudes de los clientes. Intente ponerlo solo en antes de, realice la solicitud para que el GIL se restablezca y el intérprete de Python pueda borrar los hilos pendientes.

+1

En el enlace parece que el problema es ejecutar el servidor y el cliente en el mismo proceso. Por lo tanto, están sujetos al gil. –

+0

Sí, pero ... Está viendo lo que parece ser el mismo restablecimiento de conexión incluso en hosts de cliente-servidor separados. Sigo pensando que deberías meterte a dormir aquí y allá para ver si el cambio en la programación del hilo te ayuda. –

+0

Parece que su enlace está muerto. Http/1.1 Servicio no disponible – Bunyk

1

Normalmente, obtendrá un RST si hace un cierre que no persiste (es decir, en qué datos puede ser descartado por la pila si no se ha enviado y ACK'd) y un FIN normal si permites que la cercanía permanezca (es decir, la espera cercana para que los datos en tránsito sean ACK'd).

Tal vez todo lo que necesita hacer es configurar su toma de corriente para que desaparezca la condición de carrera entre un cierre no prolongado realizado en el zócalo y los ACK que llegan?

8

No utilice wsgiref para la producción. Usa Apache y mod_wsgi, o algo más.

Continuamos viendo estos reinicios de conexión, a veces con frecuencia, con wsgiref (el servidor de prueba utilizado por el servidor de prueba werkzeug, y posiblemente otros como el servidor de prueba Django). Nuestra solución fue registrar el error, reintentar la llamada en un bucle y renunciar después de diez fallas. httplib2 intenta dos veces, pero necesitamos algunas más. Parece que también vienen en racimos, agregar 1 segundo de sueño podría solucionar el problema.

Nunca hemos visto un restablecimiento de conexión al ejecutar Apache y mod_wsgi. No sé lo que hacen diferente, (tal vez solo los enmascaran), pero no aparecen.

Cuando le pedimos ayuda a la comunidad local de desarrollo, alguien confirmó que ve muchos reinicios de conexión con wsgiref que desaparecen en el servidor de producción. Hay un error allí, pero va a ser difícil encontrarlo.

Cuestiones relacionadas