最近在闲逛 Github 的时候看到一本电子书籍《深入架构原理与实践》,花了一些时间翻阅学习,发现竟然是本宝藏书籍!里面的内容比较硬核,有一定的深度,非常值得推荐大家一看。
作者在书本中分享了云原生、网络、容器、分布式等系统架构的知识内容。尤其是云原生、微服务和服务网格相关的章节,让小年有了更深的认识。所以小年今天这篇文章主要是简单记录一下读书笔记。
什么是云原生?
相信大家对云原生这一词并不陌生,毕竟都 2023 年了,不会还有人没听过吧?如果还没听过云原生的同学,估计你要换手机了。
但在讨论什么是云原生之前,我们先回顾一下有关“云”在过去发展历程的一些重要历史阶段。
云计算
云计算,可以说是“云”发展的第一个重要时期。
云计算已经有十几年的发展历史,发展到今日已经是非常成熟了。小年认为云计算带来最核心变革是:降本增效!
回想一下,在云计算普遍之前,企业要自行采购或者搭建 IDC 机房,还需要配置带宽、交换机、网络、安装软件、运行环境等各种繁杂的操作。运维成本极大,耗费运维人员非常大的精力。这个小年深有体会,当年为了给客户部署应用,千里迢迢来回跑客户的机房安装部署环境和应用。而且不同的操作系统对于不同软件还有版本兼容性的问题,可想而知是有多麻烦。
而现在基本很少人能够体会到从软硬件自行搭建部署的这套流程。运维人员只需要在控制面板轻点鼠标或者脚本一键运行,就可以自助搭建好完整的应用所需的软硬件环境,按量计费,而且可以根据业务需求随时弹性扩展。省去了硬件层面的维护,让运维人员更加聚焦于软件层面。
虚拟化技术
确切来说,云计算最基础核心的是虚拟化技术。正是虚拟化技术的成熟,使得云计算市场开始真正发展起来。
相信爱折腾的小伙伴都玩过虚拟机,比如 VMware、Virtual Box、Parallels Desktop。如果是CS专业的同学,应该都会记得在大学操作系统的上机实操课,老师都是在 Windows PC 上的虚拟机中教学 Linux 。
英特尔(Intel) 创始人之一 戈登·摩尔提出非常有名的摩尔定律,简而言之:每隔18个月,芯片的性能会增加一倍。
虚拟化技术的出现,是为了让应用能够充分利用硬件快速发展的性能,得以让应用更加充分灵活的利用物理机的硬件资源。
云计算在发展的过程中演进出多种多样的云服务模型,主要分为三大类:
- IaaS(基础设施即服务)
- PaaS(平台即服务)
- SaaS(软件即服务)
当然,随着技术的不断更新发展,云计算提供的能力也越趋丰富,比如容器与微服务的兴起、Serverless 架构模式的出现,于是又衍生两种新的服务模型:FaaS(功能即服务)、CaaS(容器即服务)。
容器技术
谈到容器技术,大家第一时间自然而然会想到:Docker、k8s。确实,这两者的出现对云原生的发展来说意义非凡,属于是云原生进化发展的里程碑。
2013 年 Docker 发布,给云计算带来了一个颠覆性的变革。
Docker 核心关键带来的并不是容器技术,因为 2008 年 LXC (Linux Container)的出现,市场上就已经有各种容器技术和框架,包括 Google、CloudFoundry 等大公司也发布自家的版本。
LXC 技术 (Linux Container),也就是 Cgroups、Namespace 这两个核心功能实现容器之间的资源隔离(CPU、内存、磁盘、网络等),相比于传统且有点笨重的虚拟机来说,容器更加体现出它的轻量和敏捷,且移植性更高。
最初 Docker 也是使用 LXC 实现资源隔离,即使后面用自己的 libcontainer 库实现。然而 Docker 真正带来的创新变革是容器镜像(docker image),它颠覆了已往传统的应用构建、交付、运行的方式。正如其口号:"Build, Ship, and Run Any App, Anywhere."
还有一个口号大家可能更为熟悉:Build once, Run anywhere.
简而言之,容器镜像会把整个应用和运行的依赖环境,甚至包括操作系统都打到一个镜像文件里。这就是它为什么轻量和移植性高的原因。正因为 Docker 对容器镜像的变革,才使容器真正开始迅速普及,并进入大家的视野。
在 Docker 崭露头角之后,市场掀起了一股容器风,各大公司都想分摊这个新领域的大蛋糕。奈何 Docker 作为第一个吃螃蟹的人,占据了绝对的先机。
但很快大家又意识到一个问题了,对于单机应用的打包、发布、构建来说,Docker 确实起到了非常大的作用,然而真实的企业系统架构是纷繁复杂的,有多个不同的业务系统,之间可能存在复杂的上下游依赖关系和网络环境。而且更需要的是具备弹性、可观测性等特性。这时大家需要能够对容器进行编排管理,Kubernetes 因此孕育而生。
2014 年谷歌将 k8s 开源后(前身是内部集群管理系统 Borg ),并在 2015 年与 Linux 等一票巨头成立 CNCF,最初目的是为了跟当时一家独大的 Docker 公司对抗,同期谷歌将 k8s 捐献给 CNCF。
这也标记从最初的容器阶段过渡到容器编排阶段。
当然,现在我们都知道在这场编排大战中最终的赢家是谁,没错就是 k8s。尽管期间 Docker 也推出自己的集群管理和容器编排 Docker Swarm、Docker Compose,但无奈 Docker 的自负与傲慢,而且 k8s 本身有着非常优秀的设计理念和架构,提供的能力更加丰富,比如容器部署、弹性扩缩容、、滚动更新,计算资源分配等,完全释放了运维人员的双手。
至此,云原生基本核心方向都是以 Kubernetes 基础,继续发展演进。
什么是云原生?
现在我们再回来思考一开始的问题,什么是云原生?
要回答这个问题,其实是有些困难。因为云原生本身本身没有确切的定义,而且在不同的时期云原生有不同的定义。
我们先来看一下 Pivotal 和 CNCF 这两个代表,他们对云原生的定义是怎么样的。
Pivotal 是云原生的先驱者和探索者,在 2013 年技术经理 Matt Stine 首次提出云原生(Cloud Native)的概念,2015 年Matt Stine 在《迁移到云原生应用架构》一书中定义了云原生架构的 5 个特征:
- 符合 12 因素应用
- 微服务架构
- 自服务敏捷架构
- 基于 API 协作
- 抗脆弱性
2017 年 Matt Stine 对云原生的定义做了调整:
- 模块化(Modularity)
- 可观测性(Observability)
- 可部署型(Deployability)
- 可测试性(Testability)
- 可处理性(Disposability)
- 可替换性(Replaceability)
而现在 Pivotal 最新官方网站上给出的云原生最新定义是:
- DevOps
- 持续交付
- 微服务
- 容器
CNCF(Cloud Native Computing Foundation,云原生计算基金会),2015 年由 Google、RedHat 等共同主导建立的一个基金会,愿景是为了推动云原生的可持续发展,围绕云原生的概念打造云原生生态体系。
不过 CNCF 最初的目的其实是为了对抗当初 Docker 公司在容器技术中一家独大的局面
最初 CNCF 对云原生定义还比较简单,有三个方面:
- 应用容器化
- 微服务架构
- 支持容器编排和容器调度
随着云原生的概念被大家逐渐认识和接受,云原生的社区和生态不断扩大,2018 年 CNCF 对云原生重新定义:
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。
这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。
云原生计算基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。
关于云原生的最新定义可以在 CNCF 官网上找到,不过没有找到有关其最新的代表技术文档。小年查阅了其他资料,几乎大多数资料对于最新云原生的代表技术是:
- 不可变基础设施
- 容器
- 服务网格
- 微服务
- 声明式API
不过在 vmware 的官网中对云原生架构的技术,多了这么几点:
- DevOps
- CI/CD
- Serverless
- 事件驱动
可见,云原生的定义一直在变化,没有一个统一的标准答案,它会随着时代的变化而变化,不同的时期有不同的定义,而且不同厂商和机构之间也有一定的差异。
而在小年看来,云原生更像是一种设计理念,一个更为抽象的宏观定义(范式)。
究其本质,但凡能够提高云上资源利用率、应用交付效率的方式和技术都是云原生。
微服务
微服务,这个大家肯定再熟悉不过了吧。现在去面试简历上不写个“精通微服务”,还真的说不过去
基本上到达一定业务规模的系统,都是采用微服务架构。举电商场景来说,大型的电商系统通常都会分成多个模块,比如会员、订单、仓储、物流等多个服务模块,各个服务模块都由不同的团队负责。
微服务的优缺点小年就不展开说了,毕竟大家懂的都懂。
但有一点小年认为比较重要的是:微服务的限界上下文。简而言之,指的是微服务负责的业务功能范畴。
可能有的同学不是非常理解这个的重要性,不过也正常,因为当你进去新公司的时候,系统架构通常都是已经拆分的微服务体系,而你的工作重点是开发和维护自己的微服务。
为什么说这一点很重要呢?因为如果在业务需求上没有分清明确业务所在的业务域,或者在一些边界问题上模棱两可的时候,那么可能就会出现不该你负责的业务被放到你的服务系统中,最终结果就会导致你的微服务模块越来越混乱。这一点小年深有体会...
其次,第二个就是微服务带来的技术挑战:
- 服务发现
- 负载均衡
- 网络通讯
- 熔断限流
- 链路追踪
- 分布式事务
当然,对于上面这些问题我们其实并不需要担心,因为已经有很多开源框架提供非常丰富可靠的解决方案,业界也已经有非常多成熟的案例和实践经验。
对于 Java 开发开发者来说,最熟悉的莫过于 Spring Cloud、Apache Dubbo,通过引入相应的 SDK 模块,加上少量代码和注解配置,即可集成各种所需的服务治理能力。
按照作者在书中对微服务阶段的划分,目前这种是属于第二代微服务架构:服务治理逻辑 SDK 化。
我们看一下服务治理 SDK 化的架构模式有哪些问题:
- 应用与 SDK 强绑定,后续如果 SDK 有特性升级或者更新等,需要修改应用代码重新部署;
- SDK 多语言支持,维护成本高;
- 语言限制性,不同的开发语言有各自特性。对一些服务治理的能力不同语言支持的性能有所不同。比如在网络通信上 C、C++ 有着明显的优势;
- 应用引入额外的依赖。SDK 的依赖与应用的某些依赖版本冲突;
这些问题可能大家平时多少都会碰到过,特别是依赖冲突的情况。
正是因为这些问题,不得不让我们重新思考。这种服务治理的能力都是通过 SDK 形式集成到应用中,但是其实这部分提供的能力是所有的微应用几乎都是相同的,我们是否可以把这部分能力抽取成通用的基础能力?
没错!其实 Kubernetes 在基础设施层面已经提供与之类似的服务治理能力。
Kubernetes | Spring Cloud | |
---|---|---|
弹性伸缩 | Autoscaling | N/A |
服务发现 | KubeDNS / CoreDNS | Spring Cloud Eureka |
配置中心 | ConfigMap / Secret | Spring Cloud Config |
服务网关 | Ingress Controller | Spring Cloud Zuul |
负载均衡 | Load Balancer | Spring Cloud Ribbon |
跟踪监控 | Metrics API / Dashboard | Spring Cloud Turbine |
降级熔断 | N/A | Spring Cloud Hystrix |
不过,为什么 Kubernetes 的出现并没有完全取代 Dubbo、Spring Cloud 呢?
尽管说 Kubernetes 从基础设施层面上提供了比较基础全面的服务治理能力,但在某些特定场景下缺乏一定的灵活性。
举个例子,比如微应用 A 调用微服务 B 的两个接口: B~1~ 和 B~2~ 。假设 B~1~ 接口调用正常,B~2~ 出现持续的 500 错误,达到阈值需要对 B~2~ 进行熔断,避免雪崩效应。如果是使用 Dubbo、Spring Cloud 应用层框架实现熔断处理是比较容易的,但是在基础设施层来处理,会直接切断 A 到 B 的网络链路,影响到 B~1~ 的调用。
简单而言,Kubernetes 在这些复杂的网络情况下,处理的粒度比较粗糙,没有框架层面那么灵活。
为了解决这个问题, Service Mesh (服务网格)便出现了。
服务网格
Service Mesh 服务网格,是微服务架构在云原生时代演进的一种架构模式,也是作者书本中所说的第三代微服务架构。目的是为了解决上一代微服务架构 SDK 服务治理模式中存在的问题,以及 Kubernetes 在基础设施层面上能力的不足。
上一代微服务架构服务治理能力是通过 SDK 集成到应用中,在这里被模块化到服务框架的微服务的独立基础能力,实现服务治理能力与应用之间的解耦。
Sidecar
Sidecar (边车) 这个概念可能大家也有听说或者了解过,Sidecar 可以说是目前服务网格较为普遍的一种模式。把服务治理的 SDK 演进成一个独立的进程,作为业务应用的代理角色。也就是说,在同一个 Pod 中,业务应用和 Sidecar 是两个独立的部署容器。
从本质上来说,Sidecar 是一个服务代理,就是在一个 Pod 中同时部署了应用服务还有一个 Proxy 服务,由 Proxy 来处理应用的网络通讯,流量控制等。
下面这个经典的架构图大家可能也看到过,绿色模块是我们的业务应用,蓝色模块就是独立进程 Sidecar,当担微服务的代理角色,负责服务发现、网络通讯,流量控制,安全认证等所有的服务治理工作。
当然,这种模式并不是服务网格所特有的,我们平时也会经常用到这种模式,比如 Pod 中除了有应用服务,可能还会跟随一个日志收集的agent、像这种也是属于 Sidecar的模式。
Istio 是一个开源服务网格,也是目前服务网格的技术实现的一个主流代表。它提供一套完整的服务治理解决方案,包括连接、保护、控制以及观测功能,通过提供完整的非侵入式的微服务治理解决方案,可以解决云原生服务的管理、网络连接以及安全管理等服务网络治理问题。
当然,Istio 是构建于 Kubernetes 之上,与云原生的有着天然的高度集成。
Istio 的架构实现分为两部分:数据平面、控制平面
- 数据平面(Data plane):由一组智能代理(Envoy,C++开发的高性能代理)组成,被部署为 Sidecar。负责协调和控制微服务之间的所有网络通信。
- 控制平面(Control plane):管理并配置代理来进行流量路由,并提供服务发现、智能路由、流量控制、安全控制等功能。
可以看到 Sidecar 的方案能够很好地解决 SDK 服务治理化的问题,实现服务治理能力与业务应用的解耦,同时也解决了 Kubernetes 在基础设施层上的灵活性问题。
至此,我们再看回微服务框架,是不是发现微服务框架就变得纯粹得多了?微应用无需再引入任何 SDK 可以更加聚焦于业务的开发,因为服务治理的功能交由 Sidecar ,甚至说不需要任何微服务框架,也不用再纠结框架技术选型用 Spring Cloud 还是 Dubbo。
当然, Sidecar 的架构模式也并不是完美,它也会存在一些问题:
- 延时问题:因为 Sidecar 是独立的进程,与 SDK 化的架构相比会存在延时,尽管延时可能会非常小,但是对网络性能极高要求的业务场景可能需要考虑一下。
- 资源占用问题:每个业务服务 Pod 都必须配备一个 Sidecar 独立进程,如果部署集群规模比较大的话,Sidecar 的资源占用问题会比较明显。
- 侵入性:Sidecar 必须通过修改 Kubernetes Pod 规约并在 Pod 内重定向流量才能“注入”到应用中。 因此,安装或升级 Sidecar 都需要重启应用 Pod,这可能会破坏当前工作负载。
- 流量熔断:流量捕获和 HTTP 处理通常由 Istio 的 Sidecar 完成,计算成本较高,可能会因 HTTP 实现不合规而破坏一些应用。
Ambient Mesh
Istio 还有一种新的模式:Ambient Mesh!
Ambient Mesh 采用了一种不同的方式,它将 Istio 的功能拆分成两个不同的层。 最底下是安全覆盖层,用于处理流量路由和零信任安全。 在此之上,用户可以在需要时启用 L7 处理机制赋予访问 Istio 完整特性的权限。 L7 处理模式要比安全覆盖层更重,仍然用作基础设施的一个环境组件,不需要对应用 Pod 进行修改。
如下图所示,ztunnel 为安全覆盖层(L4),是运行在 Kubernetes 集群节点上的一个 处理 L4 层的共享代理。Waypoint Proxy 即是处理 L7 层,它是通过 Pod 的形式部署在 Kubernetes 集群中,可以自动扩缩。
与 Sidecar 模式对比,Ambient Mesh 更像是一种中心化代理的模式。
有关 Ambient Mesh 更多细节可以看一下 Istio 官网的Doc:https://istio.io/latest/zh/blog/2022/introducing-ambient-mesh/
写在最后
本文简单记录一下云原生的整个大致的发展历程,算是比较浅显
当然,还有 Serveless 的内容也没有讲到,这部分也是挺有意思,现在有很多云厂商提供免费的 Faas,比如 Vercel、Cloudfare。有想法的话可以搞一些比较有意思的小项目,而且还是白嫖。这里先占个坑,后面有机会的话,再展开聊聊。
架构的演进与发展正是为了解决现有的问题,也正是因为问题的存在才促进架构的不断发展。
服务治理 SDK 化的架构模式目前已经有非常多成熟的方案和活跃的社区,期间也在不断的演进和完善。随着云原生架构的发展,服务网格的出现也是必然的。但不管是哪一种架构模式,都有各自的特点,没有绝对的优劣之分。
技术的浪潮一直在前行,作为技术的热爱者,我们是有必要时刻了解和关注云原生的发展。