在《云原生基础设施》一文中我们谈到了,云原生计算包含三个维度的内容,云原生基础设施,软件架构和交付与运维体系,本文将聚焦于软件架构层面。“Software architecture refers to the fundamental structures of a software system and the discipline of creating such structures and systems. ” - 维基百科。在我的理解,软件架构主要目标是解决下列挑战:
API 应该是被优先设计的:我们知道用户需求是复杂多变的,比如从桌面到移动端,应用的展现方式和操作流程都有可能不同;然而业务逻辑的概念模型和服务交互是相对稳定的。相对而言,API 的接口是更加稳定的,而具体的实现是可以迭代实现和持续变化的。定义良好的 API 可以更好保障应用系统的质量。
API 应该是声明式,可描述/自描述的:通过规范化的描述,API 易于沟通、易于理解、易于验证,简化开发协同。支持服务的消费者和提供者并行开发,加速开发周期。支持不同的技术栈的实现,比如对于同一个 API 接口,其服务实现采用 Java 。前端应用可以使用 javascript ,而服务器端应用可以使用 Golang 进行服务调用等等。这样可以让开发组织可以根据自己的技能栈和系统要求灵活选择合适的技术。API 应该具备 SLA :API 作为服务间的集成界面,与系统的稳定性息息相关。SLA 应该作为 API 设计的一部分,而不是部署后再考虑。在分布式系统中,稳定性风险无处不在,通过 API 优先的设计模式,我们对独立的服务进行稳定性架构设计、容量规划;我们还可以对独立的 API 进行故障注入、稳定性演练,来消除系统性的稳定性风险。
在 API 领域,最重要的趋势是标准化技术的崛起。gRPC 是 Google 开源的的高性能、通用的、平台无关的 RPC 框架。它采用分层设计,其数据交换格式基于 Protobuf (Protocol Buffers) 协议开发,具备优秀的序列化/反序列化效率,也支持众多开发语言。在传输层协议, gRPC 选择了 HTTP/2,相较于 HTTP/1.1,其传输效率有了很大提升。此外 HTTP/2 作为一个成熟的开放标准,具备丰富的安全、流控等能力,同时拥有良好的互操作性。gRPC 不仅可以用于 Server 端服务调用,也可以支持浏览器、移动 App 和 IoT 设备与后端服务的交互。gRPC 在功能上已经具备完整的 RPC 能力,也提供了扩展机制来支持新的功能。
https://www.alluxio.io/blog/moving-from-apache-thrift-to-grpc-a-perspective-from-alluxio/此外在 API 领域 Swagger (OpenAPI规范),GraphQL 都是大家值得关注的开放标准。大家根据自己的业务诉求灵活选用,本文不再赘述。
Event Driven Architecture 的崛起
谈事件驱动架构 (EDA - Event Driven Architecture),我们首先来解释一下什么是事件。事件是指对已经发生的事情、状态变化等的记录。它们是不可变的(无法更改或删除),并且按其创建顺序排序。相关各方可以通过订阅已发布的事件来获取有关这些状态变化的通知,然后使用所选择的业务逻辑根据这些信息采取操作。事件驱动架构是一种构建松耦合的微服务系统的架构方式,微服务之间通过异步事件通信来进行交互。事件驱动架构实现了事件的生产者和消费者的彻底解耦。生产者无需关注事件如何被消费,同时消费者无需关注事件的生产方式;我们可以动态添加更多消费者而不影响生产者,可以增加消息中间件对事件进行动态路由和转换。这还意味着事件的生产者和消费者没有时序上的依赖,即使由于应用宕机无法及时处理消息,在重新恢复后,程序可以继续从消息队列中获取这些事件继续执行。这样的松耦合架构,为软件架构提供更高的敏捷性、灵活性和健壮性。事件驱动架构的另一个重要优点是提升了系统的可伸缩性。事件生产者在等待事件消费时不会被阻塞,并且可以采用 Pub/Sub 方式,让多个消费者并行处理事件。事件驱动架构还可以完美地与 Function as a Service (FaaS) 相整合。事件触发函数执行业务逻辑,在函数中也可以编写集成多个服务的“胶水代码”,简单、高效地构建事件驱动架构的应用。但是 EDA 架构依然存在很多挑战。
根据”墨菲定律“ — “Anything that can go wrong will go wrong”。分布式系统可能受到硬件、软件等因素、或者内部和外部的人为破坏。云计算比自建数据中心提供了更高SLA、更加安全的基础设施,但是我们在应用架构设计时依然要时刻关注系统的可用性,关注潜在的”黑天鹅“风险。
熟悉传统企业架构的同学可能发现,传统的 Java EE (现在改名为 Jakarta EE )应用服务器的目标也是解决类似的问题。一个典型 Java EE 应用服务器的架构如下图所示:应用生命周期由各种应用容器管理,如 Web 容器,EJB 容器等。应用的安全管理、事务管理、连接池管理都是交给应用服务器完成。应用可以通过 JDBC 、JMS 等标准 API 接口访问外部的企业中间件,如数据库、消息队列等。不同的外部中间件通过 Java Connector Architecture 规范实现与应用服务器的插拔。应用通过 JNDI 在运行时实现与具体资源的动态绑定。Java EE 将系统的 cross-cutting concern下沉到应用服务器来解决,让开发者只关注应用的业务逻辑,开发效率有了较好的提升;同时减轻应用对环境和中间件实现的依赖,比如可以在开发环境中用 ActiveMQ ,在生产环境中使用 IBM MQ 替换,而无需修改应用逻辑。在架构上,Java EE 是一个大的单体应用平台,拖慢了自身架构迭代的速度,跟不上时代的变化。由于Java EE过于复杂、沉重,在微服务兴起之后已经被大多数开发者所遗忘。
Serverless 具备很多优势, 比如:降低运维成本,提升系统安全性,提升研发效率,加速业务交付等等。然而 Serverless 还有一些不能回避的问题需要我们来做判断:成本管理: 对于“Pay as you go”的收费模式的一个弱点是无法准确预测具体会产生多少费用,这于许多组织预算管理的方式不同。厂商锁定: 即使 Serverless 应用基于开放的语言和框架,但是多数Serverless应用还依赖一些非标准化的 BaaS(Backend as a Service)服务,如对象储存,Key- Value 数据库,认证,日志,监控等。调试和监控: 与传统应用开发相比, Serverless 应用的调试与监控工具能力还不完善。良好的可观测性是将 serverless 计算的重要助力。架构复杂性:Serverless 开发者无需关注底层基础设施的复杂性,但是应用架构的复杂性需要格外关注。事件驱动架构和细粒度函数微服务,与传统开发模式非常不同。大家需要根据业务需求和自己的技术能力,在合适的场景应用,然后逐渐扩大应用范围。
关于典型的 Serverless 应用架构,大家可以参考 What a typical 100% Serverless Architecture looks like in AWS ! : https://medium.com/serverless-transformation/what-a-typical-100-serverless-architecture-looks-like-in-aws-40f252cd0ecb
Cloud Programming Simplified: A Berkeley View on Serverless Computing: https://www2.eecs.berkeley.edu/Pubs/TechRpts/2019/EECS-2019-3.pdf 也是深入了解 Serverless 计算的一个好的参考。正因为此,Golang、Node.js、Python 等语言开发者在持续攀升,有几个值得大家关注的技术:在 Java 领域,GraalVM (https://www.graalvm.org/)已经逐渐成熟。它是基于HotSpot上增强的一个跨语言的全栈虚拟机,支持众多语言的运行平台(包括Java、Scala、Groovy、Kotlin、JavaScript、Ruby、Python、C、C++等)。GraalVM允许您将程序提前编译为本地可执行文件。与经典Java VM相比,生成的程序具有更快的启动时间和更低的运行时内存开销。Quarkus(https://quarkus.io/)/Micronaut(https://micronaut.io/) 等作为云原生定制的新一代Java框架,可以实现惊艳的启动时间和资源开销。更多分析可以参考Java的云原生进化。WebAssembly 则是另外一个令人激动的技术。WebAssembly 作为一个面向现代 CPU 体系架构设计的,安全的、可移植、高效率的虚拟机沙箱,可以在任何地方(服务器、浏览器、IoT等等)、任何平台(不同操作系统,不同CPU体系架构下)安全运行应用。WebAssembly System Interface(WASI)是来标准化 WebAssembly 应用与系统资源的交互抽象,比如文件系统访问,内存管理,网络连接等,提供类似 POSIX 这样的标准 API 。平台开发商可以针对具体的操作系统和运行环境提供 WASI 接口不同的实现,可以在不同设备和操作系统上运行跨平台的 WebAssembly 应用。这可以让应用执行与具体平台环境实现解耦,使得应用“Build Once, Run Anywhere”的理想逐渐形成现实。虽然目前 WebAssembly 已经超越了浏览器的领域,但是其发展还在非常初期,期待社区共同推动。有兴趣的同学可以看看 WebAssembly 与 Kubernetes 双剑合璧: