简体中文
English
2022-09-08

蔡超:我们为什么需要云原生技术?

汇量科技集团首席工程架构师蔡超谈“云原生”新机遇。

Avatar
杨昕仪

内容营销经理

蔡超,汇量科技集团首席工程架构师,领导汇量科技云计算及基础架构业务中心。

在亚马逊云科技公布的 2022 亚马逊云科技Heroes 名单中,蔡超被提名为新晋亚马逊云科技 Hero。

作为一名拥有超过15年软件开发经验的资深架构师,蔡超多年来始终保持着对前沿技术的敏锐洞察力,在他看来,云计算之后,“云原生”将是企业探索新机遇、寻求新增长的另一个拐点。

 

软件架构一直在演进

微服务是更适合云计算的架构

今年,接续直播、5G、IoT等新领域迅猛发展以及数据库等基础软件重返聚光灯下的火热态势,云原生有了比较大的爆发。业务对于云的形态的需求越来越高,大家希望云能够更贴近数据的产生点,因此相应的边缘云、本地云、混合云的形态越来越多,云原生技术天然能够比较好地解决云变成多形态后的统一界面管理问题,包括混合云带来的复杂度挑战,业务场景驱动了技术的普遍落地,整个云计算的技术演进是朝着越来越灵活的方向发展。所有软件架构及开发方式的研究始终都是为了更好、更快地交付应用系统。“云原生”是一种充分利用云计算模式的优点来构建和运行应用的方法。回顾历史会发现,软件架构其实一直在演进,从单体架构到微服务之间经历了多次迭代,这种进化是与基础设施的进化相伴而生的。到了云原生时代,之所以CNCF推荐使用微服务架构,是他能够更好的适配云基础设施的特征(按需获取,按使用付费,弹性伸缩,非预期失效等) ;微服务将功能拆分到粒度级别,由此:

  • 单体服务中某个功能出现瓶颈,必须复制整个实例,新加的服务器还要承载运行整个单体服务,伸缩粒度非常粗放;相比之下,微服务提供了更精准、更细粒度的伸缩,通过使用更小的计算资源,获得更低的成本(适配“按使用付费”)。
  • 微服务小型化还能让服务启动速度更快,更好地配合云端动态资源的快速弹性。(适配“按需获取”,“弹性伸缩”)
  • 与单体服务不同,微服务架构中系统崩溃时只会损失一部分功能,并较容易通过微服务的功能分布式特性来实现服务降级等面向失效的设计,降低失效对客户的影响。(适配“非预期失效”)

云原生技术帮助企业

从管理宠物过渡到管理牛群

云原生是一种构建和运行软件应用程序的现代方法,它充分利用了云计算的灵活性、可扩展性和弹性。云原生不是一个全新的概念,而是在整个云计算发展历程中的对理念的更新和延伸。用云原生计算基金会(CNCF )自己的话来描述:“云原生技术使组织能够在公共、私有和混合云等现代动态环境中构建和运行可扩展的应用程序。”随着容器技术的普及,过去几年 Kubernetes 已经成为云原生基础设施的事实标准,即便受疫情影响,今年在全球不同地区开展的线上 Kubecon 大会依旧火爆。CNCF 社区同样发展迅速,数据显示,云原生计算基金会(CNCF )现在拥有 730 多个成员组织和 100 多个开源云原生项目,整个云原生生态逐步趋于完善。但在上云之前,很多企业会用到小型机、工作站这样的高性能机器,这些机器对企业而言就像是宠物一样的资产。因为每一台机器都会做专门的工作,有固定的IP,就像宠物有自己的名字一样。但在企业上云之后,系统管理的机器会随着弹性伸缩而随时增减,负载在大量机器之间来回迁移,就像牛群一样不可能给每台机器都定义名称和专用的目的。所以在上云后,管理大规模弹性集群就像是从饲养几只宠物变成了放养一片牛群。这一变化带来的影响不止于硬件层面。硬件上,过去升级机器时会给每一台机器提升配置,叫做Scale Up;今天则是扩展集群机器数量,亦即Scale Out。软件侧,过去针对每一台机器都有特定的操作和维护方式,今天的运行环境必须做到可重复,可以简单、稳定、在线部署到任何一台机器上。

