如何有效地测试Pod记忆

2021-07-13 英豪王 社区

作者英豪王(混沌网格贡献者)

编辑:黄了汤姆,政府高级官员

如何有效地测试Kubernetes中的Pod内存

混乱的网是一个云原生的混沌工程平台,它在Kubernetes环境中协调混沌。在它的各种工具中,混沌网格提供StressChaos,它允许你将CPU和内存压力注入你的Pod。当您测试一个cpu敏感或内存敏感的程序,并想知道它在压力下的行为时,这个工具非常有用。

然而,当我们测试和使用stress schaos时,我们发现了可用性和性能方面的一些问题。例如,stress schaos使用的内存比我们配置的要少得多。

为了纠正这些问题,我们开发了一组新的测试。在本文中,我将描述如何对这些问题进行故障排除和修正。这些信息可能会帮助你最大限度地利用“压力混乱”。

向目标Pod注入压力

在你继续之前,你需要安装混乱网在您的集群。

首先,我将教你如何将stress schaos注入目标Pod。为了演示的目的,我将使用hello-kubernetes的演示应用程序执掌图表.第一步是克隆hello-kubernetes回购和修改图表,给它一个资源限制。

git克隆https://github.com/paulbouwer/hello-kubernetes.githttps://github.com/paulbouwer/hello-kubernetes.git代码部署/舵/ hello-kubernetes / values.yaml#或任何你喜欢的编辑器

找到资源配置,按如下方法修改:

资源请求内存“200米”限制内存“500米”

在我们注入stress schaos之前,让我们看看目标Pod当前消耗了多少内存。进入花苞,开始一个壳。输入以下命令与您的Pod的名称:

kubectl执行-- -n hello-kubernetes hello-kubernetes-hello-world-b55bfcf68-8mln6——/bin/sh

通过输入:显示内存使用的摘要:

/usr/src/app $ top . /usr/src/app

从下面的输出中可以看到,Pod消耗了4,269 MB内存:

/usr/src/app免费- m Mem使用:4269美元交换:0 /usr/src/app顶级Mem美元:12742432 k使用PID PPID用户统计VSZ % VSZ CPU % CPU命令1 0节点285年代2% 0 0% npm开始18 1节点284年代2% 3 0%节点server.js 29节点0年代/bin/sh 36 29节点R 1568 1636 0% 0% 0% 3 0%

免费的命令给出了类似的答案,但这些数字没有达到我们的预期。我们已经将Pod的内存使用量限制在500 mib,但现在它似乎使用了几gb。

为了找出原因,我们可以在Pod上做一个应激混乱实验,看看会发生什么。下面是我们使用的YAML文件:

apiVersion混乱-mesh.org/v1alpha1种类StressChaos元数据的名字mem-压力名称空间混乱-测试规范模式所有选择器名称空间-你好-kubernetes压力内存工人4大小50 mib选项""持续时间“1 h”

将上述文件保存到memory.yaml.运行混沌实验:

kubectl应用-f内存。yaml stresschaos.chaos-mesh.org/mem-stress创建

让我们再次检查内存使用情况:

used Mem: 4332 Swap: 0 Mem:12805568 k使用PID PPID用户统计VSZ % VSZ CPU % CPU命令54 50根R 53252 0% 24% {stress-ng-vm} stress-ng——vm 4——vm-keep vm-bytes 50000000 57 52根R 53252 0% 0 22% {stress-ng-vm} stress-ng——vm 4——vm-keep vm-bytes 50000000 55 53根R 53252 2 21% {stress-ng-vm} stress-ng——vm 4 0%——vm-keep vm-bytes 50000000 56 51根R 532520% 3 21% {stress-ng-vm} stress-ng——vm 4——vm-keep vm-bytes 50000000 18 1节点289年代2% 2节点server.js 1 0 0%节点285年代2% 0 0% npm开始51 49根41048年代0% 0 0% {stress-ng-vm} stress-ng——vm 4——vm-keep vm-bytes 41048 49根50年代50000000 2 0% {stress-ng-vm} stress-ng——vm 4 0%——vm-keep vm-bytes 50000000 52 49根41048年代0% 0 0%{stress-ng-vm} stress-ng——vm 4——vm-keep vm-bytes 50000000 53 49根41048 0% 0% {stress-ng-vm} stress-ng——vm 4——vm-keep vm-bytes 50000000 49根年代41044年0% 0 0% stress-ng——vm 4——vm-keep vm-bytes 50000000 29节点0年代/bin/sh 48 R 29节点1568 1636 0% 0% 0% 1 0%

