作者:韩柔刚(申信)

背景

云原生场景中,运用程序通常以容器的形式布置和分配物理资源。以 Kubernetes 集群为例,运用工作负载以 Pod 声明晰资源的 Request/Limit,Kubernetes 则根据声明进行运用的资源调度和服务质量确保。

当容器或宿主机的内存资源严重时,运用功用会受到影响,比方出现服务延时过高或者 OOM 现象。一般而言,容器内运用的内存功用受两方面的影响:

  1. 本身内存束缚:当容器本身的内存(含 page cache)挨近容器上限时,会触发内核的内存子体系运转,此刻容器内运用的内存恳求和开释的功用受到影响。
  2. 宿主机内存束缚:当容器内存超卖(Memory Limit > Request)导致整机内存出现严重时,会触发内核的大局内存收回,这个进程的功用影响更甚,极点状况能导致整机夯死。

前文《阿里云容器服务差异化 SLO 混部技能实践》和《怎么合理运用 CPU 管理战略,进步容器功用》分别论述了阿里云在云原生混部、容器 CPU 资源管理方面的实践经验和优化方法,本文同大家讨论容器运用内存资源时的困扰问题和确保战略。

容器内存资源的困扰

Kubernetes 的内存资源管理

布置在 Kubernetes 集群中的运用,在资源运用层面遵循规范的 Kubernetes Request/Limit 模型。在内存维度,调度器参考 Pod 声明的 Memory Request 进行决议计划,节点侧由 Kubelet 和容器运转时将声明的 Memory Limit 设置到 Linux 内核的 cgroups 接口,如下图所示:

如何使用阿里云容器服务保障容器的内存资源质量

CGroups(Control Groups,简称 cgroups)是 Linux 上管理容器资源运用的机制,体系可以经过 cgroups 对容器内进程的 CPU 和内存资源用量作出精细化束缚。而 Kubelet 正是经过将容器的 Request/Limit 设置到 cgroup 接口,完结对 Pod 和 Container 在节点侧的可用资源束缚,大致如下:

如何使用阿里云容器服务保障容器的内存资源质量

Kubelet 根据 Pod/Container 的 Memory Limit 设置 cgroups 接口 memory.limit_in_bytes,束缚了容器的内存用量上限,CPU 资源维度也有类似束缚,比方 CPU 时刻片或绑定核数的束缚。关于 Request 层面,Kubelet 根据 CPU Request 设置 cgroups 接口 cpu.shares,作为容器间竞赛 CPU 资源的相对权重,当节点的 CPU 资源严重时,容器间同享 CPU 时刻的份额将参考 Request 比值进行划分,满意公正性;而 Memory Request 则默认未设置 cgroups 接口,首要用于调度和驱赶参考。

Kubernetes 1.22 以上版别根据 cgroups v2 支撑了 Memory Request 的资源映射(内核版别不低于 4.15,不兼容cgroups v1,且敞开会影响到节点上一切容器)。

例如,节点上 Pod A 的 CPU Request 是 2 核,Pod B 的 CPU Request 是 4 核,那么当节点的 CPU 资源严重时,Pod A 和 Pod B 运用 CPU 资源的相对份额是 1:2。而在节点的内存资源严重时,因为 Memory Request 未映射到 cgroups 接口,容器间的可用内存并不会像 CPU 一样按 Request 份额划分,因而短少资源的公正性确保。

云原生场景的内存资源运用

在云原生场景中,容器的内存 Limit 设置影响着容器本身和整个宿主机的内存资源质量。 因为 Linux 内核的原则是尽或许运用内存而非不间断收回,因而当容器内进程恳求内存时,内存用量往往会持续上升。当容器的内存用量挨近 Limit 时,将触发容器等级的同步内存收回,产生额定延时;假如内存的恳求速率较高,还或许导致容器 OOM (Out of Memory) Killed,引发容器内运用的运转中断和重启。

容器间的内存运用一起也受宿主机内存 Limit 的影响,假如整机的内存用量较高,将触发大局的内存收回,严重时会拖慢一切容器的内存分配,形成整个节点的内存资源质量下降。

