应用未迁,资源先行

引子

在企业服务和云原生的夹缝里厮混了这些年,见到了很多成功或不成功的 K8s 迁移案例。企业在向 Kubernetes 靠拢的过程中,一直有几个跟资源相关的尴尬问题:

  • 单个大集群,还是多个小集群?
  • 少量大节点,还是大量小节点?
  • 应用的资源如何配合 K8s 的策略进行分配?

这些问题有很多模棱两可的相关素材,在任何一个迁移过程中提起这些问题,都能引发大规模的磨洋工事件。然而对于我一直关注的“XX 管理系统”之类的应用来说,这就不是一个大问题了——随大流的应用,选择一个随大流的方向,大概是比较合适的,而 CNCF 红红火火恍恍惚惚,自然不会缺乏数据了。本着这个思路,就诞生了这一篇没什么技术含量的文章。

集群规模

早在 Kubernetes 1.2 时候,就已经宣布达到 1000 节点的规模了,在 1.6 版本更达到了 5000 节点的规模。各大厂也都有了各自的超大规模单一集群。然而普罗大众的情况是如何呢? 在 Sysdig 2019 年度容器应用报告中得到的结果是,大于 50 节点规模的集群不足 10%,另外一个佐证是 Mohamed Ahmed 的一篇调查报告中也提供了类似的数据。这种情况的一种解释是,目前的应用阶段还比较早期,处于试探期间;然而从一个侧面来说,Sysdig 的调研对象针对的是生产应用,也就是说处于生产应用状态下的集群,绝大多数都是这种小规模集群。根据对 CNCF Landscape 中 Distribution 分类的产品的抽查,也可以看到随处可见的 Kubernetes As Service 类似功能的实现,这也证实了小集群协作方案的落地趋势。相对于少量大集群,多个小集群的差异在于:

隔离程度高

虽然现在存在不少沙箱容器实现,然而最易用的、生态最为成熟的方案还是 Docker 为代表的传统容器方案,传统容器方案所缺失的隔离能力,通过多租户多集群方式是一个非常自然的思路。

实现难度低

国内几个大厂都有自己的大规模 Kubernetes 集群实现方式,然而通常需要对基础组件大动干戈,甚至不惜使用无法回流社区的孤岛版本,虽然部分大企业的研究院等相关部门已经具备了非常强的研发实力,然而对于通常的 To B 场景来说,这并不是一个合适的选择。

运管成本高

多个集群很明显会需要更多的运维和管理人力的投入。

资源利用率低

多个集群都会有自己的 Master 组件、ETCD 集群、网络组件等,这些都会抢占更多原本属于工作负载的系统资源,客观上降低了资源的总体利用率。

节点

目前很多 Kubernetes 系统都会使用虚拟机来做为节点。那么虚拟机的资源是多分还是少分呢?下表是一个简单的对比:

大节点 小节点 备注
节点数量 同样的资源总量情况下,相对来说小资源节点会得到更多的数量。
运维成本 通常情况下,节点的运维成本是和节点数量正相关的。
容错能力 较大的节点上通常会集中较多的应用,因此在节点出现故障时,可能会带来更大的损失。
资源粒度 单节点资源较大,因此其资源粒度也较大。
应用副本数 同一应用的多个副本,如果调度到同一个节点上的话,对于提高其负载能力和健壮性来说并无裨益。
副本规模 毫无疑问,具备更多资源的大节点,能够运行更大资源需求范围的容器应用。
系统开销 每个虚拟机都会有自己的操作系统、网络等基础开销,因此相对于少量大节点来说,大量的小节点会消耗更多的资源。

除了这些原则性的条目之外,更重要的决策依据就是运行在集群上的应用需求。例如某租户的集群需要支撑 20 个应用,共300 个 Pod,按照常见的每节点 30-50 Pod 的分布,就需要 6-10 个运算节点(Node)。以 10 节点算,加入系统保留、冗余等计算,可能需要 10 * 120G 的虚拟机实例;然而考虑到故障情况——一个节点的故障,最好的结果也是短期内降低 10% 的算力。如果扩张到 40 个 32G 的虚拟机节点,会大幅降低单节点故障的影响——当然也会提高网络的复杂性和效率要求。

应用资源

Java 应用是特别常见的迁移案例,除掉微服务化、网格、分布式等改造要求之外,资源的申请和限制是一个必须要面对的门槛。requests 是个用于调度的定义,Kubernetes 根据这个要求来选择能够满足要求的节点来分配应用。而 limits 则会用于触发 OOM。

众所周知的是,Java 的早期版本是无法识别容器内的内存限制的,因此如果没有限制堆内存上限,又开启了 limits,就会被 Kubernetes 杀掉。因此针对容器中运行的情况,需要进行一些启动参数的设置。

如果允许更新到新版本的 JVM,可以使用新引入的 UseCGroupMemoryLimitForHeapMaxRAMFraction 参数,让 JVM 直接继承容器的定义。

如果无法直接升级,那么就有必要设置 xmx 和 xms 参数了,这里有几个小建议:

  • xmx 和 xms,request 和 limits 建议设成一致,能省掉很多麻烦。
  • tmpfs、filemapping 等都是可能的内存大户。
  • JVM 并不是唯一的内存消耗者,一般建议 Limit 大于 XMX 25% 以上。
  • /sys/fs/cgroup/memory/memory.stat 是你的好朋友。
Avatar
崔秀龙

简单,是大师的责任;我们凡夫俗子,能做到清楚就很不容易了。

comments powered by Disqus
下一页
上一页

相关