打个比方:对于 A 应用的重要时刻,对于 B 应用可能不那么重要,适当打压 B 应用,腾挪出资源给 A 应用,这是个不错的选择。这听起来有点像是分时复用的感觉。但是如果我们按照流量峰值时的需求配置资源就会产生大量的浪费。
除了对于实时性要求很高的在线应用外,我们还有离线应用和实时计算应用等:离线计算对于 CPU 、Memory 或网络资源的使用以及时间不那么敏感,所以在任何时间段它都可以运行;实时计算,可能对于时间敏感性就会很高。
下面我们具体讨论一下 Policy engine 的设计。Policy engine 是单机节点上进行智能调度并执行 Pod 资源调整的核心组件。它主要包括 api server,指挥中心 command center 和执行层 executor。
其中 api server 用于服务外界对于 policy engine 运行状态的查询和设置的请求;
command center 根据实时的容器画像和物理机本身的负载以及资源使用情况,作出 Pod 资源调整的决策;
Executor 再根据 command center 的决策,对容器的资源限制进行调整。同时,executor 也把每次调整的 revision info 持久化,以便发生故障时可以回滚。
指挥中心定期从 data aggregator 获取容器的实时画像,包括聚合的统计数据和预测数据,首先判断节点状态,例如节点磁盘异常,或者网络不通,表示该节点已经发生异常,需要保护现场,不再对Pod进行资源调整,以免造成系统震荡,影响运维和调试。如果节点状态正常,指挥中心会策略规则,对容器数据进行再次过滤。比如容器 CPU 率飙高,或者容器的响应时间超过安全阈值。如果条件满足,则对满足条件的容器集合给出资源调整建议,传递给executor。
在架构设计上,我们遵循了以下原则:
插件化:所有的规则和策略被设计为可以通过配置文件来修改,尽量与核心控制流程的代码解耦,与 data collector 和 data aggregator 等其他组件的更新和发布解耦,提升可扩展性;
稳定,这包括以下几个方面:
a. 控制器稳定性。指挥中心的决策以不影响单机乃至全局稳定性为前提,包括容器的性能稳定和资源分配稳定。例如,目前每个控制器仅负责一种 cgroup 资源的控制,即在同一时间窗口内,Policy engine 不同时调整多种资源,以免造成资源分配震荡,干扰调整效果;
b. 触发规则稳定性。例如,某一条规则的原始触发条件为容器的性能指标超出安全阈值,但是为避免控制动作被某一突发峰值触发而导致震荡,我们把触发规则定制为:过去一段时间窗口内性能指标的低百分位超出安全阈值;如果规则满足,说明这段时间内绝大部分的性能指标值都已经超出了安全阈值,就需要触发控制动作了;
c. 另外,与社区版 Vertical-Pod-Autoscaler 不同,Policy engine 不主动驱逐腾挪容器,而是直接修改容器的 cgroup 文件;
基于 QoS 的资源动态调整方面:如我们之前所讲,阿里集团内部有上万个应用,应用之间的调用链相当复杂。应用 A 的容器性能发生异常,不一定都是在单机节点上的资源不足或者资源竞争导致,而很有可能是它下游的应用 B、应用 C,或者数据库、cache 的访问延迟导致的。
由于单机节点上这种信息的局限性,基于单机节点信息的资源调整,只能采用“尽力而为”,也就是 best effort 的策略了。在未来,我们计划打通单机节点和中心端的资源调控链路,由中心端综合单机节点上报的性能信息和资源调整请求,统一进行资源的重新分配,或者容器的重新编排,或者触发 HPA,从而形成一个集群级别的闭环的智能资源调控链路,这将会大大提高整个集群维度的稳定性和综合资源利用率。
Q1:请问heapster中采集到的MetricMemoryWorkingSet指标与ps命令获取到的RSS有何区别?heapster的源码中对该指标的描述是“Total working set usage. Working set is the memory being used and not easily dropped by the kernel”,同时heapster也采集了MetricMemoryRSS,kubectl top为何采用MetricMemoryWorkingSet而不采用MetricMemoryRSS?在Kubernets 1.10版本下,部分运行Java应用的pod出现kubectl top值超过ps RSS值的情况。