撰稿 | 言征
出品 | 51CTO技术栈(微信号:blog51cto)
公司业务高歌猛进时,云成本被掩埋在“数字繁荣”之中,但一旦红利退却,云超高的成本就会让老板们觉得如鲠在喉。这并不是一朝一夕的问题。
这样的大环境下,企业的侧重点变成了,如何在不影响应用性能、尽量保持基础设施不变的情况下,削减云开支。
在今天的文章中,会为诸位带来一个“对基础设施做出简单改变,并将成本降低 30%的案例,并探究云成本到底哪里贵了。
一、一个操作,6万美元没了
云计算带来的体验可以说是前所未有:几秒钟内生成一个服务器,后端配上无服务器,前端配上存储桶,就可以托管起整个网站,直到调用数量达到限制之前,该过程甚至都可以不花一分钱。
但是,流量开始增加后,痛苦就来了,就如同“走钢丝”一般,必须变得小心翼翼起来,因为免费只是暂时的,一个操作不当,糟糕的事情就奔你而来。
网络上有很多关于公司或某开发人员一夜之间云成本账户银行卡被通知“刷爆”的恐怖故事,可谓触目惊心:
上述造成的云账单,有的是因为一个调用了 lambda 函数而导致了 4.5k 美元的费用,有的则是因为按照某云的说明文档做了一个测试任务,结果3个月后收到了6万美元的邮件账单。
图片
这些并非个例,但因为高昂地上云的成本就简单粗暴下云,却又是另外一番动人心魄的故事,这里不再赘述。
二、云,哪里跑“贵”了?
问题就在于,既想要云端的高效便捷、弹性足够、便于维护,又不想云账单一日千里地不可控,有没有一些可参考的方法和实践?
我们不妨先看一下这张账单:
图片
21,433.21 欧元。这是笔者公司在 2022 年 10 月为临时环境和生产环境支付的总费用。细分来看,K8s集群、云存储赫然在列——
- Kubernetes 集群13,743.83 欧元(折扣2,333.84欧元)
- 云存储(存储桶)6,124.75 欧元
- SQL 数据库3,237.22 欧元
- 还有其他较小的成本,本文中忽略不计。
虽然成本并未失控,但 Kubernetes 集群和存储让我们付出了昂贵的代价。
三、K8s集群哪里贵了?
接下来,就是分开看这两块的成本产生过程。首先是 Kubernetes 集群本身在生产环境上的成本细分。通过下图就能看出三大罪魁祸首:
计算引擎中的N1预定义实例Core/RAM、Spot可抢占实例、区域间网络出口产生的费用最高。
图片
谷歌云计费页面的屏幕截图显示了我们的临时和生产环境的价格
Tips:对于那些不熟悉的人来说,这些标签可能需要解释一下:
- N1 预定义实例 core/ram 是我们 Kubernetes 集群日常使用的节点。N1 是节点类型。
- Spot 可抢占实例 core/ram 是我们生成的用于运行异步任务的节点。可抢占意味着我们为这些节点支付更少的费用,但我们无法保证可用性。
- 区域间网络出口(Network Egress Inter Zone)是通过网络在可用区域(AZ)之间移动的数据。假设有一个托管在区域 AZ 中的节点中的 API,如果该 API 向 AZ B 中的节点中的另一个 API 进行查询,将为从 AZ B 到 AZ A 的数据付费。
问题一:没有管理好Kubernetes的预期
我们接着逐个攻破。从成本明细中最高的开始:N1 预定义实例core/RAM。
问题的根源就在于我们有没有告诉Kubernetes该如何扩展新节点。
N1 预定义实例Core/RAM方面,当前使用的是n1-standard-8节点,它们根据使用情况自动缩放。在进行修正之前,了解 Kubernetes 如何扩展新节点非常有必要。
当定义 Pod 时,需要告诉 Kubernetes 一个信息:Pod 需要多少 RAM 和 CPU 才能正常工作;这就是 Kubernetes 所说的 Request。
假设我的 API 的 pod A 需要 400mo RAM 和 0.2 vCPU 才能正常工作,而 Kubernetes 节点容量为 30 GB RAM 和 8 个 vCPU。可以在该节点中容纳 40 个 Pod,因为 8 个 vCPU 除以 0.2 vCPU 等于 40 个 Pod,而 30,000mo 除以 400mo 等于 75 个 Pod。
所以,于K8s集群而言,明确预期的和未使用的资源,是一个技术活儿。
表示请求的 CPU 与节点实际容量的架构
问题二:配置文件中的魔鬼细节:CPU和内存值
如果在 8 个 vCPU 节点中有 40 个 pod 请求 0.2 vCPU,Kubernetes 会认为该节点已满并启动一个新节点,即使这些 pod 仅使用 4 个 vCPU。
一个合理的配置,就能大大减少因节点数量产生的付费。同时,节点根据请求的资源进行扩展,如何才能避免过多的浪费扩展中的资源浪费呢?
这就需要深入研究 Kubernetes yaml 配置文件,看看可以更改哪些内容。
我们做的第一件事是将 pod 的 yaml 定义与 Grafana 中的实际资源使用情况进行比较。我们可以使用 Grafana 轻松查看请求与实际使用情况的比较,如下所示。
图片
Grafana 在运行一个 pod 时对 1 个 API 的 RAM 请求/使用情况(在撰写本文时拍摄的屏幕截图,因此在配置更新之后)。
在此图中,我们可以看到 RAM 的平均使用率为 0.1go,而请求的 RAM 为 0.4go 。
如果我们将其与此 API 的 YAML 配置进行比较,我们可以发现类似的内容。
来自部署.yaml 文件的 IAC 存储库中的更改的屏幕截图
我们显着减少了请求的内存和 CPU 值,以更接近 API 使用的实际情况 —并且我们仍然保持保守;我们可以进一步减少它。我们对所有服务都执行了此流程。
问题3:默认为单个服务运行了太多的 Pod
例如,对于此部署,我们至少运行三个 Pod,这意味着即使 API 在夜间几乎没有收到任何调用,它仍然运行3个 Pod。
因此,我们检查了每项服务,并将 pod 副本的最小数量减少到一个(在安全的情况下)。
图片
通过这几项更改,搞定了 N1 预定义实例Core/RAM的成本问题,从4,235.43 欧元增加到 1,973.28 欧元。
问题4:区域间网络出口的数据交互费用
这方面是非常棘手的,可用区域之间的网络的数据交互会产生很大的云费用
我们有四十多个微服务,但好处是它们做得很好,而且它们之间几乎没有直接通信,但我们在所有这些服务前面有一个GraphQL 网关。这个网关接到很多调用。
笔者也采取了两种方式解决了这个问题:
第一个是使用 Flow Logs追踪哪些调用对于返回的数据最大。
第二种方法,也是我们最有信心的方法,是检查哪个 API 收到的调用最多,以及该 API 中的哪个端点非常适合缓存。我们已经使用 Redis 作为发布/订阅解决方案,因此我们也可以轻松地将它用作缓存。
我们决定先做缓存,因为我们无论如何都需要它,而且一切都已经设置好了。但这仍然是一个错误——因为我们只是将问题转移到缓存系统中,而不知道数据是否太大是因为代码问题还是因为调用次数过多。
使用Kiali,我们可以看到哪个 API 收到的调用最多。
图片
根据此信息和应用程序的功能方面,我们决定应缓存哪个端点。这样,GraphQL 网关将实现缓存,并且不必对服务进行 HTTP 调用来获取数据,从而降低了 Egress 成本。
仅通过实施第一个解决方案,我们就成功地将出口成本从 2.712,34 欧元降低到 1,095.19 欧元。
遗憾的是,我们尚未实现第二种解决方案来追踪传输大量数据的剩余 HTTP 调用。
四、云存储哪里贵了?
没错,云存储的成本,大部分还是与容量本身有关,而并非存储桶中传输的数据产生的成本。解决的方法自然就很简单:删。
笔者公司的应用程序接收来自用户的视频,我们对其进行标准化并存储原始版本和标准化版本。然后,客户会对这些视频进行编辑和验证(或拒绝)。
此前,我们从未删除过任何内容。我们多年来一直存储用户未使用的视频,并拥有超过 100 TB 的数据。因此,根据我们的法律和产品团队的意见,我们设置了一个 CRON 作业,用于查询数据库的动态参数(例如“视频拒绝”)并存档这些文件。
为了防止出现任何不可恢复的错误,我们首先将文件的存储类别在 GCP 中切换为“归档”(在 S3 中为 Glacier),并使用生命周期规则在六个月后将其完全删除。
2022 年 10 月生产环境存储成本
2023年9月生产环境存储成本
这仍然是一个持续的过程,因为我们必须谨慎决定删除哪些内容,但我们成功地将生产中的存储成本从 4,754.85 欧元降低到 3,029.93 欧元。
五、临时环境的成本也很惊人
这里,还有一个细节不应忽视,就是临时环境所产生的费用也很疯狂。2022 年 10 月,我们为临时环境支付了 4,059.25 欧元,接近生产环境的1/4。
生产环境和临时环境之间的成本明细对比
临时环境下的成本明细
我们采取了四项简单的措施来降低成本:
我们在非办公时间关闭了环境。遗憾的是,由于我们是一支国际团队,工作日晚上的时间不多。
我们缩小了 Kubernetes 集群规模,将所有部署的最小 pod 设置为 1,并防止自动扩展超过 1 个 pod——除了一些关键服务。
我们向云存储桶添加了生命周期规则,以删除六个月或更早的所有内容。我们清理了数据库,并删除了以前开发人员或 QA 中不再使用的所有数据。
图片
通过这四个简单的步骤,我们将临时环境的月开销降低了 2500多欧元!
六、进一步削减云成本的思路
其他削减云成本的办法吗?
当然,我们已经对计划如何进一步降低成本有了一些想法,更多的是延续上文的内容。
(1)微调 Kubernetes 请求,以更加精确地了解我们的微服务需要运行的内容;
(2)按照我们最初的计划追踪剩余的出口成本
(3)继续在我们的归档 cron 中实施新规则,从存储桶中删除不必要的文件;
(4)将我们的视频处理从 CPU 切换到 GPU(笔者实测速度更快且成本更低);
(5)清理生产中的 SQL 数据库,存储可存档的 TB 级事件数据。
如果我们比较 2022 年 10 月和 2023 年 10 月,我们每个月节省了 6,369.75 欧元,几乎节省了 30%,我相信我们可以节省更多。
七、写在最后
追踪云成本并优化是一件非常非常有挑战的、且富有成就感的事情。于与云程师、架构师而言,即便支付云账单的账户是公司,而不是自己。
但说起来容易,做起来难 。在个人项目上使用云的免费层和在每天有数百万次调用的生产环境中使用云是两种完全不同的野兽。
本文带大家从头开始分析了云成本过高的几个问题:生产环境下的K8s集群、云存储的问题、以及临时环境下的不必要的开支,并给出了解决思路和计划。
记住:从一开始就考虑应用程序的生命周期,并采取适当的保护措施,以防止您的云成本过高,而不是一味按照文档配置部署,否则,迎接你的只能是高昂的收费通知。
参考链接:https://alexandreolive.medium.com/how-we-manage-to-reduce-our-cloud-costs-by-25-percents-3f8c26db704a