Rsync activó el asesino OOM de Linux en un solo archivo de 50 GB

66

Tengo un solo archivo de 50 GB en server_A, y lo estoy copiando en server_B. Corro

server_A$ rsync --partial --progress --inplace --append-verify 50GB_file root@server_B:50GB_file

Server_B tiene 32 GB de RAM con 2 GB de intercambio. En su mayoría está inactivo y debería haber tenido mucha RAM libre. Tiene mucho espacio en disco. Aproximadamente a 32 GB, la transferencia se cancela porque el lado remoto cierra la conexión.

Server_B ahora se ha caído de la red. Le pedimos al centro de datos que lo reinicie. Cuando miro el registro del kernel antes de que se bloquee, veo que estaba usando 0 bytes de intercambio, y la lista de procesos estaba usando muy poca memoria (el proceso rsync estaba listado como usando 600 KB de RAM), pero el oom_killer estaba enloqueciendo, y lo último en el registro es donde mata el proceso del lector del núcleo del metalog.

Este es el kernel 3.2.59, 32 bits (de modo que ningún proceso puede asignar más de 4 GB de todos modos).

Es casi como si Linux diera más prioridad al almacenamiento en caché que a los demonios en ejecución de larga duración. ¿¿Lo que da?? ¿Y cómo puedo evitar que vuelva a suceder?

Aquí está la salida del oom_killer:

