Performance Impact of Memory Compaction (kcompactd) in UEK7 with Large HugePages Allocations.

Esta semana, estive envolvido em um problema de performance que, até então, nunca havia enfrentado. Um cliente relatou que um determinado job, responsável pela execução de aproximadamente 3.859 SQL_IDs distintos, estava apresentando uma degradação significativa em seu tempo de execução.

Normalmente, esse job era executado dentro de uma janela de aproximadamente 2 a 4 horas, dependendo do volume de dados processado naquele momento. No entanto, o tempo de execução começou a aumentar, impactando diretamente o processamento e a janela operacional do ambiente Exadata X11.

Informações e configurações do ExaCS X11.

[root@vcp-qc7tb1 ~]# uname -r
5.15.0-308.179.6.7.el8uek.x86_64
[root@vcp-qc7tb1 ~]# uname -a
Linux vcp-qc7tb1 5.15.0-308.179.6.7.el8uek.x86_64 #2 SMP Thu Jun 12 20:04:53 PDT 2025 x86_64 x86_64 x86_64 GNU/Linux

[root@vcp-qc7tb2 ~]# uname -r
5.15.0-308.179.6.7.el8uek.x86_64
[root@vcp-qc7tb2 ~]# uname -a
Linux vcp-qc7tb2 5.15.0-308.179.6.7.el8uek.x86_64 #2 SMP Thu Jun 12 20:04:53 PDT 2025 x86_64 x86_64 x86_64 GNU/Linux

[root@vcp-qc7tb1 ~]# nproc
46
[root@vcp-qc7tb1 ~]# free -lgh
              total        used        free      shared  buff/cache   available
Mem:          983Gi       595Gi       311Gi        12Gi        75Gi       354Gi
Low:          983Gi       671Gi       311Gi
High:            0B          0B          0B
Swap:          15Gi        11Mi        15Gi

[root@vcp-qc7tb2 ~]# free -lght
46
[root@vcp-qc7tb2 ~]# free -lght
              total        used        free      shared  buff/cache   available
Mem:          983Gi       573Gi       355Gi        27Gi        53Gi       365Gi
Low:          983Gi       627Gi       355Gi
High:            0B          0B          0B
Swap:          15Gi          0B        15Gi
Total:        999Gi       573Gi       371Gi

Databases existentes na versão 19c:

[oracle@vcp-qc7tb1 oratop]$ ps -ef | grep smon
grid      45469      1  0 Aug15 ?        00:00:25 asm_smon_+ASM1
oracle    62706      1  0 Aug15 ?        00:00:50 ora_smon_CDBPRD021
oracle    62893      1  0 Aug15 ?        00:00:23 ora_smon_CDBPRD21
oracle    63467      1  0 Aug15 ?        00:00:33 ora_smon_CDBPRD41
oracle    63499      1  0 Aug15 ?        00:00:32 ora_smon_CDBPRD51
oracle    63511      1  0 Aug15 ?        00:00:33 ora_smon_CDBPRD31
oracle   106647      1  0 Aug28 ?        00:00:05 ora_smon_CDBPRD71
oracle   283936      1  0 Aug28 ?        00:00:56 ora_smon_CDBPRD11

Historico de execução do job:

Considerando a configuração do ExaCS X11 e a quantidade de databases hospedados no ambiente, iniciei a análise avaliando a performance do job e os planos de execução de cada SQL_ID executado. Para identificar possíveis diferenças de comportamento, comparei as execuções realizadas nos melhores dias com aquelas observadas nos dias de pior desempenho.

Durante o período do incidente (01/08 a 30/08), os cabeçalhos do sar registraram 46 CPUs em 28 dos 30 dias. Por se tratar de ambiente ExaCS com OCPU elástica, essa contagem varia ao longo do tempo — houve dias com 70 e 78 CPUs. Todas as comparações apresentadas neste post usam as janelas em que o ambiente operava com 46 CPUs. Memória total: 983 GiB por nó, distribuídos em 2 nós NUMA.

Estatisticas de uma trace do job:

