前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Kubernetes重新思考系统架构并减轻技术债务

使用Kubernetes重新思考系统架构并减轻技术债务

作者头像
用户5166556
发布2023-03-18 14:03:25
5790
发布2023-03-18 14:03:25
举报
文章被收录于专栏:让技术和时代并行

这是一个关于尝试重新思考复杂系统的故事,您在尝试重建它们时面临的挑战,随着它们的增长而面临的负担越来越大,您很难通过架构自身解决自身的问题。当您权衡更换架构的风险和回报时,可能需要多次尝试才能找到适合您的解决方案。

当开发人员接手了一个软件,一般不想费心去理解它是如何工作的时候,通常情况下重写是一种看起来比较好的方式。经验丰富的管理者和高级工程师都知道,除非确实有必要,否则应该避免重写,因为重写通常涉及很多复杂性,并且会在重写过程中引入新问题。

我是 Pusher 的高级工程师,这是一家专注于构建实时消息分发的公司。Pusher Channels 是我们用于构建可扩展实时数据功能的发布/订阅 WebSocket 服务,已经存在了一段时间。直到最近,所有通道都在 AWS EC2 实例上运行。机器使用封装 Ansible playbook 的 Python 脚本进行配置和引导。配置和流程管理主要由 Puppet 处理,在 Upstart、God 和内部编写的许多工具的帮助下。

我们管理 EC2 实例必须像对待宠物一样。如果必须更换一台机器,工程师手动将流量/服务从旧机器迁移到新机器,然后关闭旧机器。如果集群需要更多容量,工程师会配置一些新机器并将它们连接到集群。这种方法有其缺点:

  • 有大量的手动工作介入以保持服务的正常运行
  • 非标准化的内部工具使新团队成员入职变得棘手

……但它在很长一段时间内都运行良好,并且该系统的大部分仍在将我们推向新的高度。团队成员发生了变化,我们推出了 Pusher Beams,我们淘汰了 Pusher Chatkit,我们的用户群体一直在增长。一直以来,Pusher Channels 基础设施基本保持不变,但随着规模大幅增加,问题逐渐出现。

维护成本

随着 Channels 集群变得越来越大,运行它的维护负担几乎呈线性增长。不久之后,每周大量的工程时间都花在了保证设备正常运行上。

很明显,我们需要做一些事情来减轻维护负担;然而,试图为我们的客户维护高度可靠的服务意味着我们在过去几年中一直在与不可避免的技术债务和遗留基础设施的积累作斗争,这些债务和遗留基础设施是大规模管理和维护复杂系统造成的。

在这段时间里,我们多次尝试对我们的基础设施和应用程序进行现代化改造,但遇到了许多与尝试重写或重新构建系统相关的常见问题。这意味着我们仍然面临着同样的挑战。这些问题源于试图同时实现基础设施和应用程序的现代化,而不是只专注于我们面临的最大挑战,即基础设施本身的管理和维护。

如何破局

我们花了一些时间在各种方新的方案之间来回尝试。我们尝试在我们现有的基础设施供应系统中引入更多自动化,并尝试彻底重写我们的核心应用程序服务。然而,许多解决方案以不明显的方式相互纠缠或依赖。

大多数解决方案都存在我们尚未拥有的新型基础设施。然后引入这些新型基础设施,为了适应这些新型基础设施,开发人员不得不学习新技能,甚至引入更多的新型基础设施。

在经历了一些挫折之后,我们重新考虑了问题的初衷和事情的本质。其实我们想选择一个能够实现关键目标的解决方案,并在未来继续迭代。我们总结出总体目标是得到一个更简单、一致、更易于维护和更易于扩展的平台。这将使我们能够花更少的时间维护和管理平台,而将更多时间用于构建和开发新产品和功能。

在对我们的基础设施和应用程序的当前状态进行全面审核后,我们得出以下结论:

  • 将尽可能多的基础架构复杂性转移到托管服务
  • 将尽可能多的现有应用程序迁移到这个新的基础架构,而无需对应用程序代码库进行大量重写
  • 确定可以扩展、重新编写的组件,而不会增加基础架构迁移的摩擦,并主要投资于转换和简化它们。

基础设施

一段时间以来,我们一直热衷于开始利用 a**的自动缩放功能。在分析了使用自动缩放所需的工作后,我们确定这将需要大量投资来完成这个过程:

  • 扩展我们的定制部署工具——它已经依赖于 EOL 软件——与 cloudinit 一起工作并从新贵迁移到 systemd。由于解决方案的定制性质,这也会增加新员工的熟悉过程。
  • 迁移到行业已经标准化的技术,例如容器。

我们内部在其它解决方案中投入时间/精力/金钱成本太高、意义不大,所以最终我们选择采用容器完成基础设施的构建。

容器化

为了迁移到容器,我们需要:

  • 容器化核心应用服务;
  • 更新应用服务的构建过程以构建和存储容器镜像;
  • 选择某种方式在生产中运行这些容器;
  • 更改服务流量的路由过程以更优雅地处理容器终止。

当我们分解为自动扩展组将现有 EC2 设置容器化所需的工作时,我们大部分时间都朝着 Kubernetes 之类的方向发展,我们在公司的其他地方大量使用它,并为我们提供了更多的功能。