Sep 23 02:04:16 [kernel] [1772321.850644] clamd invoked oom-killer: gfp_mask=0x84d0, order=0, oom_adj=0, oom_score_adj=0
Sep 23 02:04:16 [kernel] [1772321.850649] Pid: 21832, comm: clamd Tainted: G         C   3.2.59 #21
Sep 23 02:04:16 [kernel] [1772321.850651] Call Trace:
Sep 23 02:04:16 [kernel] [1772321.850659]  [<c01739ac>] ? dump_header+0x4d/0x160
Sep 23 02:04:16 [kernel] [1772321.850662]  [<c0173bf3>] ? oom_kill_process+0x2e/0x20e
Sep 23 02:04:16 [kernel] [1772321.850665]  [<c0173ff8>] ? out_of_memory+0x225/0x283
Sep 23 02:04:16 [kernel] [1772321.850668]  [<c0176438>] ? __alloc_pages_nodemask+0x446/0x4f4
Sep 23 02:04:16 [kernel] [1772321.850672]  [<c0126525>] ? pte_alloc_one+0x14/0x2f
Sep 23 02:04:16 [kernel] [1772321.850675]  [<c0185578>] ? __pte_alloc+0x16/0xc0
Sep 23 02:04:16 [kernel] [1772321.850678]  [<c0189e74>] ? vma_merge+0x18d/0x1cc
Sep 23 02:04:16 [kernel] [1772321.850681]  [<c01856fa>] ? handle_mm_fault+0xd8/0x15d
Sep 23 02:04:16 [kernel] [1772321.850685]  [<c012305a>] ? do_page_fault+0x20e/0x361
Sep 23 02:04:16 [kernel] [1772321.850688]  [<c018a9c4>] ? sys_mmap_pgoff+0xa2/0xc9
Sep 23 02:04:16 [kernel] [1772321.850690]  [<c0122e4c>] ? vmalloc_fault+0x237/0x237
Sep 23 02:04:16 [kernel] [1772321.850694]  [<c08ba7e6>] ? error_code+0x5a/0x60
Sep 23 02:04:16 [kernel] [1772321.850697]  [<c08b0000>] ? cpuid4_cache_lookup_regs+0x372/0x3b2
Sep 23 02:04:16 [kernel] [1772321.850700]  [<c0122e4c>] ? vmalloc_fault+0x237/0x237
Sep 23 02:04:16 [kernel] [1772321.850701] Mem-Info:
Sep 23 02:04:16 [kernel] [1772321.850703] DMA per-cpu:
Sep 23 02:04:16 [kernel] [1772321.850704] CPU    0: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850706] CPU    1: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850707] CPU    2: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850709] CPU    3: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850711] CPU    4: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850713] CPU    5: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850714] CPU    6: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850716] CPU    7: hi:    0, btch:   1 usd:   0
Sep 23 02:04:16 [kernel] [1772321.850718] Normal per-cpu:
Sep 23 02:04:16 [kernel] [1772321.850719] CPU    0: hi:  186, btch:  31 usd:  70
Sep 23 02:04:16 [kernel] [1772321.850721] CPU    1: hi:  186, btch:  31 usd: 116
Sep 23 02:04:16 [kernel] [1772321.850723] CPU    2: hi:  186, btch:  31 usd: 131
Sep 23 02:04:16 [kernel] [1772321.850724] CPU    3: hi:  186, btch:  31 usd:  76
Sep 23 02:04:16 [kernel] [1772321.850726] CPU    4: hi:  186, btch:  31 usd:  29
Sep 23 02:04:16 [kernel] [1772321.850728] CPU    5: hi:  186, btch:  31 usd:  61
Sep 23 02:04:16 [kernel] [1772321.850731] CPU    7: hi:  186, btch:  31 usd:  17
Sep 23 02:04:16 [kernel] [1772321.850733] HighMem per-cpu:
Sep 23 02:04:16 [kernel] [1772321.850734] CPU    0: hi:  186, btch:  31 usd:   2
Sep 23 02:04:16 [kernel] [1772321.850736] CPU    1: hi:  186, btch:  31 usd:  69
Sep 23 02:04:16 [kernel] [1772321.850738] CPU    2: hi:  186, btch:  31 usd:  25
Sep 23 02:04:16 [kernel] [1772321.850739] CPU    3: hi:  186, btch:  31 usd:  27
Sep 23 02:04:16 [kernel] [1772321.850741] CPU    4: hi:  186, btch:  31 usd:   7
Sep 23 02:04:16 [kernel] [1772321.850743] CPU    5: hi:  186, btch:  31 usd: 188
Sep 23 02:04:16 [kernel] [1772321.850744] CPU    6: hi:  186, btch:  31 usd:  25
Sep 23 02:04:16 [kernel] [1772321.850746] CPU    7: hi:  186, btch:  31 usd: 158
Sep 23 02:04:16 [kernel] [1772321.850750] active_anon:117913 inactive_anon:9942 isolated_anon:0
Sep 23 02:04:16 [kernel] [1772321.850751]  active_file:106466 inactive_file:7784521 isolated_file:0
Sep 23 02:04:16 [kernel] [1772321.850752]  unevictable:40 dirty:0 writeback:61 unstable:0
Sep 23 02:04:16 [kernel] [1772321.850753]  free:143494 slab_reclaimable:128312 slab_unreclaimable:4089
Sep 23 02:04:16 [kernel] [1772321.850754]  mapped:6706 shmem:308 pagetables:915 bounce:0
Sep 23 02:04:16 [kernel] [1772321.850759] DMA free:3624kB min:140kB low:172kB high:208kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolate
d(file):0kB present:15808kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:240kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tm
p:0kB pages_scanned:0 all_unreclaimable? yes
Sep 23 02:04:16 [kernel] [1772321.850763] lowmem_reserve[]: 0 869 32487 32487
Sep 23 02:04:16 [kernel] [1772321.850770] Normal free:8056kB min:8048kB low:10060kB high:12072kB active_anon:0kB inactive_anon:0kB active_file:248kB inactive_file:388kB unevictable:0kB isolated(anon)
:0kB isolated(file):0kB present:890008kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:513008kB slab_unreclaimable:16356kB kernel_stack:1888kB pagetables:3660kB unstable:0
kB bounce:0kB writeback_tmp:0kB pages_scanned:1015 all_unreclaimable? yes
Sep 23 02:04:16 [kernel] [1772321.850774] lowmem_reserve[]: 0 0 252949 252949
Sep 23 02:04:16 [kernel] [1772321.850785] lowmem_reserve[]: 0 0 0 0
Sep 23 02:04:16 [kernel] [1772321.850788] DMA: 0*4kB 7*8kB 3*16kB 6*32kB 4*64kB 6*128kB 5*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 3624kB
Sep 23 02:04:16 [kernel] [1772321.850795] Normal: 830*4kB 80*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 1*4096kB = 8056kB
Sep 23 02:04:16 [kernel] [1772321.850802] HighMem: 13*4kB 14*8kB 2*16kB 2*32kB 0*64kB 0*128kB 2*256kB 2*512kB 3*1024kB 0*2048kB 136*4096kB = 561924kB
Sep 23 02:04:16 [kernel] [1772321.850809] 7891360 total pagecache pages
Sep 23 02:04:16 [kernel] [1772321.850811] 0 pages in swap cache
Sep 23 02:04:16 [kernel] [1772321.850812] Swap cache stats: add 0, delete 0, find 0/0
Sep 23 02:04:16 [kernel] [1772321.850814] Free swap  = 1959892kB
Sep 23 02:04:16 [kernel] [1772321.850815] Total swap = 1959892kB
Sep 23 02:04:16 [kernel] [1772321.949081] 8650736 pages RAM
Sep 23 02:04:16 [kernel] [1772321.949084] 8422402 pages HighMem
Sep 23 02:04:16 [kernel] [1772321.949085] 349626 pages reserved
Sep 23 02:04:16 [kernel] [1772321.949086] 7885006 pages shared
Sep 23 02:04:16 [kernel] [1772321.949087] 316864 pages non-shared
Sep 23 02:04:16 [kernel] [1772321.949089] [ pid ]   uid  tgid total_vm      rss cpu oom_adj oom_score_adj name
            (rest of process list omitted)