在 Kubernetes 集群中,Pod 之间或许有确保优先级的需求。比方高优先级的 Pod 需求更好的资源稳定性,当整机资源严重时,需求尽或许地防止对高优先级 Pod 的影响。然而在一些真实场景中,低优先级的 Pod 往往运转着资源耗费型使命,意味着它们更简单导致大规模的内存资源严重,搅扰到高优先级 Pod 的资源质量,是真实的“费事制造者”。对此 Kubernetes 现在首要经过 Kubelet 驱赶运用低优先级的 Pod,但呼应时机或许产生在大局内存收回之后。

运用容器内存服务质量确保容器内存资源

容器内存服务质量

Kubelet 在 Kubernetes 1.22 以上版别供给了 MemoryQoS 特性,经过 Linux cgroups v2 供给的 memcg QoS 才能来进一步确保容器的内存资源质量,其间包含:

• 将容器的 Memory Request 设置到 cgroups v2 接口 memory.min,确定恳求的内存不被大局内存收回。 • 根据容器的 Memory Limit 设置 cgroups v2 接口 memory.high,当 Pod 产生内存超用时(Memory Usage > Request)优先触发限流,防止无束缚超用内存导致的 OOM。

上游方案可以有用处理 Pod 间内存资源的公正性问题,但从用户运用资源的视角来看,仍然存在一些不足:

• 当 Pod 的内存声明 Request = Limit 时,容器内仍然或许出现资源严重,触发的 memcg 等级的直接内存收回或许影响到运用服务的 RT(呼应时刻)。 • 方案现在未考虑对 cgroups v1 的兼容,在 cgroups v1 上的内存资源公正性问题仍未得到处理。

阿里云容器服务 ACK 根据 Alibaba Cloud Linux 2 的内存子体系增强,用户可以在 cgroups v1 上提早运用到更完整的容器 Memory QoS 功用,如下所示:

  1. 确保 Pod 间内存收回的公正性,当整机内存资源严重时,优先从内存超用(Usage > Request)的 Pod 中收回内存,束缚损坏者以防止整机资源质量的下降。
  2. 当 Pod 的内存用量挨近 Limit 时,优先在后台异步收回一部分内存,缓解直接内存收回带来的功用影响。
  3. 节点内存资源严重时,优先确保 Guaranteed/Burstable Pod 的内存运转质量。
    如何使用阿里云容器服务保障容器的内存资源质量

典型场景

内存超卖

在云原生场景下,运用管理员或许会为容器设置一个大于 Request 的 Memory Limit,以增加调度灵活性,下降 OOM 危险,优化内存资源的可用性;关于内存利用率较低的集群,资源管理员也或许运用这种方法来进步利用率,作为降本增效的手段。但是,这种方法或许形成节点上一切容器的 Memory Limit 之和超出物理容量,使整机处于内存超卖(memory overcommit)状态。当节点产生内存超卖时,即便一切容器的内存用量明显低于 Limit 值,整机内存也或许触及大局内存收回水位线。因而,比较未超卖状态,内存超卖时更简单出现资源严重现象,一旦某个容器许多恳求内存,或许引发节点上其他容器进入直接内存收回的慢速路径,乃至触发整机 OOM,大规模影响运用服务质量。

Memory QoS 功用经过启用容器等级的内存后台异步收回,在产生直接收回前先异步收回一部分内存,能改进触发直接收回带来的延时影响;关于声明 Memory Request < Limit 的 Pod,Memory QoS 支撑为其设置主动内存收回的水位线,将内存运用束缚在水位线附近,防止严重搅扰到节点上其他 Pod。

混合布置

Kubernetes 集群或许在同一节点布置了有着不同资源运用特征的 Pods。比方,Pod A 运转着在线服务的工作负载,内存利用率相对稳定,属于延时敏感型事务(Latency Sensitive,简称 LS);Pod B 运转着大数据运用的批处理作业,发动后往往瞬间恳求许多内存,属于资源耗费型事务(Best Effort,简称 BE)。当整机内存资源严重时,Pod A 和 Pod B 都会受到大局内存收回机制的搅扰。实际上,即便当时 Pod A 的内存运用量并未超出其 Request 值,其服务质量也会受到较大影响;而 Pod B 或许本身设置了较大的 Limit,乃至是未配置 Limit 值,运用了远超出 Request 的内存资源,是真实的“费事制造者”,但未受到完整的束缚,然后损坏了整机的内存资源质量。

