Estou tentando entender como as solicitações e limites de memória funcionam com o cgroup v2. No manifesto do Kubernetes, podemos configurar a solicitação e o limite de memória. Esses valores são então usados para configurar a interface do cgroup:
- memory.min está definido para solicitação de memória
- memory.max está definido como limite de memória
- memory.high é definido como limite de memória * 0,8, a menos que a solicitação de memória == limite, caso em que memory.high permanece indefinido
- memory.low está sempre desmarcado
memory.max é bastante autoexplicativo: quando um processo no cgroup tenta alocar uma página e isso coloca o uso de memória acima de memory.max e não é possível recuperar páginas suficientes do cgroup para satisfazer a solicitação dentro de memory.max, então o OOM killer é invocado para encerrar um processo dentro do cgroup. memory.high é mais difícil de entender: a documentação do kernel diz que o cgroup é colocado sob "alta pressão de recuperação" quando a marca d'água alta é atingida, mas o que isso significa exatamente?
Mais adiante diz:
Quando atingido, ele limita as alocações, forçando-as a uma recuperação direta para eliminar o excesso, mas nunca invoca o assassino OOM.
Estou correto em assumir que isso significa que quando o cgroup tenta alocar uma página além da marca d'água memory.high, ele vai olhar sincronicamente para o lruvecs e tentar recuperar o máximo de páginas do final das listas até que esteja de volta abaixo da marca d'água alta? Ou a "pressão de recuperação" é algo que acontece assincronamente (por meio do kswapd)?
Pergunta 2: Qual é o objetivo de usar memory.high no Kubernetes? Até onde eu sei, os nós do Kubernetes normalmente são executados sem espaço de swap. As únicas páginas que podem ser recuperadas são páginas anônimas (se houver swap suficiente disponível) e cache de página. Como não há swap, isso deixa apenas o cache de página. O problema é que o cache de página também seria recuperado ao atingir memory.max, antes de invocar o OOM killer como último recurso se nada puder ser recuperado. Então memory.high é essencialmente inútil:
Enquanto o cache de página for usado, ele sempre pode ser recuperado e memory.max também faria isso. Com memory.high, estamos apenas limitando o aplicativo antes do que precisamos. Poderíamos muito bem definir memory.max mais baixo em primeiro lugar.
Se nenhum cache de página significativo for usado (o que provavelmente é o caso da maioria dos aplicativos que executam o Kubernetes hoje), então nada pode ser recuperado, portanto, não há limitação (nenhuma paginação de memória anônima não utilizada, nenhuma thrashing visível nas informações de bloqueio de pressão que nos avisariam) e encontraremos memory.max sem saber. Usar memory.high não tem efeito.