Sep 23 02:04:16 [kernel] [1772321.949656] [14579]     0 14579      579      171   5       0             0 rsync
Sep 23 02:04:16 [kernel] [1772321.949662] [14580]     0 14580      677      215   5       0             0 rsync
Sep 23 02:04:16 [kernel] [1772321.949669] [21832]   113 21832    42469    37403   0       0             0 clamd
Sep 23 02:04:16 [kernel] [1772321.949674] Out of memory: Kill process 21832 (clamd) score 4 or sacrifice child
Sep 23 02:04:16 [kernel] [1772321.949679] Killed process 21832 (clamd) total-vm:169876kB, anon-rss:146900kB, file-rss:2712kB

Aquí está la salida 'superior' después de repetir mi comando rsync como usuario no root:

top - 03:05:55 up  8:43,  2 users,  load average: 0.04, 0.08, 0.09
Tasks: 224 total,   1 running, 223 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0% us,  0.0% sy,  0.0% ni, 99.9% id,  0.0% wa,  0.0% hi,  0.0% si
Mem:  33204440k total, 32688600k used,   515840k free,   108124k buffers
Swap:  1959892k total,        0k used,  1959892k free, 31648080k cached

Aquí están los parámetros de sysctl vm:

# sysctl -a | grep '^vm'
vm.overcommit_memory = 0
vm.panic_on_oom = 0
vm.oom_kill_allocating_task = 0
vm.oom_dump_tasks = 1
vm.overcommit_ratio = 50
vm.page-cluster = 3
vm.dirty_background_ratio = 1
vm.dirty_background_bytes = 0
vm.dirty_ratio = 0
vm.dirty_bytes = 15728640
vm.dirty_writeback_centisecs = 500
vm.dirty_expire_centisecs = 3000
vm.nr_pdflush_threads = 0
vm.swappiness = 60
vm.lowmem_reserve_ratio = 256   32      32
vm.drop_caches = 0
vm.min_free_kbytes = 8192
vm.percpu_pagelist_fraction = 0
vm.max_map_count = 65530
vm.laptop_mode = 0
vm.block_dump = 0
vm.vfs_cache_pressure = 100
vm.legacy_va_layout = 0
vm.stat_interval = 1
vm.mmap_min_addr = 4096
vm.vdso_enabled = 2
vm.highmem_is_dirtyable = 0
vm.scan_unevictable_pages = 0
sin datos
fuente
2
No soy un experto en leer mensajes de falla del kernel, pero no veo ninguna indicación de que B estaba usando 32 GB de núcleo. Antes de continuar asumiendo que sí, ¿puede confirmar que lo es actualmente? Porque hay una gran diferencia entre agotar la memoria de una caja con 32 GB de núcleo y una con solo 4 GB.
MadHatter
Actualizado con salida superior. Esto es después de ejecutar el mismo comando rsync que un usuario no root. Casi todos menos 1GB se usan para caché en este momento.
datos
Gracias. Como dije, no soy un experto, pero parecía que valía la pena comprobarlo.
MadHatter
también debe verificar que su núcleo permita el intercambio (es decir, el intercambio no está desactivado) (y debería dedicar una porción más grande de espacio en disco, digamos 16Gb o incluso 32Gb). Algunas personas extrañas en la red recomiendan desactivar el intercambio, lo cual está muy mal.
Olivier Dulac
@OlivierDulac ¿a qué configuración te refieres? el soporte de intercambio está compilado o no podríamos montar el intercambio, y la 'swappiness' está configurada en 60. En cuanto al tamaño del intercambio, ¿eso no empeoraría el problema en un kernel de 32 bits? La respuesta parece que las estructuras de datos del núcleo fueron lo que nos mató. No estamos ejecutando 32 GB de procesos de usuario, solo queremos esa cantidad de memoria RAM para caché de disco, para rendimiento
datos

Respuestas:

178

Así que leamos la salida de Oom-Killer y veamos qué se puede aprender de allí.

Al analizar los registros asesinos de OOM, es importante observar qué lo desencadenó. La primera línea de su registro nos da algunas pistas:

[kernel] [1772321.850644] clamd invocó oom-killer: gfp_mask = 0x84d0, order = 0

order=0nos dice cuánta memoria se solicita. La administración de memoria del núcleo solo puede administrar números de página en potencias de 2, por lo que clamd ha solicitado 2 0 páginas de memoria o 4KB.

Los dos bits más bajos de GFP_MASK (obtener la máscara de página libre) constituyen la llamada máscara de zona que le dice al asignador de qué zona obtener la memoria :

Flag            value      Description
                0x00u      0 implicitly means allocate from ZONE_NORMAL
__GFP_DMA       0x01u      Allocate from ZONE_DMA if possible
__GFP_HIGHMEM   0x02u      Allocate from ZONE_HIGHMEM if possible

Zonas de memoria es un concepto creado principalmente por razones de compatibilidad. En una vista simplificada, hay tres zonas para un Kernel x86:

Memory range   Zone       Purpose 

0-16 MB        DMA        Hardware compatibility (devices)
16 - 896 MB    NORMAL     space directly addressable by the Kernel, userland 
> 896 MB       HIGHMEM    userland, space addressable by the Kernel via kmap() calls

En su caso, la máscara de zona es 0, lo que significa que clamd solicita memoria ZONE_NORMAL.

Las otras banderas están resolviendo

/*
 * Action modifiers - doesn't change the zoning
 *
 * __GFP_REPEAT: Try hard to allocate the memory, but the allocation attempt
 * _might_ fail.  This depends upon the particular VM implementation.
 *
 * __GFP_NOFAIL: The VM implementation _must_ retry infinitely: the caller
 * cannot handle allocation failures.
 *
 * __GFP_NORETRY: The VM implementation must not retry indefinitely.
 */
#define __GFP_WAIT      0x10u   /* Can wait and reschedule? */
#define __GFP_HIGH      0x20u   /* Should access emergency pools? */
#define __GFP_IO        0x40u   /* Can start physical IO? */
#define __GFP_FS        0x80u   /* Can call down to low-level FS? */
#define __GFP_COLD      0x100u  /* Cache-cold page required */
#define __GFP_NOWARN    0x200u  /* Suppress page allocation failure warning */
#define __GFP_REPEAT    0x400u  /* Retry the allocation.  Might fail */
#define __GFP_NOFAIL    0x800u  /* Retry for ever.  Cannot fail */
#define __GFP_NORETRY   0x1000u /* Do not retry.  Might fail */
#define __GFP_NO_GROW   0x2000u /* Slab internal usage */
#define __GFP_COMP      0x4000u /* Add compound page metadata */
#define __GFP_ZERO      0x8000u /* Return zeroed page on success */
#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */
#define __GFP_NORECLAIM  0x20000u /* No realy zone reclaim during allocation */

de acuerdo con la documentación de Linux MM , por lo que su petición de éstos tiene las banderas de GFP_ZERO, GFP_REPEAT, GFP_FS, GFP_IOy GFP_WAIT, siendo por lo tanto no es particularmente exigente.

Entonces, ¿qué pasa con ZONE_NORMAL? Algunas estadísticas genéricas se pueden encontrar más adelante en la salida de OOM:

[kernel] [1772321.850770] Libre normal : 8056kB min: 8048kB bajo: 10060kB alto: 12072kB active_anon: 0kB inactive_anon: 0kB active_file: 248kB inactive_file: 388kB unevictable: 0kB isolated (anon): 0kB isolated (file): 0kB aislado (presente): 0kB

Notable aquí es que freees solo 8K desde miny muy por debajo low. Esto significa que el administrador de memoria de su host está algo angustiado y kswapd ya debería estar intercambiando páginas, ya que está en la fase amarilla del gráfico a continuación: Gráfico del administrador de memoria de Linux

Aquí se proporciona más información sobre la fragmentación de la memoria de la zona:

[kernel] [1772321.850795] Normal: 830 * 4kB 80 * 8kB 0 * 16kB 0 * 32kB 0 * 64kB 0 * 128kB 0 * 256kB 0 * 512kB 0 * 1024kB 0 * 2048kB 1 * 4096kB = 8056kB

básicamente afirmando que tiene una sola página contigua de 4MB con el resto muy fragmentado en páginas principalmente de 4KB.

