Подтвердить что ты не робот

Кто отправляет SIGKILL в мой процесс таинственным образом на сервере ubuntu

ОБНОВЛЕНИЯ от 25 октября:

Теперь я выяснил, что вызывает проблему.

1) Детский процесс убивает себя, поэтому strace/perf/auditctl не может отследить его.

2) JNI-вызов для создания процесса запускается из потока Java. Когда поток в конечном итоге умирает, он также разрушает процесс, который он создает.

3) В моем коде fork и execve() дочерний процесс, у меня есть код для отслеживания смерти родительского процесса и уничтожения моего дочернего процесса со следующей строкой: prctl (PR_SET_PDEATHSIG, SIGKILL); Моя вина, что я не обращал особого внимания на этот флаг, прежде чем он/она рассмотрит как ЛУЧШУЮ ПРАКТИЦИЮ для моих других проектов, где дочерний процесс разветвляется из основного потока.

4) Если я прокомментирую эту строку, проблема исчезнет. Первоначальная цель - убить дочерний процесс, когда родительский процесс исчез. Даже без этого флага все еще правильное поведение. Похоже на поведение по умолчанию в ядре ubuntu.

5) Наконец-то найденная ошибка ядра, исправленная в версии ядра 3.4.0, ящик Ubuntu от AWS является версией ядра 3.13.0-29-generic.

Есть несколько полезных ссылок на проблемы:

a) http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them

b) prctl (PR_SET_PDEATHSIG, SIGNAL) вызывается при выходе родительского потока, а не выходе из родительского процесса.

c) https://bugzilla.kernel.org/show_bug.cgi?id=43300

ОБНОВЛЕНИЯ 15 октября:

Большое спасибо за все предложения. Я исследую из одной области системы в другую область. Трудно найти причину.

Мне интересно 2 вещи.  1) почему мощные инструменты, такие как strace, auditctl и perf script не способны отслеживать, кто вызвал убийство?

2) Является ли +++, убитым SIGKILL +++, действительно означает его убитый из сигнала?

ОРИГИНАЛЬНАЯ ПОЧТА

У меня длительный процесс C, запущенный с сервера приложений Java в Ubuntu 12 через интерфейс JNI. Причина, по которой я использую интерфейс JNI для запуска процесса, а не через Java-процесс, - это b/c из соображений производительности. Это очень неэффективно для java process builder для IPC, особенно b/c, дополнительная буферизация вводит очень долгую задержку.

Периодически он прерывается SIGKILL таинственным образом. То, как я узнал, - это strace, в котором говорится: "+++ убито SIGKILL +++"

Я проверил следующее:

  • Это не крушение.
  • Это не OOM. Ничего в dmesg. Мой процесс использует только 3,3% 1 Гбайт памяти.
  • Уровень Java не убил процесс. Я помещаю журнал в код JNI, если код завершает процесс, но для этого не было записано ни одного журнала.
  • Это не проблема разрешения. Я пытался работать как sudo или другой пользователь, оба случая заставляют процесс быть убитым.
  • Если я запускаю процесс локально в оболочке, все работает нормально. Что еще, в моем C-коде для моего долговременного процесса, я игнорирую сигнал SIGHUP. Только когда он работает как дочерний процесс Java-сервера, он убивается.
  • Процесс очень интенсивен. Он использует 30% процессора. Существует множество добровольных переключателей контекста и nonvoluntary_ctxt_switches.
  • (НОВОЕ ОБНОВЛЕНИЕ) Одна ВАЖНАЯ вещь очень вероятно связана с тем, почему мой процесс убит. Если процесс совершит тяжелый подъем, он не будет убит, однако иногда он делает небольшую работу с интенсивным процессором. Когда это произойдет, через некоторое время, примерно 1 мин, он будет убит. Это состояние всегда S (Спящий) вместо R (Бег). Кажется, ОС решила убить процесс, если он большую часть времени простаивал, а не убивать процесс, если он занят.
  • Я подозреваю, что Java GC является виновником, однако Java никогда не будет мусором собирать одноэлементный объект, связанный с JNI. (Мой объект JNI привязан к этому синглтону).

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