Memory QoS 功用经过启用大局最低水位线分级和内核 memcg QoS,当整机内存资源严重时,优先从 BE 容器中收回内存,下降大局内存收回对 LS 容器的影响;也支撑优先收回超用的的内存资源,确保内存资源的公正性。

技能内情

Linux 的内存收回机制

假如容器声明的内存 Limit 偏低,容器内进程恳求内存较多时,或许产生额定延时乃至 OOM;假如容器的内存 Limit 设置得过大,导致进程许多耗费整机内存资源,搅扰到节点上其他运用,引起大规模的事务时延颤动。这些由内存恳求行为触发的延时和 OOM 都跟 Linux 内核的内存收回机制密切相关。

容器内进程运用的内存页面(page)首要包含: • 匿名页:来自堆、栈、数据段,需求经过换出到交流区(swap-out)来收回(reclaim)。 • 文件页:来自代码段、文件映射,需求经过页面换出(page-out)来收回,其间脏页要先写回磁盘。 • 同享内存:来自匿名 mmap 映射、shmem 同享内存,需求经过交流区来收回。

Kubernetes 默认不支撑 swapping,因而容器中可直接收回的页面首要来自文件页,这部分也被称为 page cache(对应内核接口计算的 Cached 部分,该部分还会包含少数同享内存)。因为拜访内存的速度要比拜访磁盘快许多,Linux 内核的原则是尽或许运用内存,内存收回(如 page cache)首要在内存水位比较高时才触发。

具体而言,当容器本身的内存用量(包含 page cache)挨近 Limit 时,会触发 cgroup(此处指 memory cgroup,简称 memcg)等级的直接内存收回(direct reclaim),收回洁净的文件页,这个进程产生在进程恳求内存的上下文,因而会形成容器内运用的卡顿。假如此刻的内存恳求速率超出收回速率,内核的 OOM Killer 将结合容器内进程运转和运用内存的状况,终止一些进程以进一步开释内存。

当整机内存资源严重时,内核将根据闲暇内存(内核接口计算的 Free 部分)的水位触发收回:当水位到达 Low 水位线时,触发后台内存收回,收回进程由内核线程 kswapd 完结,不会堵塞运用进程运转,且支撑对脏页的收回;而当闲暇水位到达 Min 水位线时(Min < Low),会触发大局的直接内存收回,该进程产生在进程分配内存的上下文,且期间需求扫描更多页面,因而十分影响功用,节点上一切容器都或许被搅扰。当整机的内存分配速率超出且收回速率时,则会触发更大规模的 OOM,导致资源可用性下降。

Cgroups-v1 Memcg QoS

Kubernetes 集群中 Pod Memory Request 部分未得到充沛确保,因而当节点内存资源严重时,触发的大局内存收回能损坏 Pod 间内存资源的公正性,资源超用(Usage > Request)的容器或许和未超用的容器竞赛内存资源。

关于容器内存子体系的服务质量(memcg QoS),Linux 社区在 cgroups v1 上供给了束缚内存运用上限的才能,其也被 Kubelet 设置为容器的 Limit 值,但短少对内存收回时的内存运用量的确保(确定)才能,仅在cgroups v2 接口上支撑该功用。

Alibaba Cloud Linux 2 内核在 cgroups v1 接口中默认敞开 memcg QoS 功用,阿里云容器服务 ACK 经过Memory QoS 功用为 Pod 主动设置适宜的 memcg QoS 配置,节点无需晋级 cgroups v2 即可支撑容器 Memory Request 的资源确定和 Limit 限流才能,如上图所示:

• memory.min:设置为容器的 Memory Request。根据该接口的内存确定的才能,Pod 可以确定 Request 部分的内存不被大局收回,当节点内存资源严重时,仅从产生内存超用的容器中收回内存。 • memory.high:当容器 Memory Request < Limit 或未设置 Limit 时,设置为 Limit 的一个份额。根据该接口的内存限流才能,Pod 超用内存资源后将进入限流进程,BestEffort Pod 不能严重超用整机内存资源,然后下降了内存超卖时触发大局内存收回或整机 OOM 的危险。

更多关于 Alibaba Cloud Linux 2 memcg QoS 才能的描绘,可拜见官网文档: help.aliyun.com/document_de…

内存后台异步收回

前面说到,体系的内存收回进程除了产生在整机维度,也会在容器内部(即 memcg 等级)触发。当容器内的内存运用挨近 Limit 时,将在进程上下文触发直接内存收回逻辑,然后堵塞容器内运用的功用。