Entonces recapitulemos:

  • tiene un proceso de tierra de usuario ( clamd) que obtiene memoria, ZONE_NORMALmientras que la asignación de memoria no privilegiada generalmente se realizaría desdeZONE_HIMEM
  • el administrador de memoria en esta etapa debería haber podido servir la página 4K solicitada, aunque parece tener una presión de memoria significativa en ZONE_NORMAL
  • el sistema, según kswapdlas reglas, debería haber visto alguna actividad de paginación de antemano, pero no se está intercambiando nada, incluso bajo presión de memoria ZONE_NORMAL, sin causa aparente
  • Ninguno de los anteriores da una razón definida de por qué oom-killerse ha invocado

Todo esto parece bastante extraño, pero al menos está relacionado con lo que se describe en la sección 2.5 del excelente libro de John O'Gorman "Comprender el administrador de memoria virtual de Linux" :

Como el espacio de direcciones que puede usar el núcleo (ZONE_NORMAL) tiene un tamaño limitado, el núcleo admite el concepto de memoria alta. [...] Para acceder a la memoria entre el rango de 1GiB y 4GiB, el núcleo asigna temporalmente las páginas de la memoria alta a ZONE_NORMAL con kmap (). [...]

Eso significa que para describir 1GiB de memoria, se requieren aproximadamente 11MiB de memoria del núcleo. Por lo tanto, con 16GiB, se consumen 176MiB de memoria, ejerciendo una presión significativa sobre ZONE_NORMAL. Esto no suena tan mal hasta que se tengan en cuenta otras estructuras que usan ZONE_NORMAL. Incluso estructuras muy pequeñas como las entradas de tabla de página (PTE) requieren aproximadamente 16MiB en el peor de los casos. Esto hace que 16GiB sea el límite práctico para la memoria física disponible Linux en un x86 .

(el énfasis es mío)

Dado que 3.2 tiene numerosos avances en la administración de memoria sobre 2.6, esta no es una respuesta definitiva, sino una pista realmente fuerte que buscaría primero. Reduzca la memoria utilizable del host a 16G como máximo utilizando el mem=parámetro del núcleo o extrayendo la mitad de los DIMM del servidor.

En última instancia, use un kernel de 64 bits .

Amigo, es 2015.

el wabbit
fuente
13
Cuando dije anteriormente " No soy un experto ", esto es lo que esperaba leer. +1000, si pudiera pero podría; +1 seguro. ¡Qué gran respuesta!
MadHatter
18
Eso fue hermoso. Todavía hay esperanza para SF.
Romano
9
@dataless Sí. Sospecho que toda su ZONE_NORMAL está llena de metadatos sobre las regiones de memoria superior. Cuando un proceso de usuario solicita páginas de memoria, lo más probable es que solicite ZONE_HIGHMEM (que MM podría actualizar a ZONE_NORMAL si HIGHMEM no tiene más páginas libres para atender la solicitud pero NORMAL sí), por lo que a menos que ZONE_HIGHMEM esté bajo presión de memoria (el suyo no lo es), ZONE_NORMAL no tendrá páginas de procesos de espacio de usuario.
the-wabbit
3
[golpea el teclado con los puños] Dale a este wabbit la recompensa
underscore_d
3
@ the-wabbit Preguntas de la red caliente.
CodesInChaos
4

Unas pocas cosas ...

Mi regla general para el espacio de intercambio ha sido tener al menos 2 veces la cantidad de ram físico. Esto permite al demonio de página / intercambio la capacidad de reorganizar la memoria de manera eficiente.

Server_B tiene 32 GB de RAM, así que intente configurarlo para 64 GB de intercambio. OMI, los 2 GB de espacio de intercambio es el servidor dispone de manera demasiado baja, especialmente para un servidor.

Si no tiene una partición adicional que pueda convertir en una partición de intercambio, puede probar esto creando un archivo y montándolo como una partición de intercambio [será lento]. Ver https://www.maketecheasier.com/swap-partitions-on-linux/

Dado que server_B tiene mucho espacio en disco, --inplace no es necesario, y puede no ser deseado, ya que puede ser lo que está causando que rsync use 32GB. --inplace solo es realmente útil si le falta espacio en el sistema de archivos [que no tiene] o si tiene algún requisito especial de rendimiento.

Supongo que rsync querrá usar 50 GB de RAM [el tamaño del archivo] con sus opciones actuales. Normalmente, rsync no necesita tanta memoria para hacer su trabajo, por lo que una o más de sus opciones pueden ser el problema. Rutinariamente transfiero archivos de 200GB sin ningún problema.

