为了使Kubernetes(K8s)能够可靠地为您的应用程序分配运行时所需的资源,并充分利用计算机资源,您应该明确指定容器运行所需要的资源要求。当前,您可以为两种类型的容器资源(内存和CPU)设置两种限制,即requests和limits。我们会在后面详细说明这两种限制需求的含义以及Docker容器运行时内存的含义。
Requests vs Limits
定义Pod时,可以为内存和CPU指定两类资源限制要求:requests和limits:
resources:
requests:
memory: "8Gi"
cpu: "4"
limits:
memory: "8Gi"
cpu: "4"
Requests是K8s的概念,主要会影响K8s中容器的调度:会根据Requests的值决定将Pod放置在那个node上,因此会影响容器的调度。Limits表示容器可用的资源的上限,因此会影响容器的实际运行。若容器的资源使用超出了limits的限制会导致节流,或者在最坏的情况下会导致容器被终止。
您可能会问为什么要将limits的值设置的高于requests。如果您的应用程序的内存占用空间非常固定,则没有必要这样做,而且一般情况下也不建议将内存的limits值设置的比requests的值大。如果使用CPU,则有可能在其他容器的CPU不繁忙的情况下,使用limits和requests之间的资源部分,从而可以更加有效的利用CPU资源。 Burstable QoS类(下面会详细说明)允许潜在地更有效地利用计算机资源,但具有更大的不可预测性-例如,与CPU绑定的应用程序的响应延迟可能会受到位于同一个node上的其他容器的影响。如果您还不熟悉K8s,一开始最好通过将requests和limits的值设置为相同从而使用Guaranteed QoS类开始,关于Qos的分类,参考这里。
内存的含义
内存在这里到底意味着什么?简而言之,它代表了容器的总驻留集大小(RSS)和page cache。在纯Docker中,此数字通常还包含了swap,但是在K8s中,我们会禁用swap。
RSS是进程使用的RAM数量。对于Java进程,这可以包括多个区域,包括native heap/非heap区域,线程stack和native的内存分配。 RSS受JVM线程配置、线程数和应用程序的影响。
page cache是用于缓存磁盘中的数据块的RAM区域。出于性能原因,所有I / O通常都通过此cache执行。每当您的程序从文件中读取或写入文件时,都可以期望将相关的数据块缓存在此处。您读取或写入的文件越多,要求就越高。请注意,内核会将可用的备用内存用于page cache,但是如果其他地方需要,它将回收page cache-这意味着如果没有足够的内存,程序的性能可能会受到影响(取决于其对page cache的性能依赖)。这里有一个潜在的问题-Docker的overlayfs存储驱动启用了page cache共享,这意味着在同一个node上的多个containers访问同一文件时,会共享该文件对应的page cache(考虑使用index或其他共享的内容)。 Docker 文档指出:
计算page cache所占据的内存大小非常复杂。如果不同control groups中的两个进程都读取同一文件(最终依赖于磁盘上的相同块),则会将内存开销在多个control groups之间进行分配。但这也意味着当一个cgroup终止时,它可能会增加另一个cgroup的内存使用量,因为它们不再为这些内存中的pages而分配内存。
…因此请注意,每个容器的page cache使用情况可能会有所不同,具体取决于与同一节点上运行的其他容器共享哪些文件。
内存限流?
内存的limits值在K8s中被认为是不可压缩的,这意味着它不能被限流。如果您的容器存在内存压力,内核将积极删除page cache条目以满足需求,并且最终可能会因为Linux内存不足(OOM)而被杀死。由于K8s禁用了swap(通过将memory-swappiness = 0传递给Docker),因此一旦内存错误配置,容器将会无法启动。