Após essa análise, o Carlos Furushima Linkedin do Carlos, que é um excelente consultor e já havia atuado em outras crises no passado, foi envolvido para olhar o problema por uma perspectiva diferente. Foi então que ele identificou o que estava acontecendo: Os processos kcompactd0 e kcompactd1, responsáveis pela compactação proativa de memória no kernel, estavam impactando o ambiente.

A recomendação do Carlos foi reduzir o valor configurado no parâmetro nr_hugepages, diminuindo a quantidade de HugePages estáticas reservadas no sistema, uma vez que aproximadamente 111 GB permaneciam reservados, porém sem utilização efetiva.

Após a alteração, o comportamento do ambiente voltou à normalidade, e o job passou a ser executado novamente dentro da janela anteriormente observada, com tempo de execução de, no máximo, 2 horas e 30 minutos.

Mesmo depois da correção do problema, fiquei com essa questão na cabeça. Eu queria entender melhor o que realmente havia acontecido e, principalmente, qual era a causa raiz do problema. Por isso, fui estudar o comportamento desse mecanismo do kernel e pesquisar mais a fundo o que estava acontecendo no ambiente. Abaixo, compartilho os detalhes dessa análise e o que consegui entender durante a pesquisa.

Vamos entender o funcionamento da compactação proativa para o kernel:

1 – A compactação proativa (vm.compaction_proactiveness) foi introduzida no kernel 5.9 e chegou ao ambiente com o UEK7. Ela não existia no UEK6 nem no Oracle Linux 7.

2 – As threads kcompactd acordam a cada 500 ms e calculam o fragmentation score do nó.

3 – Com o valor padrão de proatividade 20, os limiares são: inicia acima de 90, para abaixo de 80.

4 – A compactação executa até o score cair ao limiar inferior ou até uma condição de desistência.

O Sintoma Observado no sistema operacional relacionados ao uso de CPU pelo processo do kcompactd:

Evidências coletadas com o SAR:

Evidência 1 – Saída do top em 29/08/2026 mostrando kcompactd0 a 100,0% e kcompactd1 a 99,7% de CPU, com tempo acumulado de 17080:36 e 16738:33 minutos.

O campo TIME+ está em minutos. Convertendo:

ThreadTempo de CPU acumulado
kcompactd017.080 min = 284,7 horas
kcompactd116.738 min = 279,0 horas

Evidência 2 – Hugepage configurado de 594,00 GB:

SGA dos Databases configurados com use_large_pages=ONLY:

InstânciaSGA
CDBPRD11 / CDBPRD12290,50 GB
CDBPRD51 / CDBPRD5260,00 GB
CDBPRD71 / CDBPRD7250,00 GB
CDBPRD31 / CDBPRD3240,00 GB
CDBPRD41 / CDBPRD4215,00 GB
CDBPRD21 / CDBPRD2210,00 GB
CDBPRD021 / CDBPRD0227,42 GB
Total472,92 GB

Desperdício: 594,00 − 482,97 (usado com overhead) = 111,03 GB de RAM reservada e ociosa.

A métrica kbhugfree permaneceu constante em 111,03 GB entre 01/08 e 28/08, em ambos os nós, enquanto a métrica %hugused permaneceu em aproximadamente 81%.

O comportamento foi representado por uma linha praticamente reta durante todo o período, sem variações significativas. Isso ocorre porque a SGA é estática e, portanto, o pool de HugePages não apresentaria crescimento para ocupar o espaço adicional reservado.

Evidência 3 – Painel HugePages do kSar (qc7tb2). Painel superior: kbhugfree (vermelho) constante em ~111 Gi. Painel inferior: %hugused (verde) cravado em 81% por 28 dias, saltando para ~98% após a correção.

Evidência 5 – Estado da memória antes da correção:

numastat -m no qc7tb2:
                    Node 0        Node 1        Total
MemTotal          503052.80     503593.88    1006646.68  MB
MemFree            69289.68       7119.35      76409.04  MB
Inactive(file)    118463.17     190421.02     308884.18  MB
HugePages_Total   247662.00     246896.00     494558.00  MB
AnonHugePages          0.00          0.00          0.00  MB