Realice algunas pruebas sin usar opciones. Haga esto con archivos más pequeños, digamos 10GB; esto debería evitar el pánico del kernel, pero aún así permitirle monitorear el comportamiento que está causando el problema. Monitoree el uso de memoria de rsync.

Gradualmente, agregue las opciones, una a la vez, para ver qué opción [o combinación de opciones] hace que rsync comience a expandirse en la RAM (por ejemplo, mientras se realiza la transferencia, el uso de ram de rsync crece proporcionalmente a la cantidad de datos de archivo transferidos, etc.)

Si realmente necesita las opciones que hacen que rsync conserve algo de imagen de archivo ram, necesitará el espacio de intercambio adicional y su tamaño máximo de archivo se limitará en consecuencia.

Algunas cosas más [ACTUALIZADO]:

(1) El seguimiento de la pila del kernel muestra que rsync estaba fallando en la página en un área de mmap. Probablemente esté mapeando el archivo. mmap no ofrece ninguna garantía de que se vaciará en el disco hasta que se cierre el archivo [a diferencia de lectura / escritura] que va al caché de bloques FS de inmediato [donde se vaciará]

(2) El bloqueo / pánico del kernel se produce cuando el tamaño de la transferencia alcanza el tamaño de la RAM. Claramente, rsync está aprovechando esa cantidad de memoria no fscache a través de malloc o mmap. Una vez más, con las opciones que ha especificado, rsync asignará 50 GB de memoria para transferir un archivo de 50 GB.

(3) Transfiera un archivo de 24GB. Eso probablemente funcionará. Luego, inicie el kernel con mem = 16G y vuelva a hacer la prueba del archivo de 24GB. Estallará a 16 GB en lugar de 32 GB. Esto confirmará que rsync realmente necesita la memoria.

(4) Antes de decir que agregar swap es ridículo, intente agregar algunos [a través del método swap-to-file]. Esto es mucho más fácil de hacer y probar que todos los argumentos académicos sobre cómo no se requiere el intercambio. Incluso si no es la solución, puede aprender algo de ella. Apuesto a que la prueba mem = 16G tendrá éxito sin pánico / bloqueo.

(5) Lo más probable es que rsync esté golpeando el intercambio, pero sucede demasiado rápido para ver con la parte superior antes de que OOM entre en acción y mate a rsync. Para cuando rsync llega a 32 GB, otros procesos ya se han visto obligados a intercambiar, especialmente si están inactivos. Quizás, una combinación de "gratis" y "top" le dará una mejor imagen.

(6) Después de que rsync es asesinado, lleva tiempo descargar mmap en el FS. No es lo suficientemente rápido para OOM y comienza a matar otras cosas [algunas obviamente son de misión crítica]. Es decir, mlush flush y OOM están compitiendo. O, OOM tiene un error. De lo contrario, no habría un accidente.

(7) En mi experiencia, una vez que un sistema "golpea la pared de la memoria", Linux tarda mucho en recuperarse por completo. Y, a veces, nunca se recupera correctamente y la única forma de borrarlo es reiniciando. Por ejemplo, tengo 12 GB de RAM. Cuando ejecuto un trabajo que usa 40 GB de memoria [tengo 120 GB de intercambio para acomodar trabajos grandes] y luego lo mato, el sistema tarda unos 10 minutos en volver a la capacidad de respuesta normal [con la luz del disco encendida todo el tiempo] .

(8) Ejecute rsync sin opciones. Esto funcionará Obtenga un ejemplo de referencia para trabajar. Luego agregue de nuevo - en el lugar y vuelva a probar. Luego haga --append-verificar en su lugar. Entonces, prueba ambos. Descubra qué opción obtiene rsync haciendo el enorme mmap. Luego decida si puede vivir sin él. Si --inplace es el culpable, es obvio, ya que tienes mucho espacio en disco. Si debe tener la opción, deberá obtener el espacio de intercambio para acomodar el malloc / mmap que hará rsync.

SEGUNDA ACTUALIZACIÓN:

Haga las pruebas de archivos mem = y más pequeños de lo anterior.

Las preguntas centrales: ¿por qué OOM mata a rsync? ¿Quién / Qué está masticando la memoria?

