Rsync acionou o assassino do Linux OOM em um único arquivo de 50 GB

66

Eu tenho um único arquivo de 50 GB no server_A e estou copiando para o server_B. eu corro

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

Server_B possui 32 GB de RAM com troca de 2 GB. A maioria está ociosa e deveria ter muita RAM livre. Tem muito espaço em disco. Com cerca de 32 GB, a transferência é interrompida porque o lado remoto fechou a conexão.

Server_B agora caiu da rede. Pedimos ao data center para reiniciá-lo. Quando olho para o log do kernel antes de falhar, vejo que ele estava usando 0 bytes de swap e a lista de processos estava usando muito pouca memória (o processo rsync foi listado como 600 KB de RAM), mas o o_miller ficando selvagem, e a última coisa no log é onde mata o processo de leitura do kernel do metalog.

Este é o kernel 3.2.59, de 32 bits (portanto, nenhum processo pode mapear mais de 4 GB de qualquer maneira).

É quase como se o Linux desse mais prioridade ao cache do que aos daemons em execução de longa duração. O que da?? E como posso impedir que isso aconteça novamente?

Aqui está a saída do 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

Aqui está a saída 'top' depois de repetir meu comando rsync como um usuário não 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

Aqui estão os parâmetros 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
sem data
fonte
2
Não sou especialista em ler mensagens de travamento do kernel, mas não vejo nenhuma indicação de que B estivesse usando 32 GB de núcleo. Antes de prosseguirmos no pressuposto de que era, você pode confirmar que é atualmente? Porque há uma grande diferença entre esgotar a memória de uma caixa com 32 GB de núcleo e outra com apenas 4 GB.
MadHatter
Atualizado com saída superior. Isso ocorre após a execução do mesmo comando rsync como um usuário não raiz. Praticamente todos, com exceção de 1 GB, são usados ​​no cache no momento.
dataless
Obrigado. Como eu disse, não sou especialista - mas parecia valer a pena conferir.
MadHatter
você também deve verificar se o seu kernel permite a troca (ou seja, a troca não está desativada) (e você deve dedicar uma parte maior do espaço em disco, digamos 16 GB ou até 32 GB). Algumas pessoas estranhas na rede recomendam desativar a troca, o que é muito errado.
Olivier Dulac 24/09
@OlivierDulac a que configuração você está se referindo? o suporte ao swap está compilado ou não poderíamos montar o swap, e o 'swappiness' está definido como 60. Quanto ao tamanho do swap, isso não tornaria o problema ainda pior em um kernel de 32 bits? A resposta parece que as estruturas de dados do kernel foram o que nos mataram. Não estamos executando 32 GB de processos do usuário, apenas queremos muita memória RAM para cache de disco, para desempenho.
dataless

Respostas:

178

Então, vamos ler o resultado final e ver o que pode ser aprendido a partir daí.

Ao analisar logs do OOM killer, é importante observar o que o acionou. A primeira linha do seu log nos fornece algumas dicas:

[kernel] [1772321.850644] clamd invocou oom-killer: gfp_mask = 0x84d0, ordem = 0

order=0está nos dizendo quanta memória está sendo solicitada. O gerenciamento de memória do kernel é capaz de gerenciar apenas números de página com a potência de 2; portanto, o clamd solicitou 2 0 páginas de memória ou 4KB.

Os dois bits mais baixos do GFP_MASK (máscara de página gratuita) constituem a chamada máscara de zona informando ao alocador de qual zona obter a memória :

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 memória é um conceito criado principalmente por razões de compatibilidade. Em uma exibição simplificada, existem três zonas para um 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

No seu caso, a máscara de zona é 0, o que significa que o clamd está solicitando memória ZONE_NORMAL.

Os outros sinalizadores estão resolvendo para