大家可以看到stress-ng实例被注入到Pod中。Pod上升了60 MiB,这是我们没有预料到的。的stress-ng文档表示增量为200 MiB (4 * 50 MiB)。

让我们通过将内存压力从50 MiB改变为3000 MiB来增加压力。这会打破花苞的内存限制。我将删除混沌实验,修改内存大小,并重新应用它。

然后,轰!shell以代码137退出。过一会儿,我重新连接到容器,内存使用恢复正常。没有stress-ng实例被发现!发生了什么事?

为什么压力混乱会消失?

在上面的混沌实验中,我们看到了异常行为:内存使用量没有增加,Shell退出。在这一节中,我们将找出所有的原因。

Kubernetes通过cgroup机制。要查看Pod中的500mib限制,请进入容器并输入:

/usr/src/app美元/ sys / fs / cgroup /内存/ memory.limit_in_bytes524288000

输出以字节显示,并转换为5001024500 1024 (MiB)。

请求仅用于安排放置Pod的位置。Pod没有内存限制或请求,但可以将其视为其所有容器的总和。

所以,我们从一开始就在犯错。免费的不是“cgroup。”他们依靠/proc/meminfo(procfs)数据。不幸的是,/proc/meminfo都很老了,比c组还老。他们为你提供宿主内存信息而不是容器的内存信息。

记住这一点,让我们重新开始,看看这次得到的内存使用情况。

要获取“cgrouped”的内存使用情况,输入:

/usr/src/app美元/ sys / fs / cgroup /内存/ memory.usage_in_bytes39821312

应用50 MiB stress schaos,得到如下结果:

/usr/src/app美元/ sys / fs / cgroup /内存/ memory.usage_in_bytes93577216

这比没有压力混乱的情况下多了51个MiB。

下一个问题:为什么shell退出了?退出代码137表示“容器接收到SIGKILL时失败”。所以我们要去检查花苞。注意Pod的状态和事件:

~ kubectl描述豆荚-n你好kubernetes......最后状态:终止原因:错误退出代码:1......事件:原因年龄从消息类型  ---- ------ ---- ---- -------......警告不健康的10米x4超过16米kubelet准备就绪探测器失败:得到“http://10.244.1.19:8080”上下文期限超过客户端。超时了等待头正常死亡10米x2超过16米kubelet容器hello-kubernetes激活探测失败,将重新启动......

这些事件告诉我们炮弹坠毁的原因。hello-kubernetes有一个活性探针。当容器内存达到限制时,应用程序开始失败,Kubernetes决定终止并重新启动Pod。当Pod重启时,应激混乱就会停止。到目前为止,你可以说,stress schaos实验效果很好:它发现了Pod中的一个漏洞。你现在可以修复它,并重新应用混乱。

现在一切似乎都很完美,除了一件事。为什么4个50个MiB vm worker会产生51个MiB ?答案是不会自己显露的,除非我们进入stress-ng源代码

vm_bytes/ =arg游戏->num_instances

哦!所以文件是错误的。多个虚拟机工作人员占用指定的总大小,而不是mmap每个工人有那么多内存。终于,我们得到了所有问题的答案。在接下来的部分中,我们将讨论一些涉及记忆压力的其他情况。

如果没有活性探针呢?

为了弄清楚如果没有活性探针会发生什么,让我们删除探针并再次尝试。

找到下面的行部署/舵/ hello-kubernetes /模板/ deployment.yaml和删除它们。

livenessProbehttpGet路径/港口httpreadinessProbehttpGet路径/港口http

之后,升级部署。

有趣的是,在这种情况下,内存使用量持续上升,然后急剧下降;它来来回回。现在发生了什么?让我们检查内核日志。注意最后两行。