针对该问题,Alibaba Cloud Linux 2 增加了容器的后台异步收回功用。不同于大局内存收回中 kswapd 内核线程的异步收回,本功用没有创立 memcg 粒度的 kswapd 线程,而是采用了 workqueue 机制来完结,一起支撑 cgroups v1 和 cgroups v2 接口。

如上图所示,阿里云容器服务 ACK 经过 Memory QoS 功用为 Pod 主动设置适宜的后台收回水位线 memory.wmark_high。当容器的内存水位到达该阈值时,内核将主动启用后台收回机制,提早于直接内存收回,规避直接内存收回带来的时延影响,改进容器内运用的运转质量。

更多关于 Alibaba Cloud Linux 2 内存后台异步收回才能的描绘,可拜见官网文档: help.aliyun.com/document_de…

大局最低水位线分级

大局的直接内存收回对体系功用有很大影响,特别是混合布置了时延敏感型事务(LS)和资源耗费型使命(BE)的内存超卖场景中,资源耗费型使命会时常瞬间恳求许多的内存,使得体系的闲暇内存触及大局最低水位线(global wmark_min),引发体系一切使命进入直接内存收回的慢速路径,从而导致延敏感型事务的功用颤动。在此场景下,无论是大局 kswapd 后台收回还是 memcg 后台收回,都将无法有用防止该问题。

针对上述场景,Alibaba Cloud Linux 2 增加了 memcg 大局最低水位线分级功用,答应在大局最低水位线(global wmark_min)的基础上,经过 memory.wmark_min_adj 调整 memcg 等级收效的水位线。阿里云容器服务 ACK 经过 Memory QoS 功用为容器设置分级水位线,在整机 global wmark_min 的基础上,上移 BE 容器的 global wmark_min,使其提早进入直接内存收回;下移 LS 容器的 global wmark_min,使其尽量防止直接内存收回,如下图所示:

如何使用阿里云容器服务保障容器的内存资源质量

这样,当 BE 使命瞬间许多恳求内存的时候,体系能经过上移的 global wmark_min 将其短时刻按捺,防止促进 LS 产生直接内存收回。等候大局 kswapd 收回必定量的内存后,再处理对 BE 使命的短时刻按捺。

更多关于 Alibaba Cloud Linux 2 memcg 大局最低水位线分级才能的描绘,可拜见官网文档: help.aliyun.com/document_de…

小结

综上,容器内存服务质量(Memory QoS)根据 Alibaba Cloud Linux 2 内核确保容器的内存资源质量,各才能的引荐运用场景如下:

如何使用阿里云容器服务保障容器的内存资源质量

咱们运用 Redis Server 作为时延敏感型在线运用,经过模仿内存超卖和压测恳求,验证敞开 Memory QoS 对运用延时和吞吐的改进效果:

如何使用阿里云容器服务保障容器的内存资源质量

对比以上数据可得知,敞开容器内存服务质量后,Redis 运用的均匀时延和均匀吞吐都得到了必定改进。

总结

针对云原生场景下容器运用内存的困扰,阿里云容器服务 ACK 根据 Alibaba Cloud Linux 2 内核供给了容器内存服务质量(Memory QoS)功用,经过分配容器的内存收回和限流机制,确保内存资源公正性,改进运用的运转时内存功用。Memory QoS 属于相对静态的资源质量方案,合适作为确保 Kubernetes 集群内存运用的兜底机制,而关于复杂的资源超卖和混合布置场景,更加动态和精细化的内存确保战略显得不可或缺。例如,关于内存水位的频频波动,根据实时资源压力目标的驱赶战略,可以敏捷地在用户态进行减载(load schedding);另一方面,可以经过更细粒度地开掘内存资源,比方根据冷热页面标记的内存收回,或 Runtime (e.g. JVM) GC,来到达高效的内存超卖。敬请期待阿里云容器服务 ACK 支撑差异化 SLO 功用的后续发布。

发布云原生技能最新资讯、汇集云原生技能最全内容,定时举行云原生活动、直播,阿里产品及用户最佳实践发布。与你并肩探索云原生技能点滴,共享你需求的云原生内容。

重视【阿里巴巴云原生】公众号,获取更多云原生实时资讯!