Las publicaciones anteriores en el blog corporativo no conten铆an un solo equipo de consola, y decidimos ponernos al d铆a.
Nuestra empresa tiene una m茅trica dise帽ada para evitar grandes fakaps en hosting compartido. En cada servidor de alojamiento compartido hay un sitio de prueba en WordPress, al que se accede peri贸dicamente.

As铆 es como se ve el sitio de prueba en cada servidor de alojamiento compartido
Se mide la velocidad y el 茅xito de la respuesta del sitio. Cualquier empleado de la compa帽铆a puede mirar las estad铆sticas generales y ver qu茅 tan bien le est谩 yendo a la compa帽铆a. Puede ver el porcentaje de respuestas exitosas de un sitio de prueba para todo el alojamiento o para un servidor espec铆fico. No es necesario ser un empleado de la empresa: en el panel de control, los clientes tambi茅n ven estad铆sticas en el servidor donde se encuentra su cuenta.
Llamamos a esta m茅trica de tiempo de actividad (el porcentaje de respuestas exitosas del sitio de prueba a todas las solicitudes al sitio de prueba). No es un muy buen nombre, es f谩cil confundirlo con el tiempo de actividad , que es el tiempo total despu茅s del 煤ltimo reinicio del servidor .
El verano pas贸 y el horario de actividad disminuy贸 lentamente.

