2014-12-16 3 views
4

Я пытаюсь проверить поведение, которое трудно воспроизвести в контролируемой среде.Имитация процесса, застрявшего в системном вызове блокировки

Use case: Linux system; обычно Redhat EL 5 или 6 (мы только начинаем с RHEL 7 и systemd, так что в настоящее время это выходит за рамки).

Бывают ситуации, когда мне нужно перезапустить службу. Сценарий, который мы используем для остановки службы, обычно работает достаточно хорошо; он отправляет SIGTERM в процесс, который предназначен для его обработки; если процесс не обрабатывает SIGTERM в течение таймаута (обычно через пару минут), скрипт отправляет SIGKILL, а затем ждет еще пару минут.

Проблема: в некоторых (редких случаях) процесс не выходит после SIGKILL; обычно это происходит, когда он сильно застревает в системном вызове, возможно, из-за проблемы на уровне ядра (поврежденная файловая система или не работающая файловая система NFS или что-то в равной степени плохое, требующее ручного вмешательства).

Ошибка возникла, когда сценарий не понял, что «старый» процесс фактически не вышел и начал новый процесс, пока старый все еще работает; мы исправляем это с помощью более сильной системы блокировки (так что по крайней мере новый процесс не запускается, если старый работает), но Мне сложно проверить все это на, потому что я не нашел способ имитировать жесткий застрявший процесс.

Итак, вопрос:

Как я могу вручную моделировать процесс, который не выходит при отправке SIGKILL к нему, даже в качестве привилегированного пользователя?

+0

Вы проверили системный журнал и искали процессы в ООН-прерывают или заблокированное состояние, возможно, застряло делать ввод/вывод. – askb

+0

@askb Я не спрашиваю «почему процесс застрял». Я могу справиться с этим, как правило, сбой, с которым ядро ​​не справляется. Я хочу, чтобы мой служебный скрипт был лучше, поэтому я спрашиваю, «как я могу заблокировать процесс в безостановочном syscall», чтобы выполнить мое тестирование. –

ответ

6

Если процесс застревают делать I/O, вы можете смоделировать ситуацию таким образом:

lvcreate -n lvtest -L 2G vgtest 
mkfs.ext3 -m0 /dev/vgtest/lvtest 
mount /dev/vgtest/lvtest /mnt 
dmsetup suspend /dev/vgtest/lvtest && dd if=/dev/zero of=/mnt/file.img bs=1M count=2048 & 

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

1

Ну ... Как насчет того, чтобы просто не отправлять SIGKILL? Таким образом, ваш env будет вести себя так, как будто он был отправлен, но процесс не прекратился.

0

Я бы назвал обратный путь. Попросите свой серверный процесс записать свой pid в, например. /var/run/yourserver.pid (это обычная практика). Попросите стартовый скрипт прочитать этот файл и проверить, что процесс не существует, например. с kill сигнала 0 или с

yourserver_pid=$(cat /var/run/yourserver.pid) 
if [ -f /proc/$yourserver_pid/exe ]; then 

Вы могли бы улучшить что readlink /proc/$yourserver_pid/exe и сравнивая, что /usr/bin/yourserver

BTW, имея процесс еще жив через несколько секунд после того, как SIGKILL серьезная ситуация (общий случай, когда это может произойти, заключается в том, что процесс застрял в состоянии D, ожидая некоторый NFS-сервер), и вы, вероятно, должны обнаружить и syslog его (например, с logger в вашем скрипте).

Я также хотел бы попробовать сначала отправить SIGTERM, подождите несколько секунд, отправить SIGQUIT, подождите несколько секунд, и, наконец, отправить SIGKILL и только через несколько секунд тестов, что серверный процесс пошел

1

После proces находится в состоянии «D» (или TASK_UNINTERRUPTIBLE) в коде кода ядра, где выполнение не может быть прервано во время обработки задачи, что означает, что отправка каких-либо сигналов в процесс не будет полезна и будет проигнорирована.

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

Поэтому вам нужно посмотреть отчеты syslog и sar в то время, когда процесс застрял в D-состоянии. Если вы найдете трассировки стека в журнале, попробуйте найти kernel.bugzilla.org для получения аналогичных проблем или обратитесь за поддержкой к поставщику Linux.

0

Ошибка возникла, когда сценарий не понял, что «старый» процесс фактически не вышел и начал новый процесс, пока старый еще не работал;

Это ошибка на уровне ОС/ядра, а не в вашем сервисном скрипте. Ситуация редка и трудно моделировать, потому что OS is supposed to kill the process when SIGKILL signal happens. Поэтому я предполагаю, что ваша цель - позволить вашему скрипту работать хорошо под явным ядром. Это верно?

0

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

[email protected]:~$ ping 8.8.8.8 > /tmp/ping.log & 
[1] 3770 
[email protected]:~$ ps 3770 
PID TTY  STAT TIME COMMAND 
3770 pts/13 S  0:00 ping 8.8.8.8 

[email protected]:~$ sudo gdb -p 3770 
... 
(gdb) 

Другого терминал

[email protected]:~$ ps 3770 
PID TTY  STAT TIME COMMAND 
3770 pts/13 t  0:00 ping 8.8.8.8 

sudo kill -9 3770 
... 
[email protected]:~$ ps 3770 
PID TTY  STAT TIME COMMAND 
3770 pts/13 Z  0:00 [ping] <defunct> 

Первый терминал снова

(gdb) quit 
Смежные вопросы