Os mesmos valores convertidos para GB:

MétricaNode 0Node 1Total
MemTotal491,26 GB491,79 GB983,05 GB
MemFree67,67 GB6,95 GB74,62 GB
Inactive(file)115,69 GB185,96 GB301,64 GB
HugePages_Total241,86 GB241,11 GB482,97 GB
AnonHugePages0,00 GB0,00 GB0,00 GB

Evidência 6 – Índice de fragmentação calculado a partir de /proc/buddyinfo (2 MB, tamanho de uma huge page):

ZonaFragmentação ordem 9Fragmentação ordem 10
Node 0, Normal96,90%99,76%
Node 1, Normal97,58%100,00%

Com base nas evidências coletadas do ambiente, o score calculado era de 96 no nó NUMA 0 e 97 no nó NUMA 1, acima do limite de acionamento (trigger) de 90 e da meta de 80. Como 482,97 GB (aproximadamente 49% da memória RAM) estavam alocados em HugePages estáticas, essas páginas permaneciam reservadas e não podiam ser migradas durante o processo de compactação. Dessa forma, havia memória insuficientemente disponível e elegível para movimentação, impedindo que a compactação reduzisse o score aos níveis esperados.

Resultado: Meta inatingível do score, perseguida indefinidamente. As threads compactavam, não progrediam, e reiniciavam o ciclo por 285 horas de CPU acumulativas.

O kernel não avalia fragmentação de forma subjetiva — ele calcula um número inteiro por nó NUMA e o compara com dois limiares fixos. Abaixo está a fórmula conforme implementada em mm/compaction.c e mm/vmstat.c no kernel 5.15, aplicada aos valores medidos no servidor.

Índice de fragmentação por zona (extfrag_for_order, em mm/vmstat.c):

extfrag(zona, ordem) = ((Fz − Hz) / Fz) × 100

Onde Fz é o total de páginas livres da zona e Hz é o número de páginas livres que estão em blocos de tamanho igual ou maior que a ordem pedida (ordem 9 = 2 MB).

Cálculo do fragmentation score:

score(zona) = extfrag(zona, 9) × present_pages(zona) / (present_pages(nó) + 1)
score(nó) = Σ score(zona)
wmark_low = 100 − vm.compaction_proactiveness = 80
wmark_high = wmark_low + 10 = 90

Proactive compaction for the kernel
Proactive Compaction
Linux Memory Compaction: Internals and Debugging

Aplicação aos valores medidos (qc7tb2, antes da correção):

Índices por zona calculados a partir de /proc/buddyinfo na ordem 9, e present_pages derivado do numastat -m (MemTotal de 491,26 GB no nó 0 e 491,79 GB no nó 1. As zonas DMA e DMA32 são estimadas em 0,02 GB e 3,81 GB, valores padrão em x86_64):

Zonapresent (GB)extfrag (ordem 9)pesocontribuição
Node 0 / DMA0,029,09%0,00000,00
Node 0 / DMA323,810,13%0,00780,00
Node 0 / Normal487,4496,90%0,992296,15
score do Node 096
Node 1 / Normal491,7997,58%1,000097,58
score do Node 197

Interpretação:

score Node 0 = 96 > wmark_high (90) → compactação ativa
score Node 1 = 97 > wmark_high (90) → compactação ativa
meta a atingir = wmark_low (80)

Ambos os nós estavam 6 e 7 pontos acima do gatilho, e precisariam cair 16 e 17 pontos para que as threads parassem o processo de compactação.

Para solucionar o problema, ajustamos a configuração de HugePages para considerar o valor correspondente à soma total das SGA de todos os databases do ambiente. Após essa alteração, o ambiente voltou a apresentar excelente desempenho, e o job que apresentava problemas de performance retornou ao seu tempo médio de execução, restabelecendo o comportamento esperado.

Correção aplicada:

sysctl -w vm.nr_hugepages=247279

