Para aqueles que leram sobre containers e Docker , mas não entendem como o Java se agarrou aos containers. Primeiro, vamos refrescar nossa memória sobre a memória Java . Deixe-me lembrá-lo que a memória consiste em Stack e Heap, que utilizam a RAM (memória de acesso aleatório) do servidor; quando falarmos mais sobre memória, nos referiremos à RAM. Agora vamos dar uma olhada no contêiner em seção transversal. Não, claro que não, não estamos interessados na garupa e nas coxas, vamos olhar a estrutura da memória no container. Pode ser dividido em três partes: • Memória Heap – o próprio heap; • Off Heap é tudo que não está no heap; • Sobrecarga do SO é a sobrecarga de memória para implementar processos dentro do contêiner. Digamos: Alocamos 1 Gb para o container, na figura será Container Limit - seus limites são indicados por um retângulo azul. Alocamos 80%, ou seja, 0,8 Gb, para memória Java no contêiner, e o Heap nos ocupou cerca de 80% do contêiner, ou seja, não muito menos que 0,8 Gb, porque o OS Overhead tomou parte dos recursos (overhead) para manutenção de processos. Restam cerca de 20% do contêiner para tudo que não está conectado ao heap ( Off Heap ). A área Usada na figura mostra a área de memória usada para executar o aplicativo. Agora precisamos falar sobre situações em que a memória do contêiner pode acabar. OutOfMemoryError Se o consumo de memória do aplicativo ( Área usada ) atingir os limites de heap ( Heap ), capturaremos um OutOfMemoryError (OOM Error) . O que indica que não há espaço suficiente no heap, nomeadamente, na área da memória onde são colocados os objetos criados programaticamente na aplicação. Se ainda não estiver totalmente claro, explicarei em gatos. Erro OOM é quando um gato grita muito, muito tempo na frente das portas da varanda, e quando essa porta é aberta, ele fica parado na porta e não vai para nenhum dos lados, costumam dizer que o gato está congelado. Se você empurrá-lo a tempo, ele ficará de queixo caído e irá para a varanda fazer suas necessidades de gatinho. OOM Killer Esta é outra situação que pode acontecer em um contêiner quando a memória acaba. Se um programa sai do contêiner, obtemos um OutOfMemory Killer (OOM Killer) - este é um processo que encerra o aplicativo para evitar que o kernel trave. Ele sacrifica o aplicativo para manter o contêiner em execução. Não é fato que o contêiner cairá, mas o aplicativo que roda nele certamente cairá. Isso acontece se você deixar o consumo de memória de uma aplicação Java sem controle. Novamente em gatos. Se você decidiu dormir mais no sábado e esqueceu de dar comida aos gatos, então OOM Killeras flores estão garantidas, os vasos não podem ser danificados, mas as flores terão que ser replantadas. Qual é a diferença entre erro OOM e assassino OOM? Você pode processar o erro OOM e executar algumas ações (por exemplo: dimensionar o aplicativo), e o OOM Killer simplesmente encerrará todo o processo. OOM Killer é semelhante ao kill-9 (kill menos nove) – um comando que mata um processo no Linux . O fato é que a implementação de contêiner mais popular é o contêiner Docker, que é baseado em Linux , mesmo se você executá-lo no Windows , o kernel ainda será do Linux . No Linux, estamos interessados em um conceito: CGroups (grupo de controle em inglês) - um mecanismo do kernel Linux que limita e isola recursos de computação (processador, rede, recursos de memória, recursos de E/S) para grupos de processos. Simplificando, esse mecanismo permite gerenciar recursos em um contêiner, no nosso caso, memória. Como o Java se relaciona com isso? É através do mecanismo CGroups que o Java pode se conectar à memória do contêiner. Mas tudo isso depende da versão do Java. Por exemplo, Java 7 não sabe como usar CGroups e os limites do contêiner são desconhecidos para ele. Por padrão, tamanho máximo de heap = ¼ memória física. Se o aplicativo exceder os limites do contêiner, haverá um OOM Killer e, se os limites do contêiner não forem definidos, o aplicativo consumirá memória de outros aplicativos no servidor (é melhor definir limites, caso contrário, todos perderão) . Você pode, é claro, usar configurações de heap ou "imagens" especiais que resolvem esse problema, mas a maneira mais fácil é usar a versão correta do Java. As versões corretas começam com Java 8 x131 (portado do Java 9), ele começa a entender CGroups . E no Java 10 apareceu o suporte para containers: UseContainerSupport , posteriormente essa função foi portada para Java 8 x 191 . Ou você pode simplesmente usar Java: 11+ . O que pode ser concluído: Ao usar memória contêiner, você pode receber um OutOfMemoryError (OOM Error) ou OutOfMemoryKiller (OOM Killer). No primeiro caso, o aplicativo não irá travar imediatamente, o erro OOM pode ser detectado, processado e ações controladas podem ser executadas. Por exemplo, dimensione o aplicativo. Se ocorrer um OOM Killer, o aplicativo irá travar imediatamente e não haverá mais opções para salvá-lo. E o pior é que externamente o próprio contêiner ficará bem, ou seja, você pode nem suspeitar que algo caiu ali. Mecanismos Linux são usados para interagir com contêiner e memória Java. Mas nem todo Java os implementa. Para evitar problemas com Java 8, você precisa usar uma versão a partir de 131, ou melhor ainda, de 191. Ou use Java: 11+. Para praticar: OutOfMemoryError: capture-o se puder
Павел
Nível 11
GO TO FULL VERSION