java - suspender - ¿Quién envía un SIGKILL a mi proceso misteriosamente en el servidor de ubuntu?
parar proceso ubuntu (3)
ACTUALIZACIONES el 25 de octubre:
Ahora me enteré de lo que está causando el problema.
1) El proceso hijo se mata a sí mismo, por eso strace / perf / auditctl no puede rastrearlo.
2) La llamada JNI para crear un proceso se inicia desde un hilo de Java. Cuando el hilo finalmente muere, también está destruyendo el proceso que crea.
3) En mi código para bifurcar y ejecutar () un proceso hijo, tengo el código para monitorear el proceso de muerte del padre y el proceso de mi hijo con la siguiente línea: prctl (PR_SET_PDEATHSIG, SIGKILL); Por mi culpa de no haber prestado especial atención a esta bandera antes de b / c, se la considera una MEJOR PRÁCTICA para mis otros proyectos donde el proceso secundario se deriva del hilo principal.
4) Si comento esta línea, el problema desaparece. El propósito original es matar el proceso hijo cuando el proceso padre se ha ido. Incluso sin esta bandera, sigue siendo el comportamiento correcto. Parece el comportamiento por defecto de la caja de ubuntu.
5) Finalmente se encontró que es un error del kernel, corregido en la versión 3.4.0 del kernel, mi caja de ubuntu de AWS es la versión del kernel 3.13.0-29-genérica.
Hay un par de enlaces útiles a los temas:
a) http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them
c) https://bugzilla.kernel.org/show_bug.cgi?id=43300
ACTUALIZACIONES el 15 de octubre:
Muchas gracias por todas las sugerencias. Estoy investigando desde un área del sistema a otra área. Es difícil encontrar una razón.
Me estoy preguntando 2 cosas. 1) ¿Por qué las herramientas poderosas como strace, auditctl y perf script no pueden rastrear quién causó la muerte?
2) ¿El +++ es eliminado por SIGKILL +++ realmente significa que fue eliminado de la señal?
POSTE ORIGINAL
Tengo un proceso C de larga ejecución lanzado desde un servidor de aplicaciones Java en Ubuntu 12 a través de la interfaz JNI. La razón por la que utilizo la interfaz JNI para iniciar un proceso en lugar de hacerlo a través del generador de procesos de Java es b / c de las razones de rendimiento. Es muy ineficiente para el generador de procesos java hacer IPC, especialmente porque el búfer extra extra introduce un retraso muy largo.
Periódicamente es terminada misteriosamente por SIGKILL. La forma en que lo descubrí es a través de strace, que dice: "+++ kill by SIGKILL +++"
Revisé lo siguiente:
- No es un choque.
- No es un OOM. Nada en dmesg. Mi proceso usa solo el 3.3% de 1Gbytes de memoria.
- La capa de Java no mató el proceso. Puse un registro en el código JNI si el código termina el proceso, pero no se escribió ningún registro para indicar eso.
- No es un problema de permiso. Intenté ejecutarme como sudo o un usuario diferente, ambos casos causan la muerte del proceso.
- Si ejecuto el proceso localmente en un shell, todo funciona bien. Además, en mi código C para mi proceso de larga ejecución, ignoro la señal SIGHUP. Solo cuando se ejecuta como un proceso secundario del servidor Java, se anula.
- El proceso es muy intensivo en CPU. Está utilizando el 30% de la CPU. Hay un montón de cambio de contexto voluntario y conmutadores no_activos no voluntarios.
- (NUEVA ACTUALIZACIÓN) Una cosa IMPORTANTE muy probablemente relacionada con por qué se mata mi proceso. Si el proceso hace un trabajo pesado, no se eliminará, sin embargo, a veces se está haciendo poco trabajo intensivo de CPU. Cuando eso sucede, después de un tiempo, aproximadamente 1 minuto, se mata. Su estado es siempre S (En reposo) en lugar de R (En ejecución). Parece que el sistema operativo decide finalizar el proceso si está inactivo la mayor parte del tiempo, y no el proceso si está ocupado.
- Sospecho que el GC de Java es el culpable, sin embargo, Java NUNCA recogerá un objeto singleton asociado con JNI. (Mi objeto JNI está vinculado a ese singleton).
Estoy desconcertado por la razón por la cual ha terminado. ¿Alguien tiene una buena sugerencia de cómo localizarlo?
PD
En mi límite de ubuntu -un resultado es:
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
Traté de aumentar los límites, y todavía no resuelve el problema.
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
Aquí está el estado de proc cuando ejecuto 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 muestra:
$ 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 +++
Como mencioné anteriormente, la otra opción es usar la traza del kernel, que se puede hacer con la herramienta 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
Finalmente me di cuenta de la razón.
El proceso hijo se mata a sí mismo y es un error del kernel de Linux.
Detalles:
1) El proceso hijo se mata a sí mismo, por eso strace / perf / auditctl no puede rastrearlo.
2) La llamada JNI para crear un proceso se inicia desde un hilo de Java. Cuando el hilo finalmente muere, también está destruyendo el proceso que crea.
3) En mi código para bifurcar y ejecutar () un proceso hijo, tengo el código para monitorear el proceso de muerte del padre y el proceso de mi hijo con la siguiente línea: prctl (PR_SET_PDEATHSIG, SIGKILL); No le presté especial atención a esta bandera antes de que b / c se considere como la MEJOR PRÁCTICA para mis otros proyectos donde el proceso secundario se bifurca del hilo principal.
4) Si comento esta línea, el problema desaparece. El propósito original es matar el proceso hijo cuando el proceso padre se ha ido. Incluso sin esta bandera, sigue siendo el comportamiento correcto. Parece el comportamiento por defecto de la caja de ubuntu.
5) De este artículo, https://bugzilla.kernel.org/show_bug.cgi?id=43300 . es un error del kernel, corregido en la versión 3.4.0 del kernel, mi caja de ubuntu de AWS es la versión del kernel 3.13.0-29-genérico.
Configuración de mi máquina: ===> Ubuntu 14.04 LTS ===> 3.13.0-29-genérico
Algunos enlaces útiles a los temas:
a) http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them
Suponiendo que tenga acceso de root en su máquina, puede habilitar la auditoría en kill (2) syscall para recopilar dicha información.
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)
La otra forma es configurar el rastreo del kernel, que puede ser una anulación cuando el sistema de auditoría puede hacer el mismo trabajo.