Comparando as janelas de três dias antes e dois dias depois, no qc7tb1:

Métrica25–27/0829–30/08Variação
%sys8,35%4,46%−3,88 pp
%usr57,40%57,84%+0,44 pp

Após a alteração, no qc7tb1, a memória livre aumentou significativamente, atingindo 313 GB. No qc7tb2, observou-se um aumento do page cache, que chegou a 345 GB, evidenciando a liberação e a melhor utilização da memória anteriormente reservada.

Por que o impacto foi maior que o consumo de CPU:

Duas threads consumindo dois núcleos representam cerca de 4% de 46 CPUs. Isso sozinho não explica a degradação observada no job. O custo real foi indireto.

Contenção de locks. Para migrar páginas, o kcompactd segura o zone->lock e o lru_lock da zona. Todo processo Oracle que aloca memória — crescimento de PGA, sort, hash join, criação de processo — disputa exatamente esses mesmos locks. O tempo perdido aparece como latência de sessão, não como CPU.

Direct reclaim. Sem folga de memória livre, o reclaim acontece no contexto do processo que pediu a memória. O qc7tb2 varria cerca de 1.500 páginas por segundo continuamente durante todo o mês. Cada sessão que alocava PGA parava para fazer esse trabalho ela mesma.

TLB shootdown. Migrar página mapeada exige invalidar TLB em todas as CPUs via IPI. Com dezenas de núcleos e compactação ininterrupta, é tráfego constante de interrupções.

Infelizmente, não tivemos uma resposta conclusiva sobre alguns pontos importantes. Não ficou claro se toda a análise estava correta, se poderia existir algum problema no cálculo da compactação, considerando o valor total reservado para HugePages em vez da memória efetivamente utilizada, ou se existe alguma boa prática específica que deva ser seguida após a introdução desse mecanismo de compactação no kernel UEK7.

Durante a pesquisa, o único documento que encontrei diretamente relacionado ao problema foi o Oracle Linux: 100% CPU Utilization by kcompactd Process (KB181416). O documento orienta que, em situações de alto consumo de CPU pelo processo kcompactd, a compactação de memória seja desabilitada. No entanto, não encontrei uma documentação que explicasse de forma mais detalhada o funcionamento desse mecanismo, principalmente em ambientes Oracle Database com uma grande quantidade de HugePages estáticas reservadas.

Também enviei alguns e-mails para o time do Oracle Linux, mas, infelizmente, não obtive retorno sobre o problema apresentado.

Na minha opinião, esse é um ponto que poderia ser melhor documentado pela Oracle. Uma melhoria na própria implementação ou, pelo menos, uma nota no MOS explicando esse comportamento e indicando as melhores práticas para configuração de HugePages nesse cenário seria bastante útil.

Uma documentação mais clara ajudaria os times responsáveis pela administração dos ambientes Oracle e também toda a comunidade técnica de DBAs a entender melhor o funcionamento do kcompactd, principalmente como o processo de compactação considera as HugePages reservadas e quais cuidados devem ser tomados na configuração do nr_hugepages no UEK7.

Como recomendação, na minha opinião, a partir do UEK7, o ideal é configurar o nr_hugepages considerando apenas a quantidade de HugePages que será efetivamente utilizada pelos databases. Eu evitaria manter uma quantidade excessiva de HugePages reservadas sem utilização que antes era inofensiva até o UEK7, pois, conforme observado neste caso, essa memória permanece indisponível para outros usos do sistema e pode influenciar o comportamento do gerenciamento e da compactação de memória.

Dessa forma, a configuração deve buscar um equilíbrio entre atender à demanda real dos databases e evitar a reserva desnecessária de memória, principalmente em ambientes com grande quantidade de RAM e múltiplos databases.

Referências:

https://blogs.oracle.com/linux/reasons-to-install-uek7
https://blogs.oracle.com/linux/linux-memory-compaction-part-1
https://lwn.net/Articles/817905/
Oracle Linux: 100% CPU Utilization by kcompactd Process KB181416
search previous next tag category expand menu location phone mail time cart zoom edit close