Назад | Перейти на главную страницу

Процессы зависают на неопределенное время при чтении из сетевых подключений

Обновление ниже:

У меня возникла аналогичная проблема с несвязанным скриптом на виртуальной машине Debian в другом центре обработки данных.

Это подозрительно похоже на описанную проблему Вот (и, как и человек, задающий этот вопрос, у меня нет прокси-сервера, настроенного перед сервером).

Основное отличие от приведенного ниже описания заключается в том, что когда я подключаюсь к зависшему процессу, я вижу вызов recvfrom скорее, чем read:

$ strace -p 17527
Process 17527 attached - interrupt to quit
recvfrom(3, 

Однако у Python нет никакого впечатления, что он проксируется:

>>> import os; print os.getenv("HTTP_PROXY"), os.getenv("http_proxy")
None, None

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

(Мне также интересно, если этот вопрос связано, но кажется маловероятным, что S3 не соблюдает Connection: close заголовки.)


У меня есть несколько серверов Debian (Wheezy, x86_64), каждый из которых демонстрирует следующее поведение:

На всех серверах есть набор заданий cron, которые, помимо прочего, извлекают данные из S3. Обычно они работают нормально, но иногда ps aux показывает, что некоторые из заданий, начатых несколько часов или дней назад, все еще выполняются и не завершены должным образом.

Осматривая их с strace -p <pid> показывает, что во всех случаях процесс зависает от команды чтения. Например, результат процесса, который я только что проверил, был:

$ strace -p 12089
Process 12089 attached - interrupt to quit
read(5, 

И проверка дескрипторов открытых файлов дает мне следующее:

$ sudo lsof -i | grep 12089
python  12089    user    5u  IPv4 809917771      0t0  TCP my.server.net:35427->185-201.amazon.com:https (ESTABLISHED)

Сначала я предположил, что это произошло из-за того, что в сценариях Python не задан тайм-аут чтения, но этого не произошло по нескольким причинам:

  1. Этого не происходит, когда одни и те же задания выполняются на наших устройствах OS X (все 10.5, i386) с использованием идентичного кода.
  2. Вариант сценария, который делает установить тайм-аут (60 секунд, используя socket.setdefaulttimeout - это в Python 2.7, но кодовая база должна быть совместима с 2.5) зависло со вчерашнего дня.
  3. Другой процесс, отличный от Python, иногда, кажется, демонстрирует подобное поведение. В этом случае сценарий Python выполняет svn up --non-interactive процесс (с использованием subprocess.Popen, чего это стоит).

Ситуация с этим процессом SVN аналогична -

Python ждет SVN:

$ strace -p 28034
Process 28034 attached - interrupt to quit   
wait4(28127, 

И SVN ждет read звонок для завершения:

$ strace -p 28127
Process 28127 attached - interrupt to quit
read(6, 

И это чтение указывает на другой внешний хост:

$ sudo lsof -i | grep 28127
svn     28127    user    3u  IPv4 701186417      0t0  TCP my.server.net:49299->sparrow.telecommunity.com:svn (ESTABLISHED)
svn     28127    user    6u  IPv4 701186439      0t0  TCP my.server.net:49309->sparrow.telecommunity.com:svn (ESTABLISHED)

(Похоже, svn:externals свойство установлено на ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup об обновляемом каталоге; судя по их веб-сайту, я думаю, что это перенаправление на teleity.com)

Дополнительные, возможно, важные моменты:

Итак, я предполагаю, что мои вопросы:

Могу ли я исправить это на системном уровне, или что-то не так с каждым отдельным процессом?

Сложно сказать, потому что неизвестно, что происходит на уровне протокола. В основном read(2) заблокирует на неопределенный срок при условии: -

  • TCP-соединение остается открытым.
  • Ожидается получение как минимум 1 байта данных.
  • Отправитель не готов отправлять вам данные.

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

Вы не можете исправить это изящно, потому что по имеющейся у вас информации невозможно определить, что отправитель этих данных ожидает от вас. Однако есть несколько возможных способов избежать проблемы и сообщить о ней.

  • Вместо того, чтобы использовать wait в простом режиме блокировки запустите wait и настроить тревогу в родительском процессе. Теперь, когда процесс не может быть завершен в течение определенного периода времени, вы можете убить его и сообщить об этом. Дешевый способ сделать это - изменить subprocess.Popen для вызова timeout команда.
  • Измените чтение так, чтобы он устанавливал параметр сокета тайм-аута чтения. Вы можете сделать это, изменив код, или - используя промежуточную программу, чтобы переопределить значение по умолчанию socket системный вызов, чтобы также добавить тайм-аут для получателя. И то, и другое нетривиально. Это может вызвать svn вести себя неожиданным образом.

Есть ли что-то принципиально иное в том, как OS X и Linux обрабатывают вызовы чтения, что мне нужно знать, чтобы избежать бесконечного зависания процессов?

Я не знаю ответа на этот вопрос, однако, если оба ведут себя положительно правильно, они оба должны вести себя одинаково. Если вы пытаетесь читать из сокета, который еще не подготовлен для отправки вам данных, поток блокируется на неопределенный срок, что является ожидаемым поведением.

В целом, я думаю, что ваш лучший выбор атаки - ожидать вашего svn команда должна быть завершена в течение определенного периода времени. Если он не убьет его, сообщите об этом.

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

Были следующие основные проблемы:

  • Скрипты Python, для которых должен был быть установлен тайм-аут (а я предполагал, что это так), этого не сделали. Некоторые из них зависали на неопределенное время при подключении к S3, демонстрируя поведение бесконечного ожидания завершения чтения. Прочесывание кода и проверка того, что глобальные тайм-ауты сокетов были установлены и не сбрасываются, похоже, решили эту часть.
  • Некоторые из старых процессов Python казались зависшими, но при ближайшем рассмотрении (после того, как действительно заблокированные процессы были отсеяны), они просто перечисляли большие сегменты S3, чтобы проверить статус ключей в этих сегментах, и эта операция занимала часы или дней на выполнение.
  • Команда проверки SVN зависала (до сих пор) в течение длительного времени при обновлении очень больших проектов со многими файлами в очень глубоких структурах каталогов. Клиент ожидает завершения чтения, но это вполне законно (похоже, серверу репозитория требуется много времени, чтобы собрать данные, которые он должен отправить обратно клиенту).

Я оставляю этот ответ здесь, чтобы объяснить, что происходит, но я собираюсь принять ответ Мэтью, потому что он был прав в отношении фактических возможных проблем.