1.3 云原生与世界和平
我在这个行业中已经工作很长时间了,也看到有几次技术进步声称要解决“所有”问题。例如,20世纪80年代后期出现面向对象编程时,有些人认为软件会自己编写代码。尽管这些乐观的预测都没有成真,但毫无疑问,许多大肆宣传的技术提升了软件的许多方面,例如易于构建和管理、更好的健壮性等。
云原生软件架构通常被称为微服务[8],目前已经变得非常流行(虽然它们不会维护世界和平)。即使它真的能占据软件开发的主导地位(我相信会的),它也不是万能的。让我们稍后更详细地来讨论这个问题,现在先讨论一下“云”(Cloud)这个词。
1.3.1 云和云原生
“云”这个词可能会给人带来困惑。当我听到一个公司的老板说“我们正在向云迁移”时,他通常是指正在将一些甚至所有应用程序转移到其他的数据中心,例如AWS、Azure或者GCP。这些云提供了与本地数据中心(机器、存储和网络)相同的功能,因此这种“向云迁移”只需对当前软件和运维方式进行少许的变更。
但是这种方法不会带来更好的软件弹性、更好的管理方式,或者更多的敏捷性。事实上,由于云服务的SLA(Service Level Agreement,服务级别协议)通常低于本地数据中心的SLA,所以在许多方面可能会出现降级。简而言之,迁移到云上并不意味着你的软件就是云原生的,也不会具有云原生软件的价值。
正如我在本章前面所分析的,消费者的新期望和新的计算环境(即云计算环境)迫使软件的构建方式发生了变化。当你拥抱新的架构模式和运维实践时,所开发的软件就会非常适合于在云环境中工作,如同天生源自于此。
注意 “云”是指我们在哪里计算,而“云原生”指的是如何实现。
如果云原生是关于如何实现的,那么是否意味着你可以在当前环境下实现云原生的解决方案呢?你说对了,我合作过的大多数企业都是先在自己的数据中心实现云原生架构。这意味着其内部的基础设施需要支持云原生的软件和运维方式。我将在第3章来讨论这种基础设施。
尽管云原生很棒(我希望当你读完这本书的时候,你也会这么想),但是它并不意味着一切。
1.3.2 什么不是云原生
我相信你应该可以理解,不是所有的软件都应该是云原生的。当你学习这些模式时,会发现有些新方法很有用,而有些则不那么有用。如果软件所依赖的服务总是位于一个固定的位置,并且从来不发生改变,那么就不需要实现一个服务发现协议。有些方法在带来好处的同时,也会产生新的问题,比如调试多个分布式组件中的程序逻辑就可能很困难。下面将介绍三个最常见的不适合使用云原生架构的原因。
首先,有的时候,软件和计算基础设施不需要云计算。例如,如果软件不是分布式的,并且很少出现变化,那么完全不用做到像大规模运行的Web或移动应用一样的稳定性。例如,嵌入到越来越多的物理设备(例如洗衣机)中的代码,甚至可能没有计算和存储资源来支持对现代架构很关键的冗余机制。我的象印电饭煲中的软件,可以根据主板上的传感器的报告来调整烹饪的时长和温度,它不需要能在不同处理器上运行的软件。如果这种软件或者硬件的某个部分出现了故障,最糟糕的结果就是食材被浪费了,而我只需要叫个外卖而已。
其次,有时云原生软件的特点并不适合解决面临的问题。例如,许多新的模式为系统提供了最终一致性,于是在分布式软件中,系统中的某个部分更新的数据可能不会立即反映到系统的其他部分。最终所有数据都将变成一致,但是这个过程可能需要几秒甚至几分钟才能完成。有时这种情况是可以接受的,例如,由于网络故障,你正在查看的影片评论信息区并不能立即反映出另一个用户刚提交的五星评级,这不是什么大问题。但有时此情况是不能接受的,例如,储户在银行的一家分行提取了所有资金并注销了账户,但是随后又从ATM机上提取出额外的资金,这是银行系统所不能允许的。最终一致性是许多云原生模式的核心,这意味着当我们需要强一致性时,就不能使用这些新模式了。
最后,有时虽然你现有的软件不是云原生的,但是重写它也没有什么价值。信不信由你,大多数有几十年历史的企业,都有一部分IT资产运行在大型机上,而且可能会继续在大型机上运行几十年。但这不仅仅是大型机的问题,许多软件运行在大量现有的IT基础设施上,这些基础设施都基于比云更早的架构设计。只有当重写代码具有足够的商业价值时,你才应该那样做,但是即使有价值,你也需要对这些工作排列优先级,通过几年的时间来逐渐更新各种产品。
1.3.3 云原生的价值
这不是一个非此即彼的情况。大多数开发者都是基于多个现有解决方案进行软件开发的。即使是在开发一个新的软件,可能也需要与那些现有的系统进行对接,而且已运行的软件几乎都不是云原生的。云原生的绝妙之处在于它最终是由许多不同的组件组成的,即使其中一些组件的模式不是最新的,云原生的组件仍然可以与它们进行交互。
即使你的软件使用了旧的设计模式,应用云原生模式依然可以带来立竿见影的价值。例如,图1.12中包含了几个应用程序的组件。一名银行柜员可以通过用户界面访问用户的账户信息,然后调用在大型机上运行的应用程序的API接口。在这种简单的部署拓扑中,如果账户API服务和大型机应用程序之间的网络连接中断了,客户将无法进行提现。
图1.12 在没有访问记录源的情况下发放资金是不允许的
但是,现在让我们将一些云原生模式应用到这个系统中。例如,如果你在多个可用区中为每个微服务部署多个实例,通过同一个区域中的网络,其他可用区中的服务实例仍然可以访问大型机上的数据(如图1.13所示)。
图1.13 通过使用一些云原生模式,例如冗余和适当的分布式部署,对非云原生的软件很有帮助
同样值得注意的是,当你希望重构遗留代码时,不需要一下子完成所有重构工作。例如,为了向云迁移,Netflix将其面向客户的整个数字解决方案重构为云原生架构。这项工作最终历时7年,但在此过程中,Netflix首先对部分单体的客户端-服务端系统进行了重构,并获得了立竿见影的效果。[9]通过之前的银行示例,我们得到的经验是,在向云迁移的过程中,即使只有一部分解决方案是云原生的,也是有价值的。
无论你是打算通过新的模式在云环境中创建一个新的应用程序,还是打算从一个已有的单体程序中提取和重构出一个云原生的部分,都会从中受益。在21世纪10年代早期,尽管那时我们还没有使用“云原生”这个术语,但业界已经开始试验以微服务为中心的架构,几年间,许多模式都得到了改进。这种“新”趋势很容易被理解,也得到越来越广泛的传播。我们已经看到了这些方法所带来的价值。
我相信这种架构风格会在未来的一二十年里占据主导地位,它与其他容易消失的架构风格的不同之处在于,它是计算基础设施从根本上演变的结果。过去二三十年中占据主导地位的客户端-服务端模型,首次出现是在计算基础设施从大型机转移到众多小型计算机的时候,因此需要我们开发各种软件来适应那种计算环境。云原生架构也经历了类似的过程,并且逐渐成为一种新的计算基础设施,即提供高度分布式且不断变化的软件定义计算、存储和网络抽象。