Leí [pero olvidé] que el sistema tiene 32 bits. Entonces, estoy de acuerdo, rsync puede no ser directamente responsable (a través de malloc / mmap - glibc implementa mallocs grandes a través de mapas anónimos / privados), y la falla de la página mmap de rsync solo dispara OOM por coincidencia. Luego, OOM calcula la memoria total consumida por rsync directa e indirectamente [caché FS, buffers de socket, etc.] y decide que es el candidato principal. Por lo tanto, monitorear el uso de memoria total puede ser útil. Sospecho que se arrastra al mismo ritmo que la transferencia de archivos. Obviamente, no debería.

Algunas cosas que puede monitorear en / proc o / proc / rsync_pid a través de un script perl o python en un bucle rápido [un script bash probablemente no será lo suficientemente rápido para el evento del fin del mundo] que puede monitorear todo los siguientes varios cientos de veces / seg. Puede ejecutar esto con una prioridad más alta que rsync para que se mantenga en RAM y se ejecute para que pueda monitorear las cosas justo antes del bloqueo y, con suerte, durante OOM para que pueda ver por qué OOM se vuelve loco:

/ proc / meminfo: para obtener más grano fino en el uso de intercambio en el "punto de impacto". En realidad, obtener el número final de la cantidad total de RAM que se está utilizando puede ser más útil. Si bien top proporciona esto, puede que no sea lo suficientemente rápido como para mostrar el estado del universo justo antes del "big bang" (por ejemplo, los últimos 10 milisegundos)

/ proc / rsync_pid / directorio fd. Leer los enlaces simbólicos le permitirá identificar qué fd se abre en el archivo de destino (por ejemplo, el enlace de lectura de / proc / rsync_pid / fd / 5 -> target_file). Esto probablemente solo debe hacerse una vez para obtener el número fd [debe permanecer fijo]

Conociendo el número fd, mira / proc / rsync_pid / fdinfo / fd. Es un archivo de texto que se parece a:

pos: <posición_archivo>
banderas: blah_blah
mnt_id: blah_blah

Monitorear el valor "pos" puede ser útil ya que la "última posición del archivo" puede ser útil. Si realiza varias pruebas con diferentes tamaños y opciones mem =, ¿la última posición del archivo rastrea alguno de estos [y cómo]? El sospechoso habitual: posición del archivo == RAM disponible

Pero, la forma más simple es comenzar con "rsync local_file server: remote_file" y verificar que funciona. Puede obtener resultados similares [pero más rápidos] haciendo "ssh server rsync file_a file_b" [primero necesitaría crear un archivo de 50GB_a]. Una manera simple de crear file_a es scp local_system: original_file server: file_a y esto puede ser interesante en sí mismo (por ejemplo, ¿funciona esto cuando se bloquea el rsync? Si scp funciona, pero rsync falla, esto apunta a rsync. Si scp falla, esto apunta a algo más como el controlador NIC). Hacer el ssh rsync también elimina la NIC de la ecuación, lo que puede ser útil. Si eso manguea el sistema, entonces algo está realmente mal. Si tiene éxito, [como he mencionado], comience a agregar las opciones una por una.

Odio desmentir el punto, pero agregar algo de intercambio a través de intercambio a archivo puede cambiar / retrasar el comportamiento del bloqueo y puede ser útil como herramienta de diagnóstico. Si agregar, digamos 16 GB, de intercambio retrasa el bloqueo [medido por el uso de memoria o la posición del archivo de destino] de 32 GB a 46 GB, entonces eso dirá algo.

Puede que no sea un proceso en particular, sino un controlador de kernel errante que está masticando memoria. El vmalloc interno del núcleo asigna cosas y puede intercambiarse. IIRC, no está sujeto a la direccionamiento en todas las circunstancias.

Claramente, la OOM se está confundiendo / entrando en pánico. Es decir, mata a rsync, pero no ve la memoria liberada de manera oportuna y busca a otras víctimas. Algunos de ellos son probablemente críticos para la operación del sistema.

Dejando a un lado malloc / mmap, esto podría ser causado por un caché FS sin vaciar que lleva mucho tiempo (por ejemplo, con 30 GB de datos no vaciados, suponiendo una velocidad de disco de 300 MB / seg, puede tomar 100 segundos vaciarlo). Incluso a ese ritmo, OOM puede ser demasiado impaciente. O, OOM que mata a rsync no inicia el lavado de FS lo suficientemente rápido [o en absoluto]. O la descarga FS ocurre lo suficientemente rápido, pero tiene una versión "perezosa" de las páginas de regreso al grupo libre. Hay algunas opciones / proc que puede configurar para controlar el comportamiento de la caché FS [No recuerdo cuáles son].