云原生很重要的一个概念是不可变,它就是与牛群模式相对应的。首先,整个CI/CD过程就是一个不断将可变变为不可变的过程。上图中每一步都是要锁定一部分内容,做到不可变。有了不可变,才能随时得到不同资源组合的稳定版本,然后才能重复部署,或者安全及准确的回退到之前的版本。知名的康威定律认为,组织团队之间的通讯和交流的模式,最终会映射成软件系统或者产品的形态。反过来说,就是组织结构要同软件系统的架构相匹配。

对于微服务来说,背景就是组织的团队拆分得更小,每个团队都有自己的边界,有自己的微服务,并且还要独立部署。独立部署是微服务的精髓,服务部署时还要依赖其他团队,本质上就不是微服务了。

MaxCloud

让开发人员轻松实践DevOps

除了微服务外,容器化是另一个云原生实践。Kubernetes 是今天最常用的容器编排平台,被视为云原生操作系统。根据康威定律,在 Mobvista 内部,技术团队通过自研的系统 MaxCloud(MaxCloud 是 Mobvista 自研的 DevOps 平台,它封装了云原生技术栈的复杂性,内置了云原生的最佳实践)将企业的组织结构映射到 K8S 中。

这里的一种尝试是利用命名空间。因为今天很多公司用命名空间来划分不同的服务,如果把命名空间和项目、组织和集中在一起映射上,就可以做到很多事情。例如可以根据每个团队所做的项目涉及的服务来为它们划分权限。甚至可以设定每个命名空间可以使用的 CPU 和内存资源,来实现很多资源管控策略。

我列举了汇量科技在实践中总结出来的一些对于 DevOps 团队来说很有参考价值的技巧:

Pod 生命周期

Pod 是 Kubernetes 的基本调度单位。要用好 Kubernetes 就要掌握好 Kubernetes 的生命周期。下图就是 Pod 的生命周期。

首先看 Init container。Init container 一定要在 Main container 之前执行,而且成功之后才会开始 Main container,如果它失败,Pod 也会失败。根据这样的特性,我们可以用它来做初始化的工作。当我们要在 Main container 加载一些配置数据时,在它启动之前可以用 Init container 来替它加载,如下图。

两个 container 可以共享一个存储卷( volume);通过 Init container 把数据准备到这个共享存储空间的路径上,Main container 就可以在这个存储上加载数据。这样一来,Main container 就会与数据加载以及初始化的方式彻底解耦。可以使用不同的方式来加载,比如说从 GitHub、数据库、S3 上加载,但都不需要修改程序,只需要放不同的 Init container 即可。当然也可以利用 Init container 做依赖项的等待,比如说一个依赖要不断检查,检查好之后 Init container 退出,Main container 起来,这样是可以的。

下图是另一个例子,加载负载配置。这里利用另一个 container 的组合让 Pod 软件解耦数据装载的方式,提高扩展性。

与 postStart 对比:

  • postStart 是异步执行的。
  • postStart 过程不能保证在 container 的入口点前执行完成。
  • Container 的状态在 postStart 过程完成后才会被置为 RUNNING。

另外,利用上述postStart特性,如果在 pod 中包含多个 container,当我们需要某个 container 先完成启动就绪,就绪完成后才继续下一个 container 的创建,那么就可以在前一个 container 中加一个 postStart。这个 postStart 过程只是检查自己是否就绪,如果一直没有就绪,退出后返回不正常时整个 Pod 会失败,无法创建成功。如果创建成功,意味着已经就绪,就可以继续启动下一个 container。而且这个方式可以用在不同场景中,尤其是在 sidecar 的场景中,需要确保 sidecar 首先就绪。以下是两者的简单对比:

此外,终止也非常重要。当一个 Pod 被终止,它会在服务发现里摘掉,不接受流量,状态变成 terminating。这时它会收到一个信号,叫 SIGTERM,告诉它应该准备停止了。这个时候并不会把 container 马上杀掉,而是会给一段时间,默认值是 30 秒。在这个 30 秒之后会收到另一个信号叫 SIGKILL,是强制的,立刻杀掉。当然我们并不需要一定要处理 SIGTERM,而是可以用一个叫 PreStop 的 hook 来优雅地处理。它可以实现完美中断,避免数据损失或服务发现未摘掉等情况。

最后,是健康检查,也就是 readiness。它的重点是在发布和伸缩时确保新增 Pod 都是就绪的,避免未就绪时就接收外部请求带来的很多错误。

QoS vs Priority

Qos 和 Priority 是非常容易搞混的概念,很多人一直以为他们心目中的 Priority 是 Priority,而其实那是 Qos。下图展示的是 Priority 的内容。

通常情况下我们不提倡设定对 pod 设定优先级,因为优先级越来越高,很容易失控。我们更期望的是与调度无关、与启动顺序无关的更好的架构。

下图是 QoS,这往往是很多人心目中的认为的 Priority。当一个 Node 上有很多 Pod 在运行,可能会出现 Node 资源不够用的情况,那么哪些 Pod 会被杀死?哪些 Pod 会被保留下来?这个叫 QoS。

Affinity vs Taint

Affinity 亲和性和 Taint 这两个概念有很多工程师也容易混淆。所谓亲和性是从 Pod 的视角去看,什么样的 Node 适合我来运行。Taint 是从 Node 的角度来看自己可以运行什么样的 Pod,兼容了 node 上的 taint 的 pod 才可以被调度到 node 上。

集成化和版本化

集成化和版本化Kubernetes 是从资源的视角来设计的,所以在部署时要写很多资源定义相关的 yaml 文件,不仅学习曲线陡峭,维护起来也不容易。所谓 DevOps 就是让一个团队负责开发和运维,但开发人员往往并不习惯资源视角,就会犯很多错误。

汇量科技对此的思考是,如果做 DevOps,是不是应该把资源视角转化成一种对于应用的管理视角?是不是应该把这种不可变性进一步扩展,把所有资源聚集在一起,变成应用程序的一个包(Bundle)。能不能实现这个包的版本化?让它实现不可变性,这样就会让开发人员应用起来更自然。

于是汇量科技就开发了一个平台,叫 MaxCloud。

MaxCloud结合汇量科技对云原生技术栈的实践,可以帮助其它客户更轻松地使用云原生技术栈,帮助研发人员实践DevOps。企业可以利用MaxCloud把组织结构和项目、微服务匹配在一起,遵循康威定律。不仅如此,MaxCloud封装了很多云原生的复杂性,同时给大家提供一些最佳实践。

Amazon EKS 是一项托管容器服务,可以在云中和本地,来运行和扩展 Kubernetes 应用程序。基于 Kubernetes 的现有应用程序与 Amazon EKS 兼容。企业可以利用 MaxCloud 把组织结构和项目、微服务匹配在一起,实现康威定律。不仅如此,MaxCloud 封装了很多云原生的复杂性,同时给大家提供一些最佳实践。

下图是MaxCloud的界面。

MaxCloud把各种碎片的资源组合到一起成为一个bundle。这个bundle不是完全手动打包,而是会自动进行。选中了一个service,它会自己把一些有依赖关系的资源如deployment、configmap、secret等等聚合在一起,完成后可以手动调整或添加我们认为相关的资源。一旦打成了这个应用的bundle,就可以通过这个应用bundle聚合一些不同资源的告警事件,便于用户找到这些独立事件的相关性,快速定位根本问题。

此外,打成bundle之后还要对bundle做版本化,和GitOps打通。当利用GitOps提交到任何一个资源,只要是bundle当中的,都会触发MaxCloud起一个新的bundle的版本(Immutable,不可变性),然后自动同步到多个集群中。当出现问题时,可以按整个按bundle回退,不会出现其中某个资源被忘记这种尴尬。