/*
 * 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 acordo com a documentação do Linux MM , para que o seu requst tem as bandeiras para GFP_ZERO, GFP_REPEAT, GFP_FS, GFP_IOe GFP_WAIT, sendo assim, não é particularmente exigente.

Então, o que se passa ZONE_NORMAL? Algumas estatísticas genéricas podem ser encontradas mais adiante na saída do OOM:

[kernel] [1772321.850770] Normal livre: 8056kB min: 8048kB baixo: 10060kB alto: 12072kB active_anon: 0kB inactive_anon: 0kB arquivo ativo: 248kB arquivo inativo: 388kB inevitável: 0kB isolado (anon): 0kB presente (arquivo): 89k presente:

Notável aqui é que freefica a apenas 8K de distância mine abaixo low. Isso significa que o gerenciador de memória do seu host está um pouco angustiado e o kswapd já deve trocar de página, pois está na fase amarela do gráfico abaixo: Gráfico do gerenciador de memória Linux

Mais informações sobre a fragmentação da memória da região são fornecidas aqui:

[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

basicamente, afirmando que você tem uma única página contígua de 4 MB, com o restante fortemente fragmentado em páginas principalmente de 4KB.

Então, vamos recapitular:

  • você tem um processo de userland ( clamd) obtendo memória, ZONE_NORMALenquanto a alocação de memória não privilegiada geralmente seria realizada a partir deZONE_HIMEM
  • o gerenciador de memória deve, neste estágio, ter sido capaz de veicular a página 4K solicitada, embora você pareça ter uma pressão significativa de memória em ZONE_NORMAL
  • pelas kswapdregras do sistema, o sistema deveria ter visto alguma atividade de paginação antecipadamente, mas nada está sendo trocado, mesmo sob pressão da memória ZONE_NORMAL, sem causa aparente
  • Nenhuma das opções acima fornece uma razão definida para o motivo de oom-killerter sido invocado.

Tudo isso parece bastante estranho, mas deve estar relacionado ao que está descrito na seção 2.5 do excelente livro "Entendendo o Linux Virtual Memory Manager" de John O'Gorman :

Como o espaço de endereços utilizável pelo kernel (ZONE_NORMAL) é limitado em tamanho, o kernel tem suporte para o conceito de Memória Alta. [...] Para acessar a memória entre 1GiB e 4GiB, o kernel mapeia temporariamente as páginas da memória alta para ZONE_NORMAL com kmap (). [...]

Isso significa que, para descrever 1GiB de memória, são necessários aproximadamente 11MiB de memória do kernel. Assim, com 16GiB, 176MiB de memória são consumidos, pressionando significativamente o ZONE_NORMAL. Isso não parece muito ruim até que outras estruturas sejam levadas em consideração e que usem ZONE_NORMAL. Mesmo estruturas muito pequenas, como PTEs (Page Table Entries), exigem cerca de 16MiB no pior dos casos. Isso torna o 16GiB sobre o limite prático para a memória física disponível do Linux em um x86 .

(ênfase é minha)

Como o 3.2 possui vários avanços no gerenciamento de memória acima do 2.6, essa não é uma resposta definitiva, mas uma dica realmente forte que eu buscaria primeiro. Reduza a memória utilizável do host para no máximo 16G usando o mem=parâmetro kernel ou retirando metade dos DIMMs do servidor.

Por fim, use um Kernel de 64 bits .

Cara, é 2015.

o wabbit
fonte
13
Quando eu disse acima " não sou especialista ", era isso que eu esperava ler. +1000, se eu pudesse; +1 com certeza. Que ótima resposta!
MadHatter
18
Isso foi lindo. Ainda há esperança para SF.
Roman
9
@dataless Sim. Suspeito que todo o seu ZONE_NORMAL esteja preenchido com metadados sobre as regiões superiores da memória. Quando um processo da terra do usuário está solicitando páginas de memória, é provável que ele solicite ZONE_HIGHMEM (que pode ser atualizado pelo MM para ZONE_NORMAL se HIGHMEM não tiver mais páginas gratuitas para atender à solicitação, mas NORMAL tiver), portanto, a menos que ZONE_HIGHMEM esteja sob pressão de memória (a sua não é), ZONE_NORMAL não terá páginas de processos no espaço do usuário.
the-wabbit 24/09
3
[SLAMS punhos no teclado] dar a este wabbit a recompensa
underscore_d
3
@ the-wabbit Perguntas sobre redes quentes.
CodesInChaos
4

Algumas coisas ...

Minha regra geral para o espaço de troca é ter pelo menos duas vezes a quantidade de memória RAM física. Isso permite que o daemon de página / troca reorganize a memória com eficiência.

O Server_B possui 32 GB de RAM, portanto, tente configurá-lo para 64 GB de swap. IMO, a 2 GB de espaço de troca o servidor tem é maneira muito baixo, especialmente para um servidor.

Se você não possui uma partição extra que pode ser transformada em uma partição swap, você pode testar isso criando um arquivo e montando-o como uma partição swap [será lenta]. Consulte https://www.maketecheasier.com/swap-partitions-on-linux/

Como server_B possui bastante espaço em disco, --inplace não é necessário e pode ser indesejável, pois pode estar causando o rsync a usar 32GB. --inplace só é realmente útil se você estiver com pouco espaço no sistema de arquivos [que não é] ou se tiver algum requisito especial de desempenho.

Meu palpite é que o rsync desejará usar 50 GB de RAM [o tamanho do arquivo] com suas opções atuais. Normalmente, o rsync não precisa de tanta memória para fazer seu trabalho, então uma ou mais de suas opções podem ser o problema. Eu transfiro rotineiramente arquivos de 200 GB sem problemas.

Faça algumas execuções de teste sem opções. Faça isso com arquivos menores, digamos 10 GB - isso deve evitar o pânico do kernel, mas ainda permitir que você monitore o comportamento que está causando o problema. Monitore o uso da memória do rsync.

Gradualmente, adicione novamente as opções, uma de cada vez, para ver qual opção [ou combinação de opções] faz com que o rsync comece a se destacar na RAM (por exemplo, enquanto a transferência está acontecendo, o uso de ram do rsync aumenta proporcionalmente à quantidade de dados do arquivo transferido, etc.)

Se você realmente precisa das opções que fazem com que o rsync mantenha alguma imagem de arquivo in-ram, precisará de espaço de troca extra e o tamanho máximo do arquivo será limitado de acordo.

Mais algumas coisas [ATUALIZADO]:

(1) O traceback da pilha do kernel mostra que o rsync estava com falha de página em uma área mmap. Provavelmente, está mamando o arquivo. O mmap não oferece garantia de que será liberado para o disco até que o arquivo seja fechado [ao contrário da leitura / gravação], que vai para o cache do bloco FS imediatamente [onde será liberado]

(2) O travamento / pânico do kernel ocorre quando o tamanho da transferência atinge o tamanho da RAM. Claramente, o rsync está capturando tanta memória não-fscache via malloc ou mmap. Mais uma vez, com as opções que você especificou, o rsync alocará 50 GB de memória para transferir um arquivo de 50 GB.

(3) Transfira um arquivo de 24 GB. Provavelmente isso funcionará. Em seguida, inicialize o kernel com mem = 16G e faça o teste de arquivo de 24 GB novamente. Ele explodirá em 16 GB em vez de 32 GB. Isso confirmará que o rsync realmente precisa da memória.

(4) Antes de você dizer que adicionar swap é ridículo, tente adicionar alguns [pelo método swap-to-file]. Isso é muito mais fácil de fazer e testar do que todos os argumentos acadêmicos sobre como a troca não é necessária. Mesmo que não seja a solução, você pode aprender algo com isso. Aposto que o teste mem = 16G terá sucesso sem pânico / acidente.

(5) As chances são de que o rsync esteja atingindo a troca, mas isso acontece muito rápido para ver com o top antes do OOM entrar em ação e matar o rsync. Quando o rsync chega aos 32 GB, outros processos já foram forçados a trocar, principalmente se estiverem ociosos. Talvez, uma combinação de "livre" e "superior" proporcione uma imagem melhor.

(6) Após o rsync ser morto, leva tempo para liberar o mmap para o FS. Não é rápido o suficiente para o OOM e começa a matar outras coisas [algumas são obviamente de missão crítica]. Ou seja, o mmap flush e o OOM estão correndo. Ou, OOM tem um erro. Caso contrário, não haveria um acidente.

(7) Na minha experiência, uma vez que um sistema "atinge a parede da memória", o Linux leva muito tempo para se recuperar totalmente. E, às vezes, ele nunca se recupera corretamente e a única maneira de limpá-lo é uma reinicialização. Por exemplo, tenho 12 GB de RAM. Quando executo um trabalho que usa 40 GB de memória [tenho 120 GB de swap para acomodar trabalhos grandes] e depois o corro, leva cerca de 10 minutos para o sistema retornar à capacidade de resposta normal [com a luz do disco acesa o tempo todo] .

(8) Execute o rsync sem opções. Isso vai funcionar. Obtenha um exemplo de linha de base para trabalhar. Em seguida, adicione novamente --inplace e teste novamente. Em seguida, faça --append-verifique. Então, tente os dois. Descubra qual opção obtém o rsync fazendo o enorme mmap. Então decida se você pode viver sem ele. Se --inplace é o culpado, isso é óbvio, já que você tem bastante espaço em disco. Se você tiver a opção, precisará obter o espaço de troca para acomodar o malloc / mmap que o rsync fará.

SEGUNDA ATUALIZAÇÃO:

Por favor, faça os testes mem = e arquivos menores do acima.

As perguntas centrais: Por que o rsync é morto pelo OOM? Quem / O que é mastigar memória?

Eu li [mas esqueci] sobre o sistema ter 32 bits. Portanto, concordo que o rsync pode não ser diretamente responsável (via malloc / mmap - a glibc implementa grandes mallocs por mmaps anônimo / privado), e a falha da página mmap do rsync apenas aciona o OOM por coincidência. Em seguida, o OOM calcula a memória total consumida pelo rsync direta e indiretamente [cache do FS, buffers de soquete etc.] e decide que é o candidato principal. Portanto, o monitoramento do uso total de memória pode ser útil. Eu suspeito que ele se arraste na mesma taxa que a transferência de arquivos. Obviamente, não deveria.

Algumas coisas que você pode monitorar em / proc ou / proc / rsync_pid por meio de um script perl ou python em um loop rápido [um script bash provavelmente não será rápido o suficiente para o evento de fim do mundo] que pode monitorar todos as seguintes centenas de vezes / s. Você pode executar isso com uma prioridade mais alta que o rsync, para que ele se mantenha na RAM e em execução, para que você possa monitorar as coisas imediatamente antes da falha e, esperançosamente, durante o OOM, para que você possa ver por que o OOM fica louco:

/ proc / meminfo - para obter mais detalhes sobre o uso da troca no "ponto de impacto". Na verdade, obter o número final de quanto de RAM está sendo usado total pode ser mais útil. Enquanto o top fornece isso, pode não ser rápido o suficiente para mostrar o estado do universo imediatamente antes do "big bang" (por exemplo, os últimos 10 milissegundos)

Diretório / proc / rsync_pid / fd. A leitura dos links simbólicos permitirá que você identifique qual fd é aberto no arquivo de destino (por exemplo, link de leitura de / proc / rsync_pid / fd / 5 -> target_file). Provavelmente, isso só precisa ser feito uma vez para obter o número fd [ele deve permanecer fixo]

Conhecendo o número fd, consulte / proc / rsync_pid / fdinfo / fd. É um arquivo de texto que se parece com:

pos: <posição do arquivo>
bandeiras: blah_blah
mnt_id: blah_blah

O monitoramento do valor "pos" pode ser útil, pois a "última posição do arquivo" pode ser útil. Se você fizer vários testes com tamanhos variados e opções mem =, a última posição do arquivo rastreia algum desses [e como]? O suspeito comum: posição do arquivo == RAM disponível

Mas, a maneira mais simples é começar com "rsync local_file server: remote_file" e verificar se funciona. Você pode obter resultados semelhantes [mas mais rápidos] executando "ssh server rsync file_a file_b" [você precisaria criar um arquivo de 50GB_a primeiro]. Uma maneira simples de criar file_a é scp local_system: original_file server: file_a e isso pode ser interessante por si só (por exemplo, isso funciona quando o rsync falha? Se o scp funcionar, mas o rsync falhar, isso indica o rsync. Se o scp falhar, isso aponta para outra coisa como o driver da NIC). Fazer o ssh rsync também remove a NIC da equação, o que pode ser útil. Se isso mangueira o sistema, algo está realmente errado. Se for bem-sucedido, [como eu mencionei], comece a adicionar de volta as opções, uma por uma.

Eu odeio insistir nesse ponto, mas adicionar alguma troca via troca para arquivo pode alterar / atrasar o comportamento da falha e pode ser útil como uma ferramenta de diagnóstico. Se adicionar, digamos 16 GB, ao swap atrasar a falha [medida pelo uso da memória ou pela posição do arquivo de destino] de 32 GB para 46 GB, isso dirá algo.

Pode não ser um processo específico, mas um driver de kernel incorreto que está mastigando memória. O vmalloc interno do kernel aloca coisas e pode ser trocado. IIRC, não está vinculado à endereçamento em todas as circunstâncias.

Claramente, o OOM está ficando confuso / em pânico. Ou seja, mata o rsync, mas não vê a memória liberada em tempo hábil e procura outras vítimas. Alguns deles são provavelmente críticos para a operação do sistema.

malloc / mmap à parte, isso pode ser causado por um cache FS não liberado que demora muito tempo (por exemplo, com 30 GB de dados não liberados, assumindo uma taxa de disco de 300 MB / s, pode levar 100 segundos para liberá-lo). Mesmo a esse ritmo, o OOM pode ser muito impaciente. Ou, o OOM que mata o rsync não inicia o FS flush com rapidez suficiente [ou nada]. Ou o FS flush acontece com rapidez suficiente, mas possui uma versão "lenta" das páginas de volta ao pool gratuito. Existem algumas opções / proc que você pode definir para controlar o comportamento do cache do FS [não me lembro o que são].

Tente inicializar com mem = 4G ou algum outro número pequeno. Isso pode reduzir o cache do FS e diminuir o tempo de liberação para impedir que o OOM procure outras coisas a eliminar (por exemplo, o tempo de liberação é reduzido de 100 para <1 segundo). Também pode desmascarar um bug do OOM que não pode lidar com memória RAM física> 4 GB em um sistema de 32 bits ou algo parecido.

Além disso, um ponto importante: execute como não raiz. Nunca é esperado que os usuários root consigam mastigar recursos; portanto, eles recebem mais limites de perdão (por exemplo, 99% da memória versus 95% para usuários não root). Isso pode explicar por que o OOM está nesse estado. Além disso, isso fornece à OOM et. al. mais espaço para fazer seu trabalho de recuperar a memória.

Craig Estey
fonte
Consulte Quanto espaço SWAP em um sistema com alta memória? - e você não deseja que seu sistema use 63GB de swap. Não será utilizável.
Reinstate Monica - M. Schröder
11
swap> RAM só é realmente útil se você executar sem o supercomprometimento da VM; portanto, o kernel precisa reservar espaço de troca para as páginas alocadas até que estejam sujas e precisem de páginas físicas reais para apoiá-las. A prática atual é permitir a confirmação excessiva e executar com uma pequena quantidade de espaço de troca para paginar as páginas que foram tocadas apenas na inicialização e que não são necessárias na operação normal. overcommit = 0 com troca pequena é bom se você tiver muita RAM, na maioria dos sistemas.
Peter Cordes
Parece que o rsync realmente está tentando usar> 32 GB, portanto a troca é necessária para isso. Ou seja, o rsync utilizará 50 GB para esse arquivo. O 2x é uma métrica comprovada e comprovada há 30 anos. Como um disco de 6 TB custa ~ US $ 300, não há razão para não fazê-lo. O que mais pode estar em execução neste servidor que coletivamente ultrapassará o limite de RAM?
Craig Estey
11
O @CraigEstey de 64 GB de swap é completamente ridículo, pois, como afirmei anteriormente, não temos grandes processos de usuário, queremos apenas o cache do disco e, como meu log mostrou, estávamos usando o ZERO swap no momento do travamento. ZERO. Além disso, o rsync usa 600 KB de memória RAM, mesmo em um arquivo de 50 GB. Minha confusão inicial foi que talvez o linux estivesse segurando agressivamente o cache do disco. E, finalmente, quero ver alguns números ou documentação sobre quanta memória o kernel usa para rastrear seu espaço de troca antes de adicionar mais a essa caixa.
dataless
@dataless Adicionei informações adicionais que explicam completamente o que está acontecendo e por quê. O rsync está capturando a memória via malloc / mmap e gastará 50 GB antes de terminar. Veja a seção atualizada. Possui testes que podem provar / refutar o que estou dizendo e você pode pular a troca adicionada inicialmente para testar. BTW, eu tenho programado kernels / drivers há mais de 40 anos - talvez eu saiba algo que você não sabe, então, por favor, modere o tom - estou tentando ajudar.
Craig Estey
2

clamd? Parece que você está usando o ClamAV e tem a verificação no acesso ativada, onde o mecanismo antivírus tenta verificar se há vírus nos arquivos abertos, carregando na memória todo o conteúdo de cada arquivo aberto por qualquer outro processo .

Dependendo da sua postura de segurança e da necessidade dessa transferência, você deve avaliar a desativação da verificação de acesso ao ClamAV enquanto realiza a transferência.

oo.
fonte
Eu não sabia que isso era algo que o clamav poderia fazer ... mas não, apenas analisamos arquivos específicos canalizados pelo clamc. Além disso, 32 bits, portanto não há perigo de obstruir toda a memória do sistema. (você vê por que pensávamos que 32 bits ainda era uma boa ideia?) #
315
11
O kernel do Linux está relatando que clamd é o processo cujas solicitações de alocação de memória estão invocando o assassino do OOM - o ClamAV é quase certamente a causa secundária (a causa principal não é memória suficiente). Seja na varredura ao acessar ou em alguma outra configuração, todos os sinais apontam para o ClamAV.
oo.
Da próxima vez que você iniciar o rsync, execute o top e monitore o tamanho residente do processo clamd.
oo.
O clamd foi o primeiro processo a chamar o oom killer, mas também o primeiro a morrer, já que pesa quase 42 MB (um dos processos maiores no servidor). O oom_killer roda repetidamente depois disso até que até o metalog seja morto.
dataless