Intente arrancar con mem = 4G o algún otro número pequeño. Esto podría reducir el caché de FS y acortar el tiempo de descarga para evitar que OOM busque otras cosas que matar (por ejemplo, el tiempo de descarga se reduce de 100 segundos a <1 segundo). También puede desenmascarar un error OOM que no puede manejar ram física> 4GB en un sistema de 32 bits o algo así.

Además, un punto importante: ejecutar como no root. Nunca se espera que los usuarios raíz mastiquen recursos, por lo que se les otorgan límites más permisivos (por ejemplo, el 99% de la memoria frente al 95% para usuarios no root). Esto puede explicar por qué OOM está en tal estado. Además, esto le da a OOM et. Alabama. más espacio para hacer su trabajo de reclamar memoria.

Craig Estey
fuente
Consulte ¿Cuánto espacio SWAP en un sistema de memoria alta? - y no desea ver que su sistema use 63GB de intercambio. No será utilizable.
Restablecer Monica - M. Schröder
1
swap> RAM solo es realmente útil si se ejecuta sin sobrecompromiso de VM, por lo que el núcleo debe reservar espacio de intercambio para las páginas asignadas hasta que estén sucias y necesiten páginas físicas reales que las respalden. La práctica actual es permitir un exceso de compromiso y ejecutarse con una pequeña cantidad de espacio de intercambio para paginar páginas que solo se tocaron al inicio y no son necesarias en la operación normal. overcommit = 0 con intercambio pequeño está bien si tiene mucha RAM, para la mayoría de los sistemas.
Peter Cordes
Parece que rsync realmente está tratando de usar> 32 GB, por lo que se necesita el intercambio para eso. Es decir, rsync usará 50 GB para este archivo. El 2x ha sido una métrica probada y verdadera durante 30 años. Dado que un disco de 6TB cuesta ~ $ 300, no hay razón para no hacerlo. ¿Qué más podría estar ejecutándose en este servidor que colectivamente superará el límite de RAM?
Craig Estey
1
@CraigEstey 64 GB de intercambio es completamente ridículo ya que, como dije antes, no tenemos grandes procesos de usuario, solo queremos la memoria caché del disco y, como mostró mi registro, estábamos usando CERO intercambio en el momento del accidente. CERO. Además, rsync usa 600 KB de RAM incluso en un archivo de 50 GB. Mi confusión inicial fue que tal vez Linux mantenía agresivamente el caché del disco. Y finalmente, quiero ver algunos números o documentación sobre cuánta memoria usa el kernel para rastrear su espacio de intercambio antes de agregar más a este cuadro.
datos
@dataless He agregado información adicional que explica completamente lo que está sucediendo y por qué. rsync está tomando la memoria a través de malloc / mmap y tendrá una capacidad de 50 GB antes de que se haga. Ver la sección actualizada. Tiene pruebas que pueden probar / refutar lo que estoy diciendo y puede omitir el intercambio agregado inicialmente para probar. Por cierto, he estado programando kernels / drivers por más de 40 años. Tal vez sepa algo que tú no sabes, así que por favor modera el tono. Estoy tratando de ayudar.
Craig Estey
2

clamd? Parece que está utilizando ClamAV y tiene habilitado el escaneo en acceso donde el motor antivirus intenta escanear archivos abiertos en busca de virus, cargando en la memoria, todo el contenido de cada archivo abierto por cualquier otro proceso .

Dependiendo de su postura de seguridad y la necesidad de esta transferencia, debe evaluar deshabilitar el escaneo de acceso ClamAV mientras realiza la transferencia.

oo.
fuente
No sabía que esto era algo que clamav podía hacer ... pero no, solo escaneamos archivos específicos desde clamc. Además, 32 bits, por lo que no hay peligro de que clamav acapare toda la memoria del sistema. (¿ves por qué pensamos que 32 bits seguía siendo una buena idea?)
datos
1
El kernel de Linux informa que clamd es el proceso cuyas solicitudes de asignación de memoria invocan al asesino de OOM: ClamAV es casi con certeza la causa secundaria (la causa principal es que no hay suficiente memoria). Ya sea en el escaneo en acceso o en alguna otra configuración, todos los signos apuntan a ClamAV.
oo.
La próxima vez que inicie rsync, ejecute top y monitoree el tamaño residente del proceso clamd.
oo.
clamd fue el primer proceso en invocar al asesino de Oom, pero también el primero en morir, ya que pesa casi 42 MB (uno de los procesos más grandes en el servidor). El oom_killer se ejecuta repetidamente después de esto hasta que incluso el metalog muere.
datos