104, Ошибка сокета «Сброс соединения по одноранговой сети», или Когда закрытие сокета приводит к RST, а не к FIN? - PullRequest
30 голосов
/ 21 декабря 2008

Мы разрабатываем веб-сервис Python и клиентский веб-сайт параллельно. Когда мы делаем HTTP-запрос от клиента к сервису, один вызов постоянно вызывает socket.error в socket.py, в read:

(104, 'Connection reset by peer')

Когда я слушаю Wireshark, ответы «хорошо» и «плохо» выглядят очень похоже:

  • Из-за размера заголовка OAuth запрос разбивается на два пакета. Служба отвечает как ACK
  • Служба отправляет ответ, один пакет на заголовок (HTTP / 1.0 200 OK, затем заголовок Date и т. Д.). Клиент отвечает каждому ACK.
  • (Хороший запрос) сервер отправляет FIN, ACK. Клиент отвечает FIN, ACK. Сервер отвечает ACK.
  • (неверный запрос) сервер отправляет RST, ACK, клиент не отправляет ответ TCP, на стороне клиента возникает ошибка socket.error.

И веб-служба, и клиент работают на коробке Gentoo Linux x86-64 с glibc-2.6.1. Мы используем Python 2.5.2 внутри того же virtual_env.

Клиент - это приложение Django 1.0.2, которое вызывает httplib2 0.4.0 для выполнения запросов. Мы подписываем запросы с помощью алгоритма подписи OAuth, для маркера OAuth всегда задана пустая строка.

Служба работает под управлением Werkzeug 0.3.1, который использует Python wsgiref.simple_server. Я без проблем запустил приложение WSGI через wsgiref.validator.

Кажется, что это должно быть легко отладить, но когда я прослеживаю хороший запрос на стороне службы, он выглядит как неправильный запрос в функции socket._socketobject.close (), превращая методы делегата в фиктивные. методы. Когда метод send или sendto (не помню, какой) отключен, отправляется FIN или RST, и клиент начинает обработку.

"Сброс соединения по пиру", кажется, возлагает вину на службу, но я тоже не доверяю httplib2. Может ли клиент быть виноват?

** Дальнейшая отладка - похоже на сервер в Linux **

У меня есть MacBook, поэтому я попытался запустить службу на одном, а веб-сайт клиента - на другом. Клиент Linux вызывает сервер OS X без ошибки (FIN ACK). Клиент OS X вызывает службу Linux с ошибкой (RST ACK и a (54, «Сброс соединения по пиру»). Похоже, это сервис, работающий в Linux. Это x86_64? Плохой бойц? wsgiref? Все еще смотрю ...

** Дальнейшее тестирование - wsgiref выглядит ненадежно **

Мы перешли на работу с Apache и mod_wsgi, и сброс соединений прекратился. Смотрите мой ответ ниже, но мой совет - зарегистрировать сброс соединения и повторить попытку. Это позволит вашему серверу нормально работать в режиме разработки и стабильно работать.

Ответы [ 5 ]

20 голосов
/ 21 декабря 2008

У меня была эта проблема. См. Проблема Python «Сброс соединения по одноранговой сети» .

Вы (скорее всего) столкнулись с небольшими проблемами синхронизации, связанными с глобальной блокировкой интерпретатора Python.

Вы можете (иногда) исправить это с помощью стратегического размещения time.sleep(0.01).

"Где?" ты спрашиваешь. Бьет меня Идея состоит в том, чтобы обеспечить лучший параллелизм потоков в клиентских запросах и вокруг них. Попробуйте указать до , когда вы сделаете запрос, чтобы сбросить GIL и интерпретатор Python может очистить все ожидающие потоки.

11 голосов
/ 27 января 2009

Не используйте wsgiref для производства. Используйте Apache и mod_wsgi или что-то еще.

Мы по-прежнему видим перезагрузку этих соединений, иногда часто, с помощью wsgiref (бэкэнд, используемый тестовым сервером werkzeug и, возможно, другими, такими как тестовый сервер Django). Нашим решением было зарегистрировать ошибку, повторить вызов в цикле и отказаться после десяти сбоев. httplib2 пытается дважды, но нам нужно было еще немного. Похоже, они тоже идут в кучу - добавление 1 секунды сна может решить проблему.

Мы никогда не видели сброса соединения при работе через Apache и mod_wsgi. Я не знаю, что они делают по-другому (возможно, они просто маскируют их), но они не появляются.

Когда мы обратились за помощью к местному сообществу разработчиков, кто-то подтвердил, что он видит много перезагрузок соединения с wsgiref, которые исчезают на рабочем сервере. Там есть ошибка, но найти ее будет сложно.

5 голосов
/ 29 июля 2009

Я понимаю, что вы используете python, но я нашел эту статью о Java полезной.

http://java.sun.com/javase/6/docs/technotes/guides/net/articles/connection_release.html

2 голосов
/ 21 декабря 2008

Обычно вы получаете RST, если вы делаете закрытие, которое не задерживается (то есть, в котором данные могут быть сброшены стеком, если они не были отправлены и ACK'd), и обычный FIN, если вы разрешить близким к задержке (т. е. закрытие ожидает, когда данные в пути будут ACK'd).

Возможно, все, что вам нужно сделать, это установить в своем сокете задержку так, чтобы вы удалили условие гонки между не задерживающимся закрытием, сделанным в сокете, и прибытием ACK?

1 голос
/ 16 октября 2018

Однако у меня возникла та же проблема с загрузкой очень большого файла с помощью отправки клиентом Python-запросов в серверную часть nginx + uwsgi.

Причиной тому было то, что у бэкенда был максимальный размер файла для загрузок, меньших, чем то, что пытался отправить клиент.

Ошибка никогда не обнаруживалась в наших логах uwsgi, так как это ограничение фактически было установлено nginx.

Увеличение лимита в nginx устранило ошибку.

...