如何在不重启节点的前提下释放Windows AKS节点的内核内存

如何在不重启节点的前提下释放Windows AKS节点的内核内存

在过去几周,我在 Azure Kubernetes Service (AKS) 上运行了一组 RAM 密集型的容器工作负载,使用的是 Windows Server 节点池。虽然工作负载本身运行得很稳定,但在任务完成后我注意到节点内存长期处于异常状态,尤其是“Nonpaged Pool”和“Paged Pool”占用持续高居不下。唯一有效的手段似乎只有重启节点,但在生产环境中,这并不是一个理想的选择。因此,我开始研究是否可以“让节点恢复理智”,即在不重启节点的前提下恢复其内存状态。

一、在开始之前,我运行以下 PowerShell 命令来获取节点内存的详细分布:

Get-Counter "\Memory\Pool Nonpaged Bytes", "\Memory\Pool Paged Bytes", `
            "\Memory\System Cache Resident Bytes", "\Memory\Modified Page List Bytes", `
            "\Process(_Total)\Working Set" |
Select-Object -ExpandProperty CounterSamples |
Select-Object Path, @{Name = 'SizeGB'; Expression = { '{0:N2} GB' -f ($_.CookedValue / 1GB) } }

在运行工作负载前后,系统状态如下:

任务前(空闲状态):

  • Nonpaged Pool: 0.56 GB
  • Paged Pool: 0.85 GB
  • Cache Resident: 0.38 GB
  • Working Set Total: 4.35 GB

任务结束 25 小时后:

  • Nonpaged Pool: 5.80 GB
  • Paged Pool: 11.38 GB
  • Cache Resident: 2.84 GB
  • Working Set Total: 6.01 GB

可以看出,“Paged”和“Nonpaged Pool”分别暴涨了超过 10 GB,却没有在任务结束后释放。

二、排查与理解:为何内核池内存无法释放?

Windows 的 Nonpaged Pool 和 Paged Pool 属于内核内存,它们不会像用户态进程那样自动释放,尤其是由驱动程序、内核模式 API 或网络堆栈分配的资源。一旦分配,这些内存通常只有在明确的回收逻辑执行后才会释放,某些情况下甚至需要驱动卸载或系统重启。

在 AKS 的 Windows 节点中,以下几个组件可能是“内存泄露”来源:

  • Host Networking Service (HNS) 与其相关的容器网络驱动
  • Kubelet for Windows(管理 Windows 容器生命周期)
  • 大型容器应用程序未正确释放句柄
  • Hyper-V 虚拟交换机残留

三、可行的缓解方案(无需重启)

以下是我验证可行的几种方案,部分适用于生产环境下临时缓解:

1. 清理 HNS 网络残留

容器停止后,其网络接口信息有时不会及时清除,HNS 的资源分配会持续占用内核内存。

Get-HnsNetwork

查找所有非活跃的 HNS 网络,如果发现存在孤立网络,可以执行:

Get-HnsNetwork | Where-Object { $_.Name -like "nat" -or $_.Name -like "cbr*" } | Remove-HnsNetwork

⚠️ 注意:此操作可能会断开所有容器网络,建议配合 node cordon 和 drain 操作使用。

2. 重启 Kubelet 与容器运行时服务

Restart-Service kubelet
Restart-Service docker

这将清理 Kubelet 所维护的容器状态缓存,可能间接触发内核释放部分句柄资源。需注意:某些容器会被自动重建。

3. 定期强制回收内存缓存(Memory Compression 机制)

Windows 支持通过设置工作集限制来触发回收:

Get-Process | ForEach-Object {
    Try {
        $_.MinWorkingSet = 1MB
        $_.MaxWorkingSet = 1MB
    } Catch {}
}

这会将大多数进程的工作集压缩进 Standby List,有助于清空部分页池内容。

4. 使用 RAMMap 手动释放 Standby List(需远程桌面)

微软官方工具 RAMMap 可以用来手动清除 Standby Cache,对 system cache 类资源释放有奇效。

打开 RAMMap → “Empty” 菜单 → 选择 “Empty Standby List”。

5. 启用 System Managed Cache Trimming 策略

在某些版本的 Windows Server 中,可以通过注册表或组策略强制启用 aggressive trimming:

Set-ItemProperty -Path "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" `
                 -Name "LargeSystemCache" -Value 0

重启相关服务后生效(非系统重启)。

四、最佳实践建议

为了防止类似问题再次出现,我也采取了以下预防策略:

  • 为 Windows 节点池设定定期维护窗口(例如每月一次的节点滚动更新)
  • 避免长时间运行的单体大型容器,尽量将 RAM 使用峰值限制在物理内存的 60% 以下
  • 使用 DaemonSet 监控 Nonpaged/Paged Pool 占用并告警

虽然 Windows 节点不像 Linux 那样有完善的 memory cgroup 控制和自动清理机制,但通过 HNS 网络清理、服务重启和进程压缩机制,我们可以在不重启节点的情况下有效释放部分内核内存资源。这一流程在我的 AKS 环境中显著降低了 Nonpaged Pool 占用,并避免了对服务的中断。

当然,在无法控制的情况下,节点重启仍是最彻底的手段。但希望本文能为同样面临问题的运维人员提供一条可选的“温和路线”。

未经允许不得转载:A5数据 » 如何在不重启节点的前提下释放Windows AKS节点的内核内存

相关文章

contact