p.s.

  • В моем ограничении ubuntu -a результат:

    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 7862
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65535
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 7862
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    

    Я попытался увеличить лимиты и все еще не решил проблему.

    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) unlimited
    max locked memory       (kbytes, -l) unlimited
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65535
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) unlimited
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) unlimited
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    
  • Вот статус proc, когда я запускаю cat/proc/$$$/status

    Name:   mimi_coso
    State:  S (Sleeping)
    Tgid:   2557
    Ngid:   0
    Pid:    2557
    PPid:   2229
    TracerPid:  0
    Uid:    0   0   0   0
    Gid:    0   0   0   0
    FDSize: 256
    Groups: 0
    VmPeak:   146840 kB
    VmSize:   144252 kB
    VmLck:         0 kB
    VmPin:         0 kB
    VmHWM:     36344 kB
    VmRSS:     34792 kB
    VmData:    45728 kB
    VmStk:       136 kB
    VmExe:       116 kB
    VmLib:     23832 kB
    VmPTE:       292 kB
    VmSwap:        0 kB
    Threads:    1
    SigQ:   0/7862
    SigPnd: 0000000000000000
    ShdPnd: 0000000000000000
    SigBlk: 0000000000000004
    SigIgn: 0000000000011001
    SigCgt: 00000001c00064ee
    CapInh: 0000000000000000
    CapPrm: 0000001fffffffff
    CapEff: 0000001fffffffff
    CapBnd: 0000001fffffffff
    Seccomp:    0
    Cpus_allowed:   7fff
    Cpus_allowed_list:  0-14
    Mems_allowed:   00000000,00000001
    Mems_allowed_list:  0
    voluntary_ctxt_switches:    16978
    nonvoluntary_ctxt_switches: 52120
    
  • strace показывает:

    $ strace -p 22254 -s 80 -o /tmp/debug.lighttpd.txt
    read(0, "SGI\0\1\0\0\0\1\0c\0\0\0\t\0\0T\1\2248\0\0\0\0'\1\0\0(\0\0"..., 512) = 113
    read(0, "SGI\0\1\0\0\0\1\0\262\1\0\0\10\0\1\243\1\224L\0\0\0\0/\377\373\222D\231\214"..., 512) = 448
    sendto(3, "<15>Oct 10 18:34:01 MixCoder[271"..., 107, MSG_NOSIGNAL, NULL, 0) = 107
    write(1, "SGO\0\0\0\0 \272\1\0\0\t\0\1\253\1\243\273\0\0\0\0'\1\0\0\0\0\0\1\242"..., 454) = 454
    sendto(3, "<15>Oct 10 18:34:01 MixCoder[271"..., 107, MSG_NOSIGNAL, NULL, 0) = 107
    write(1, "SGO\0\0\0\0 \341\0\0\0\10\0\0\322\1\254Z\0\0\0\0/\377\373R\4\0\17\21!"..., 237) = 237
    read(0, "SGI\0\1\0\0\0\1\0)\3\0\0\t\0\3\32\1\224`\0\0\0\0'\1\0\0\310\0\0"..., 512) = 512
    read(0, "\344u\233\16\257\341\315\254\272\300\351\302\324\263\212\351\225\365\1\241\225\3+\276J\273\37R\234R\362z"..., 512) = 311
    read(0, "SGI\0\1\0\0\0\1\0\262\1\0\0\10\0\1\243\1\224f\0\0\0\0/\377\373\222d[\210"..., 512) = 448
    sendto(3, "<15>Oct 10 18:34:01 MixCoder[271"..., 107, MSG_NOSIGNAL, NULL, 0) = 107
    write(1, "SGO\0\0\0\0 %!\0\0\t\0\0+\1\243\335\0\0\0\0\27\0\0\0\0\1B\300\36"..., 8497) = 8497
    sendto(3, "<15>Oct 10 18:34:01 MixCoder[271"..., 107, MSG_NOSIGNAL, NULL, 0) = 107
    write(1, "SGO\0\0\0\0 \341\0\0\0\10\0\0\322\1\254t\0\0\0\0/\377\373R\4\0\17\301\31"..., 237) = 237
    read(0, "SGI\0\1\0\0\0\1\0\262\1\0\0\10\0\1\243\1\224\200\0\0\0\0/\377\373\222d/\200"..., 512) = 448
    sendto(3, "<15>Oct 10 18:34:01 MixCoder[271"..., 107, MSG_NOSIGNAL, NULL, 0) = 107
    write(1, "SGO\0\0\0\0 \341\0\0\0\10\0\0\322\1\254\216\0\0\0\0/\377\373R\4\0\17\361+"..., 237) = 237
    read(0, "SGI\0\1\0\0\0\1\0\221\0\0\0\t\0\0\202\1\224\210\0\0\0\0'\1\0\0P\0\0"..., 512) = 159
    read(0,  unfinished ...)
    
    +++ killed by SIGKILL +++
    