Los administradores identificaron de inmediato la raz贸n: falta de RAM. Fue f谩cil ver los casos de OOM en los registros cuando el servidor se qued贸 sin memoria y el kernel mat贸 a nginx.
El jefe del departamento, Andrey, divide una tarea en varias de la mano de un mago y las pone en paralelo con diferentes administradores. Uno va a analizar la configuraci贸n de Apache, 驴tal vez la configuraci贸n no sea 贸ptima y con mucho tr谩fico Apache usa toda la memoria? Otro analiza el consumo de memoria mysqld: de repente, 驴hay alguna configuraci贸n desactualizada desde el momento en que el alojamiento compartido utilizaba el sistema operativo Gentoo? El tercero analiza los cambios recientes en la configuraci贸n de nginx.
Uno por uno, los administradores regresan con resultados. Cada uno logr贸 reducir el consumo de memoria en el 谩rea asignada a 茅l. En el caso de nginx, por ejemplo, se detect贸 un mod_security incluido pero no utilizado. OOM, mientras tanto, tambi茅n es frecuente.
Finalmente, es posible notar que el consumo de memoria central (en particular, SUnreclaim) es terriblemente grande en algunos servidores. 隆Ni en la salida ps ni en htop es visible este par谩metro, por lo que no lo notamos de inmediato! Ejemplo de servidor con SUnreclaim infernal:
root@vh28.timeweb.ru:~
Se le dan 24 gigabytes de RAM al kernel, 隆y el kernel los gasta porque nadie sabe qu茅!
El administrador (llam茅mosle Gabriel) se apresura a la batalla. Vuelve a ensamblar el kernel con las opciones KMEMLEAK para la detecci贸n de fugas.
Opciones para reconstruirPara habilitar KMEMLEAK, solo especifique las opciones enumeradas a continuaci贸n y cargue el kernel con el par谩metro kmemleak = on.
CONFIG_HAVE_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=10000
KMEMLEAK escribe (en /sys/kernel/debug/kmemleak
) estas l铆neas:
unreferenced object 0xffff88013a028228 (size 8): comm "apache2", pid 23254, jiffies 4346187846 (age 1436.284s) hex dump (first 8 bytes): 00 00 00 00 00 00 00 00 ........ backtrace: [<ffffffff818570c8>] kmemleak_alloc+0x28/0x50 [<ffffffff811d450a>] kmem_cache_alloc_trace+0xca/0x1d0 [<ffffffff8136dcc3>] apparmor_file_alloc_security+0x23/0x40 [<ffffffff81332d63>] security_file_alloc+0x33/0x50 [<ffffffff811f8013>] get_empty_filp+0x93/0x1c0 [<ffffffff811f815b>] alloc_file+0x1b/0xa0 [<ffffffff81728361>] sock_alloc_file+0x91/0x120 [<ffffffff8172b52e>] SyS_socket+0x7e/0xc0 [<ffffffff81003854>] do_syscall_64+0x54/0xc0 [<ffffffff818618ab>] return_from_SYSCALL_64+0x0/0x6a [<ffffffffffffffff>] 0xffffffffffffffff unreferenced object 0xffff880d67030280 (size 624): comm "hrrb", pid 23713, jiffies 4346190262 (age 1426.620s) hex dump (first 32 bytes): 01 00 00 00 03 00 ff ff 00 00 00 00 00 00 00 00 ................ 00 e7 1a 06 10 88 ff ff 00 81 76 6e 00 88 ff ff ..........vn.... backtrace: [<ffffffff818570c8>] kmemleak_alloc+0x28/0x50 [<ffffffff811d4337>] kmem_cache_alloc+0xc7/0x1d0 [<ffffffff8172a25d>] sock_alloc_inode+0x1d/0xc0 [<ffffffff8121082d>] alloc_inode+0x1d/0x90 [<ffffffff81212b01>] new_inode_pseudo+0x11/0x60 [<ffffffff8172952a>] sock_alloc+0x1a/0x80 [<ffffffff81729aef>] __sock_create+0x7f/0x220 [<ffffffff8172b502>] SyS_socket+0x52/0xc0 [<ffffffff81003854>] do_syscall_64+0x54/0xc0 [<ffffffff818618ab>] return_from_SYSCALL_64+0x0/0x6a [<ffffffffffffffff>] 0xffffffffffffffff
Gabriel no nos revel贸 todos sus secretos y no cont贸 c贸mo, en las l铆neas anteriores, descubri贸 la causa exacta de la p茅rdida de memoria. Lo m谩s probable es que haya usado el addr2line /usr/lib/debug/lib/modules/`uname -r`/vmlinux ffffffff81722361
para encontrar la l铆nea exacta. O simplemente abri贸 el net/socket.c
y lo mir贸 hasta que el archivo se volvi贸 inc贸modo.
El problema result贸 ser un parche en el net/socket.c
, que se agreg贸 a nuestro repositorio hace muchos a帽os. Su prop贸sito es prohibir a los clientes el uso de la llamada al sistema bind (), esta es una protecci贸n simple contra el servidor proxy que inician los clientes. El parche cumpli贸 su prop贸sito, pero no borr贸 la memoria despu茅s de s铆 mismo.
Tal vez hubo un nuevo malware de moda en PHP que intent贸 ejecutar un servidor proxy en un bucle, lo que condujo a cientos de miles de llamadas bloqueadas bind () y perdi贸 gigabytes de RAM.
Luego fue simple: Gabriel arregl贸 el parche y reconstruy贸 el n煤cleo. Monitoreo agregado del valor de SUnreclaim en todos los servidores que ejecutan Linux. Los ingenieros advirtieron a los clientes y reiniciaron el alojamiento en el nuevo n煤cleo.
OOM desapareci贸.
Pero el problema con la disponibilidad de sitios permaneci贸
En todos los servidores, el sitio de prueba dej贸 de responder varias veces al d铆a.
Aqu铆, el autor comenzar铆a a rasgar el cabello en diferentes partes del cuerpo. Pero Gabriel mantuvo la calma y activ贸 la grabaci贸n del tr谩fico a partes de los servidores de alojamiento.
En el volcado de tr谩fico, se observ贸 que con mayor frecuencia la solicitud al sitio de prueba cae despu茅s de la recepci贸n repentina de un paquete TCP RST
. En otras palabras, la solicitud lleg贸 al servidor, pero la conexi贸n termin贸 siendo interrumpida por nginx.
Adem谩s m谩s interesante! La utilidad strace lanzada por Gabriel muestra que el demonio nginx no est谩 enviando este paquete. 驴C贸mo puede ser esto, porque solo nginx est谩 escuchando en el puerto 80?
La raz贸n fue una combinaci贸n de varios factores:
- en la configuraci贸n de nginx, se
reuseport
opci贸n de reuseport
(incluida la SO_REUSEPORT
socket SO_REUSEPORT
), que permite que diferentes procesos acepten conexiones en la misma direcci贸n y puerto - en (en ese momento, la versi贸n m谩s reciente) de nginx 1.13.0 hay un error debido al cual al iniciar la prueba de configuraci贸n de
nginx -t
trav茅s de nginx -t
y al usar la SO_REUSEPORT
este proceso de prueba de nginx realmente comenz贸 a escuchar el puerto 80 e interceptar solicitudes de clientes reales . Y al final del proceso de prueba de configuraci贸n, los clientes recibieron el Connection reset by peer
- finalmente, al monitorear el zabbix, se configur贸 el monitoreo de correcci贸n de la configuraci贸n de nginx en todos los servidores con nginx instalado: se llam贸 al comando
nginx -t
una vez por minuto.
Solo despu茅s de actualizar nginx podr铆a exhalar con calma. El gr谩fico de tiempo de actividad de los sitios ha aumentado.
驴Cu谩l es la moraleja de toda esta historia? Sea optimista y evite el uso de n煤cleos autoensamblados.