104, Ошибка сокета "Сброс соединения одноранговым узлом", или Когда закрытие сокета приводит к RST, а не FIN?

StackOverflow https://stackoverflow.com/questions/383738

Вопрос

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

(104, 'Connection reset by peer')

Когда я слушаю с помощью wireshark, "хорошие" и "плохие" ответы выглядят очень похожими:

  • Из-за размера заголовка OAuth запрос разбивается на два пакета.Служба отвечает на оба запроса с помощью ACK
  • Служба отправляет ответ, по одному пакету на заголовок (HTTP/1.0 200 OK, затем заголовок даты и т.д.).Клиент отвечает на каждый из них с помощью ACK.
  • (Хороший запрос) сервер отправляет FIN, подтверждение.Клиент отвечает "FIN", "ACK".Сервер отвечает 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, который использует wsgiref.simple_server на Python.Я запустил приложение WSGI через wsgiref.validator без проблем.

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

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

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

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

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

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

Это было полезно?

Решение

У меня была эта проблема.Видишь Проблема Python "Сброс соединения с помощью однорангового узла".

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

В конечном итоге причиной стало то, что серверная часть установила ограничение на максимальный размер файла для загрузок ниже, чем тот, который пытался отправить клиент.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top