但这会产生额外的工作,例如,添加额外的管理服务以将我们的核心应用程序服务迁移到 Kubernetes。最后,我们认为这是值得的,原因如下:

  • 专为我们的问题而构建——Kubernetes 旨在解决我们遇到的问题——跨多个节点弹性管理工作负载。
  • 内部经验——我们在内部有很多 Kubernetes 经验,并且已经在运行多个集群。
  • 招聘– Kubernetes 是该领域的主要工具之一。雇用具有 Kubernetes 经验或渴望学习它的工程师比雇用想使用 Puppet/Ansible 的人容易得多。
  • 入职——我们现有的解决方案是定制的,因此任何新加入者都必须花费大量时间来学习我们所有自制工具的来龙去脉。Kubernetes 有很好的文档,因此即使没有经验的新手也可以更快地上手。
  • 卸载基础设施的复杂性——这一变化将使我们能够将复杂性转移到像 EKS 这样的托管服务上。

应用程序

我们之前在尝试改进 Channels 时陷入的陷阱之一是尝试重写应用程序的大部分内容,同时尝试减少运行基础设施的维护负担。这种紧密耦合的方法导致了一些挫折和放弃的尝试。有了这个新计划,我们主要是寻找解决方案,将我们的大部分应用程序移植到 Kubernetes,而无需进行大型应用程序重写。

然而,我们仍然热衷于战略性地改进应用程序的某些部分,只要它不会从根本上增加迁移到新基础架构的成本。我们发现这种方法让工程师可以自由地对应用程序进行技术改进,并有机会减少应用程序组件的维护负担,另外这些应用程序组件经常遇到移植到 Kubernetes 无法解决的问题。

例如,我们最近写了我们的 webhook 系统,从 EC2 上的 EventMachine 到 Go on Kubernetes。这没有涵盖的一件事是重写实际从 SQS 出列作业并发送 webhook 的组件。该组件最近开始引发大量告警邮件,需要重构。

重写 webhook 发送器

我们知道将我们的 webhook 发送器组件从 EC2 移植到 Kubernetes 很重要,因为我们已经开始遇到越来越多的该组件的操作问题。由于缺乏自动缩放,负责发送 webhook 的进程运行在我们称为发送方机器的专用 EC2 机器上。在我们的一个集群上,我们有四台发送方机器,每台机器运行 12 个 webhook 发送方进程(称为 Clowns,由它们处理队列中的作业)。这对于集群的峰值负载来说已经足够了,通常我们会预留一些意外峰值的空间。

由于我们已经在 Go 中大量重写了大部分 webhook 管道,因此通过重写发送者本身来完成这个过程也是有意义的。webhook 发送器是一个非常简单的软件。它从 SQS 队列读取作业并发出 HTTP POST 请求。进程从 SQS 读取的作业包含进程将 HTTP POST 请求发送到客户服务器所需的一切。

因为 webhook 发送器是一个令人尴尬的并行进程,它非常适合利用像 Kubernetes 这样的系统的扩展优势。通过在 Go 中重写它,我们还可以实现一些优于 EventMachine 的性能优势,就像我们在使用 webhook 打包器和发布器。

因为 webhook 发送服务是一种无状态服务,所以很容易将新发送服务与旧发送服务一起部署,让他们互相竞争。这意味着我们可以逐步推出新的发送服务,并依靠旧的发送服务在出现意外问题时继续为队列提供服务。事实上,我们在一些较小的集群上发现,新的发送服务效率很高,旧的发送服务基本上没有工作可做。

图 1. Rollout:随着新发送服务的效率接管其工作,流向旧发送服务的流量逐渐减少

图 2. Rollout:新发送接收服务

最后,我们最大的集群从 4 * 台机器,每台机器有 12 个 Clowns,到 3-15 个 Kubernetes Pod,每个请求 250mCPU。

图 3. 切换过程积压服务的变化

图 4. 新的自动缩放(超过一周)

简而言之,这是非常成功的。我们的 EC2 和 Eventmachine 架构中的另一个组件从列表中划掉,意味着多余的框架再也不用维护了。

概括

关于尝试重构和重写系统有据可查的故事数不胜数,并且通常包含有关开始此类项目重构后的警告。我们这些以前在架构大修方面有经验的人几乎总是会不惜一切代价避免重写,因为它们经常出错。此外,复杂的系统通常是有原因的。正如切斯特顿的围栏所解释的那样,我们通常最好假设先于我们的人知道一些我们不知道的事情。

然而,在此过程中经历了一些失败和挑战之后,我们找到了前进的道路和方法,它确实允许我们有效地重写代码,同时减少我们的维护负担。公平地说,我们的重写可能不是乔尔·斯波尔斯基(Joel Spolsky)所说的重写永远是您不应该做的事情之一的意思。

但我们发现,通过识别具有明确定义边界的组件,可以在不丢弃整个系统的情况下重写它们。如果您可以确定明确定义的边界和接口,事情就会变得容易得多。在 webhooks 管道场景下,它有一个队列形式的逻辑边界。随着时间的推移,我们可以重写其中的部分内容,这使我们能够测试和验证管道中的新组件,同时仍然能够在发生故障时回滚。

我们还发现,随着这些项目中的每一个完成,我们都实现了减少运营负担的好处,这意味着我们实际上可以加快进度。突破是最大的挑战,重要的是要保持势头,避免回退到不可持续的领域。现在我们已经打破了壁垒,我们对拥有一个更简单的系统感到兴奋和自信,该系统使我们能够专注于做我们真正喜欢做的事情 - 构建出色的产品和酷炫的功能,而不仅仅是保持灯火通明。

参考资料

[1]

pusher: https://pusher.com/channels

[2]

ansible: https://en.wikipedia.org/wiki/Ansible_(software)

[3]

Puppet: https://en.wikipedia.org/wiki/Puppet_%28software%29

[4]

自动扩容: https://docs.aws.amazon.com/autoscaling/ec2/userguide/AutoScalingGroup.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生技术爱好者社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 维护成本
  • 如何破局
  • 基础设施
  • 容器化
  • 应用程序
    • 重写 webhook 发送器
    • 概括
      • 参考资料
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档