SpotMax有效利用云端收费模式:

按需获取,按使用付费

Kubernetes HPA 可以自动伸缩 Pod,但只是伸缩 Pod 没用,Node 才是真正要付费的。这个时候可以利用 CA(Cluster Autoscaler),它会把一些闲置的 Node 从集群里面卸掉,提升 Node 利用率,降低成本。

用量波峰差距较大时,一般会选择 Spot instance 模式。Amazon EC2 Spot 实例是使用闲置 EC2 容量的实例,其价格远低于按需实例的 EC2 实例价格。但 Spot 实例在发生中断时将暂停或停止 / 关闭 实例,当容量可用时实例可以从之前的状态中恢复。Kubernetes 集群对 Spot instance 比较友好,如下图所示。

当然,在使用Spot时也有几点需要注意。

首先,因为Node会回收Spot instance,所以不要把所有的Pod部署在一个Node上,否则一回收全没了,这个可以利用Antiaffinity来做到。

其次,当你开始在集群中引入Spot instance,需要注意原有的应用程序和部署是否支持。最好的方法是给Spot instance node打一个污点,让可以兼容它的部署才部署在上面。

那么,该如何能够降低Spot instance回收带来的中断影响?我认为其实可以借助一些外部工具,比如说汇量科技的SpotMax。

SpotMax 是汇量科技基于 Amazon EC2 Spot 实例构建的云原生弹性集群管理平台,可以实现自动化的 Spot 实例资源管理与调度而无需担心资源容易中断回收而影响稳定性。

SpotMax 能够无缝整合 Kubernetes 和 Amazon EKS。它首先通过利用大数据及线上实时学习技术,实时优化线上集群组成,降低整个集群的中断概率。在中断发生前,SpotMax 会在资源层面替你先把 Node 加进去,初始化好。这个过程中它会主动告诉 EKS 或 Kubernetes 的 API server,你现在可以把 Pod 安全地迁移到我新加入的这个 Node 上,这个 Node 也是根据 SpotMax 里的 expert system 选择出来的一个中断率更低的 Node,平滑迁移 Pod。整个过程几秒钟就可以完成(在不使用 SpotMax 的情况下这个过程需要大约 2 分钟)。

任何一项技术的改进和升级,归根结底都要为业务服务,为企业降本、增效。汇量科技(Mobvista)规模化使用亚马逊云科技的低成本算力资源,构建了云原生的弹性集群管理平台SpotMax,而SpotMax加上MaxCloud两项技术的成功落地,帮助汇量科技移动广告业务的单位广告请求成本降低65%。利用亚马逊云科技多项数据分析和机器学习服务打造的广告交易平台,轻松应对日均10亿台的独立移动设备高达2000亿次的广告请求。

引入了容器之后,带来的改变绝对不仅仅是构建、部署和维护的方式这么简单。其实每一次软件设计的变更都涉及到新增的构建块,带来新的设计思考。但这些设计的出发点还是一样的,例如 Sidecar 模式就是利用了一个 Pod 里面的 container 可以共享 volume 或者 container 间网络通讯的特性,来将一些功能从主 container 中解耦,使得主 container 更具扩展性,能够和不同 sidecar 配合适应不同场景。比如一个 Main container 打日志出来,就可以用 Sidecar 来整理这些日志,与业务逻辑实现解耦。

写在最后

技术的演进日新月异,在对技术保有初心、保持敬畏的同时,无需感到焦虑,而要多思考这些技术更迭背后不变的本质,更多去关注那些不变的技术和知识,注重基础知识的学习和积累。

构筑自己专业能力的过程要耐得住寂寞,这个过程好比是在盖一个楼,那些可以快速学会的应用新技术,可以让我们很快盖一个别人能注意到的小楼。而对那些基础知识的学习,效果并不会立即体现在你的工作中,因为你不是在往地面上建,而是在往地下打地基,打一个很深的地基。当然不会被人们注意到,当有一天别人看到你的高楼的时候,会不禁高山仰止。

Share