4b9b3361

Ответ 1

Наконец, я понял причину.

Детский процесс убивает себя, и это ошибка ядра Linux.

Подробнее:

1) Детский процесс убивает себя, поэтому strace/perf/auditctl не может отследить его.

2) JNI-вызов для создания процесса запускается из потока Java. Когда поток в конечном итоге умирает, он также разрушает процесс, который он создает.

3) В моем коде fork и execve() дочерний процесс, у меня есть код для отслеживания смерти родительского процесса и уничтожения моего дочернего процесса со следующей строкой: prctl (PR_SET_PDEATHSIG, SIGKILL); Я не обращал особого внимания на этот флаг до того, как он/она рассмотрит как ЛУЧШУЮ ПРАКТИЦИЮ для моих других проектов, где дочерний процесс разветвляется из основного потока.

4) Если я прокомментирую эту строку, проблема исчезнет. Первоначальная цель - убить дочерний процесс, когда родительский процесс исчез. Даже без этого флага все еще правильное поведение. Похоже на поведение по умолчанию в ядре ubuntu.

5) Из этой статьи https://bugzilla.kernel.org/show_bug.cgi?id=43300. это ошибка ядра, исправленная в ядре версии 3.4.0, мой ящик ubuntu от AWS - это версия ядра 3.13.0-29-generic.

Моя конфигурация машины:  === > Ubuntu 14.04 LTS  === > 3.13.0-29-родовое

Некоторые полезные ссылки на проблемы:

a) http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them

b) prctl (PR_SET_PDEATHSIG, SIGNAL) вызывается при выходе родительского потока, а не выходе из родительского процесса

c) https://bugzilla.kernel.org/show_bug.cgi?id=43300

Ответ 2

Предполагая, что у вас есть корневой доступ на вашем компьютере, вы можете включить аудит на kill (2) syscall для сбора такой информации.

root # auditctl -a exit,always -F arch=b64 -S kill -F a1=9
root # auditctl -l
LIST_RULES: exit,always arch=3221225534 (0xc000003e) a1=9 (0x9) syscall=kill

root # sleep 99999 &
[2] 11688
root # kill -9 11688

root # ausearch -sc kill
time->Tue Oct 14 00:38:44 2014
type=OBJ_PID msg=audit(1413272324.413:441376): opid=11688 oauid=52872 ouid=0 oses=20 ocomm="sleep"
type=SYSCALL msg=audit(1413272324.413:441376): arch=c000003e syscall=62 success=yes exit=0 a0=2da8 a1=9 a2=0 a3=0 items=0 ppid=6107 pid=6108 auid=52872 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsg
id=0 tty=pts2 ses=20 comm="bash" exe="/bin/bash" key=(null)

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

Ответ 3

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

# apt-get install linux-tools-3.13.0-35-generic
# perf list | grep kill
 syscalls:sys_enter_kill                            [Tracepoint event]
 syscalls:sys_exit_kill                             [Tracepoint event]
 syscalls:sys_enter_tgkill                          [Tracepoint event]
 syscalls:sys_exit_tgkill                           [Tracepoint event]
 syscalls:sys_enter_tkill                           [Tracepoint event]
 syscalls:sys_exit_tkill                            [Tracepoint event]
# perf record -a -e syscalls:sys_enter_kill sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.634 MB perf.data (~71381 samples) ]

// Open a new shell to kill. 
$ sleep 9999 &
[1] 2387
$ kill -9 2387
[1]+  Killed                  sleep 9999
$ echo $$
9014

// Dump the trace in your original shell.
# perf script
...
        bash  9014 [001] 1890350.544971: syscalls:sys_enter_kill: pid: 0x00000953, sig: 0x00000009