/usr/src/app $ dmesg…[189937.362908] [pid] uid tgid total_vm RSS nr_ptes swapents oom_score_adj name [189937.363092] [441060] 1000 441060 63955 3791 80 3030 988 node [189937.363145] [443265] 0 443265 193367 84215 197 9179 1000 stress-ng-vm…[189937.363148] Memory cgroup out of Memory: Kill process 443160 (stress-ng-vm) score 1272 or sacrifice child . [189937.363186] Kill process 443160 (stress-ng-vm), UID 0, total-vm:773468kB, anon-rss:152704kB, file-rss:164kB, shmems -rss:0kB .

从输出中可以清楚地看出stress-ng-vm由于内存不足(OOM)错误,进程正在被终止。

如果进程不能得到它们想要的内存,它们很可能会失败。与其等待进程崩溃,不如杀死其中一些进程以释放更多内存。OOM杀手按顺序停止进程,并试图在造成最少麻烦的同时恢复最多的内存。有关此过程的详细信息,请参见介绍伯父杀手。

看看上面的输出,你可以看到节点,我们的申请过程不应该终止,有一个oom_score_adj988股。这是相当危险的,因为这是最容易被杀死的过程。

要阻止OOM杀手杀死特定的进程,您可以尝试一个简单的技巧。创建Pod时,分配Pod服务质量(QoS)类.通常,如果使用精确指定的资源请求创建Pod,则将其分类为保证豆荚。如果有其他杀死选项,OOM杀手不会杀死保证Pod中的容器。这些选项包括non-保证豆荚和stress-ng工人。没有资源请求的Pod被标记为BestEffort他可能会首先被OOM杀手杀死。

参观到此结束。当你将stress schaos注入你的pod时,我们有两个建议:

  • 不要使用免费的评估容器中的记忆。
  • 在为Pod分配资源限制时要小心,并选择正确的QoS。

将来,我们将创建一个更详细的stress schaos文档。

深入了解Kubernetes的内存管理

Kubernetes试图驱逐使用过多内存的pod(但内存不能超过其限制)。Kubernetes获取Pod内存使用情况/ sys / fs / cgroup /内存/ memory.usage_in_bytes然后减去total_inactive_filememory.stat

记住,Kubernetes支持交换。即使您有一个启用了交换的节点,Kubernetes也会用swappiness = 0,这意味着swap实际上是禁用的。这主要是出于性能考虑。

memory.usage_in_bytes=驻留集+缓存,total_inactive_file是内存中缓存当内存耗尽时,操作系统可以检索。memory.usage_in_bytes-total_inactive_file被称为working_set.你可以得到这个working_set价值Kubectl top pod <你的pod>——容器.Kubernetes使用这个值来决定是否驱逐你的豆荚。

Kubernetes定期检查内存使用情况。如果容器的内存使用量增长过快,或者无法收回容器,则调用OOM杀手。Kubernetes有自己的方法来保护自己的进程,所以OOM杀手总是选择容器。当容器终止时,它可能重新启动,也可能不重新启动,这取决于您的重新启动策略。如果它被杀死了,在你执行的时候Kubectl描述豆荚<你的豆荚>,您将看到它重新启动,原因是OOMKilled

另一件值得一提的事情是内核内存。从1.9版开始,Kubernetes默认启用内核内存支持。这也是cgroup内存子系统的一个特性。您可以限制容器内核内存的使用。不幸的是,这将导致内核版本4.2之前的cgroup泄漏。您可以将内核升级到v4.3,也可以禁用该特性。

我们如何实现压力混乱

stress schaos是在内存不足时测试容器行为的一种简单方法。stress schaos使用了一个强大的工具stress-ng分配内存并继续写入已分配的内存。因为容器有内存限制,而且容器限制绑定到cgroup,所以我们必须找到一种运行的方法stress-ng在一个特定的c组中。幸运的是,这部分很简单。只要有足够的权限,我们就可以通过写入文件的方式将任意进程分配给任意cgroup/ sys / fs / cgroup /

如果你对混沌网格感兴趣,并想帮助我们改进它,欢迎你的加入我们的松弛通道(# project-chaos-mesh) !或者把你的请求或问题提交给我们GitHub库

混乱的工程

准备好开始使用TiDB了吗?