Serverless时代的微服务开发指南:华为云提出七大实践新标准
历川:华为云 Serverless 研发专家
丙真:华为云中间件 Serverless 产品经理
冯嘉:华为云中间件首席专家
分散治理、数据去中心化、基础设施自动化等优秀设计原则,使得微服务架构在过去几年中逐渐发展为企业应用架构的首选。然而,随着应用规模的持续增长和微服务生态的成熟,新的挑战也在不断涌现出来。相比于传统 SOA 等架构, 微服务架构给予开发者更多设计和开发 “自由度”,同一应用的各微服务模块,可以采用不同的技术栈来实现独立自治的业务逻辑。但自由也相应增加了开发运维的复杂度,提高了软件开发者的认知成本;同时,微服务架构在业务资源开销、交付速度、扩展性能和基础设施弹性等方面,也面临一系列新的挑战。
Serverless 编程范式的兴起,允许开发者聚焦业务逻辑本身,无需再感知底层运行时细节和后端资源的维护伸缩等问题,给微服务应用开发提供了效率更高的选择。本文结合华为云函数工作流 FunctionGraph、事件网格 EventGrid 以及云应用引擎 CAE 等在 Serverless Microservice 方面的实践,总结提炼出包括基础设施无感知、全生命周期可观测、 状态管理自动化等在内的七大 Serverless Microservice 开发 “实践标准”,为加速全域 Serverless 产业升级、推动企业应用开发框架从微服务向 Serverless 演进提供一些思考。
图 1. 微服务应用开发的生命周期示意
如图 1 所示,在微服务架构中,应用程序由一组功能自治的小型化服务围绕业务能力构建,服务之间采用轻量级通信,可以独立开发、构建、测试、发布和监控。微服务的目的是有效拆分应用,实现敏捷开发和部署 [1]。Martin Fowler 和 James Lewis 在《Microservices: A Definition of This New Architectural Term》中,列举了微服务架构的九大特征,如表 1 所示 (参见 [2]),这些特征使得微服务相比于传统软件开发架构,具有更加灵活的设计开发模式,服务之间支持独立部署和扩展,有效提升了企业应用的开发、迭代和运维效率。
表 1:微服务架构的九大特征
尽管微服务架构秉承众多优秀设计原则,随着应用规模增长、技术生态的成熟和工具链的多元化发展,一系列新的挑战逐渐呈现在企业应用开发者面前。
相比于单体(Monolithic)或 SOA(Service-Oriented Architecture)等传统架构下的 “规范标准”,微服务更提倡基于 “实践标准” 解决分布式问题 [2];因此,对于服务注册发现、负载均衡、配置和安全、事务处理等,在微服务场景中不再有统一的解决方案。例如,服务间通信方案就有数十种,包括 REST、gRPC、Thrift、Dubbo 等,服务发现也包含 CoreDNS、Eureka、ZooKeeper、ETCD 等多种技术选型 ; 应用开发人员从这些各有千秋的技术中,选择最适合自己业务场景的系统性方案,无疑是一件门槛很高的任务 ; 尽管有 Spring Cloud 等一站式的全家桶工具集,对应用设计和运维人员来说,一揽子工具集所提供的技术组合复杂多样,导致问题定位、定界效率低。
除 Spring Cloud,Kubernetes 也逐渐成为一种主流的微服务解决方案。与 Spring Cloud 相比,Kubernetes 的配置管理和服务注册功能更加友好,且“边车代理模式”、服务网格 (e.g., Istio) 等技术的提出,显著提高了服务治理的效率;但要实现这类解决方案的高效利用,开发者的认知成本和所面对的复杂性并不低;从 Spring Cloud 到 Kubernetes,复杂性没有被减弱,更多地是被转移。微服务架构也需要开发者掌握并发编程框架和分布式事务一致性等技术,这些技术本身具备不低的复杂性,以事务一致性为例,常见机制就包括 TCC (Try-Confirm-Cancel)、2/3PC (2/3 Phase Commit)、SAGA 等模式。
尽管微服务提倡对应用进行拆分,但微服务的粒度仍然比较大。同一个微服务单元中,不同子功能之间的使用频率(e.g., QPS、RPS et al.)、变更频率等往往也不相同,因而对扩展性的诉求也不一样。图 2 展示了一个 Web 应用中“用户管理”微服务的例子 [3],该微服务包含账号注册 API、登录 API 和登出 API 三项子功能,在实际使用中,注册 API 和登录 API 的调用频率通常远高于登出 API,因此对扩展性的要求也高于后者;此时虽然可以对微服务进一步进行拆分,但整个应用的服务数量也可能会随之翻倍,从而加重应用基础设施的管理负担。
图 2. 一个 Web 应用中“用户管理”微服务的示例
微服务粒度较大的问题也使得单个服务的扩容速度十分受限,在高并发场景下要实现微服务的快速弹性是一件十分困难的事;对于时延敏感型应用,并发请求的扩容诉求通常在秒级以内,甚至毫秒级,但在微服务架构下,服务弹性扩容则通常需要秒级以上甚至分钟级的时延。
与服务扩展效率和应用规模平衡相关的另一个难题是成本问题。受限于单个服务的弹性能力,微服务架构通常采用“多实例主备”或“多实例多活”的方案,来保障应用的高可用性,实现容错、容灾、负载均衡等目标。但与前文中讨论的相似,同一个微服务应用的不同子服务之间,其承载的流量大小、调用频率等的差距也可能很大,因此对资源的横向、纵向扩缩容诉求也不一致,这种差距往往给企业带来无畏的成本浪费。图 3 展示了一个由 6 个功能不可或缺的子服务构建而成的微服务应用, 每个服务运行在虚机或容器中,图中实线表示在给定的一段时间内企业为每个服务所占据的虚机或容器所支付的资源成本,虚线表示服务在业务运行中所实际消耗的资源成本。
图 3. 一个微服务应用的资源成本示意
在图 3 的示例中,微服务 F 由于被调用的频率很高,其所占据的资源利用率也较高,而微服务 A 则相反,其所占据的资源成本和 F 相差不大(e.g., 2u2G 的容器),但 A 被调用的频率则相对低很多,资源利用率也相应更低。在实际应用开发运维中,为保障高可用性和资源弹性,图中实线与虚线之间通常存在较大的差距,这部分成本是企业为应用所占据但未使用的资源付出的成本,属于一种成本浪费;同时,由于微服务架构通常不支持(一般也不建议)单个服务 “Scale-to-Zero”,且微服务应用逐渐变得越来越 “重”,上述 “资源占而不用” 导致的浪费现象也更加严重。
云原生基础设施的发展,有力促进了事件驱动的 Serverless 架构的广泛应用。相比于微服务,Serverless 提供了一种更加细粒度的应用开发模型,以及更加便捷、轻量的应用运维框架。以 FaaS(Function-as-a-Service)为例,应用开发支持以单个函数作为最小部署单元,开发者只需提供函数代码(包括源码文件、镜像等)和一些配置信息,即可实现应用的快速发布和上线;同时,后端资源的维护及其随流量的自适应伸缩等复杂任务,则全部被下移到 Serverless 平台侧,显著降低了开发者的认知成本和开发、运维门槛,如图 4 所示;开发者只需为应用函数所实际使用的资源时长进行付费,付费粒度精确到毫秒级;同时,在应用流量负载为零的所有时间区间中,函数实例通过“Scale-to-zero”可以有效消除成本浪费,实现应用开发经济化。
图 4. Serverless 应用开发架构的资源边界示意
与在微服务场景下相似,事件驱动式(Event-driven)也是 Serverless 函数架构的核心特征。Serverless 函数一般由函数代码包和事件处理程序(event handler)构成,函数通过事件进行触发,并对接收到的事件进行响应、处理。例如,FunctionGraph 支持多种类型的事件触发器,满足应用在不同业务场景下的诉求;同时,通过原生集成事件网格服务 EventGrid,FunctionGraph 为各类云服务、自定义应用、SaaS 应用提供了标准化、中心化的接入方式,事件可以在不同应用和服务之间灵活路由,帮助开发者快速构建松耦合、分布式的事件驱动式 Serverless 应用,如图 5 所示。
图 5. EFG:基于 EventGrid 和 FunctionGraph 的事件驱动式 Serverless 应用模型
图 6 给出了基于 FunctionGraph 和 APIG(API Gateway)的 Serverless Microservice 简易应用模型,整个应用采用云上托管服务(managed services)构建,每个微服务由函数实现,并通过 APIG 对外暴露,函数之间采用 Workflow 进行功能编排。在该模型基础上,我们用函数快速实现一个 Serverless Microservice 示例。
图 6. 基于 FunctionGraph 和 APIG 的 Serverless Microservice 模型
以经典的电商应用为例,首先用 FunctionGraph 创建三个函数,分别实现 Product, Basket, Order 微服务,其中,Product 实现商品清单及详情浏览,Basket 负责加购,Order 完成下单。交易相关的状态采用分布式缓存服务 DCS(Distributed Cache Service)进行存储,DCS 实例通过绑定独立 VPC 来实现网络私有和隔离,最后,我们为每个函数分别绑定一个 APIG 触发器,对外暴露服务;如图 7(1) - 7(5) 所示。
图 7-(1). 分别创建三个函数,实现微服务功能
图 7-(2). 授权 FunctionGraph 访问 VPC 内服务 (i.e., DCS 实例)
图 7-(3). 开启函数访问 VPC
图 7-(4). 在函数中获取对应环境变量
图 7-(5). 最后为每个函数绑定 APIG 触发器
我们用 APIPost 进行简单测试并返回函数界面查看监控信息,如图 8(1) – (3) 所示:
图 8-(1). 用 APIPost 测试函数微服务
图 8-(2). 查看日志监控
图 8-(3). 查看并发数等监控信息
最后,我们通过 EventGrid 进行异步事件解耦,并采用分布式消息服务 DMS(Distributed Message Service)实现基于 Fan Out/Fan In 的批处理,如图 9 所示:
图 9. 一个基于事件驱动的 Serverless 函数架构的电商应用示例
其中,EventGrid 创建事件订阅时,事件源选择 DCS 实例,事件目标选择 FunctionGraph 函数,如图 10 所示:
图 10. 创建 EventGrid 事件订阅
在基于事件驱动式 Serverless 函数架构开发应用的过程中,遵循一定的设计 / 开发原则或“实践标准”,有利于开发者构建更加高效、经济和稳健的企业应用。本文结合华为云 FunctionGraph、EventGrid 以及 CAE 等云服务在 Serverless 领域的最佳实践,总结并提炼出 Serverless microservice 应用开发的七类实践标准,为开发者的架构决策提供参考;如表 2 所示。
表 2. 云上 Serverless Microservice 应用开发的实践标准探索
基础设施无感知(Infra-less):基础设施无感知帮助开发者更快、更高效地构建应用程序,并显著降低应用运维的成本和复杂性。除服务器无感知外,基础设施无感知具有更广泛的含义。包括开发者对平台底层操作系统、分布式运行时以及硬件的有限制访问,开发者无需感知 FunctionGraph 平台是如何架构的,其它云服务与 FunctionGraph 的集成由华为云统一管理,只公开少量配置选项给开发者,开发者也无需感知函数在任何时间点被调用时实例资源位于哪个可用区(Available Zone, AZ),等等;这种抽象允许开发者专注于应用程序本身的功能开发、数据流设计和业务逻辑优化,从而更聚焦地为应用的终端用户提供价值。
全生命周期可观测(Deep Observability):基础设施无感知在提供便捷性的同时,也在开发者的“心智模型”方面降低了透明性,因此,全生命周期、深度、实例级的可观测性,对于开发者实现对应用的自主掌控具有关键作用。Serverless 可观测性包含链路追踪,日志,和指标三类,主要服务于异常监控、性能调测、故障定位、问题定界等。例如,FunctionGraph 通过内置对接云日志服务 LTS,为应用函数提供日志监控能力,包括高级日志分析能力(e.g., loginsight)等;通过对接应用性能管理服务 APM,提供指标丰富的函数实例级监控;同时,支持全链路调用链管理等。开发者无需复杂的配置,即可享受应用函数全生命周期的深度可观测性能力。
流式编排(Flow Orchestration):编排是 Serverless 的核心概念之一,狭义的编排主要指工作流编排,如 FunctionGraph Workflow,在 Serverless microservice 应用开发中,开发者应尽量避免在单个函数中定制化地开发应用的各类分支逻辑及其异常处理程序,应尽可能采用函数工作流编排来实现,工作流编排提供了一种更加便捷的分支路由、错误捕获以及异常处理方法,能够增强应用逻辑的稳健性并提高全链路可观测性 [4]。广义的编排还包括服务流编排(Service Flow),应用架构所依赖的三方功能,如网关、消息、缓存等,也应尽可能采用云上托管服务,通过配置驱动、服务流编排的方式进行组装式构建,从而尽可能减少定制化代码的开发和维护,降低应用运维的负担。FunctionGraph 原生支持开发者集成云上其它服务,表 3 列出了在 Serverless microservice 开发中最常用的几类云服务。
表 3:Serverless microservice 应用程序开发中常用的几类云服务
事件驱动(Event-driven):事件,表示状态的变化。采用事件驱动的方式构建应用的优点在于松耦合、独立扩缩容、良好的扩展性等。在状态查询、数据存取、函数调用等场景中,优先采用事件来代替传统应用开发中常用的轮询、Webhook 等机制,可以有效降低应用的复杂性、提高系统性能、或降低应用成本 [5]。以轮询为例,由于系统状态的更新在时间维度上不一定是规律且连续的,使得轮询类策略往往是低效或非经济的;Webhook 机制则在被集成的服务之间不一定能够得到广泛的支持。同时,轮询和 webhook 机制在支持应用按需扩缩容方面也存在较大挑战。采用事件驱动模式,开发者既可以很方便地构建实时系统,实现数据按需流动并避免过量的批处理任务;也可以通过将事件发布到 DMS 等消息服务,利用弹性缓冲区实现异步解耦,然后利用 EventGrid 对事件进行过滤和路由,从而增强应用在流量激变情形下的可伸缩性。
交互式控制(Interactive Autopilot):交互式控制主要解决如何通过广义的自动驾驶技术(autopilot)[7] 实现应用迭代和生产的高性能、低成本;对于 Serverless 函数而言,自动驾驶主要包括函数代码包瘦身、源码优化、资源规格选择、并发度调优等问题。以函数资源规格选择为例,过去主要依赖于开发者的工程经验和其对自身业务场景的理解进行设定,但经验性配置往往具有误差大、静态性、黑盒化等缺点;因此,FunctionGraph 提出在线式资源消耗感知与规格动态推荐等 autopilot 技术,配合离线式最佳规格调优(power tuning),最大限度帮助用户实现应用函数 FinOps 效果,让开发者能够真正享受到 Economical Serverless 的福利 [8];开发者无需感知应用自动驾驶技术的实现细节,但整个过程 “处处可观察、 实时可干预”。
状态管理自动化(Automatic State Management):尽管 Serverless 提倡无状态优先,但在多数分布式应用中,状态管理是无法回避且复杂度很高的任务。随着数据密集型应用逐渐成为云上应用的主流,如大规模机器学习、大数据与流处理、实时交互型应用、多人协作类应用等,Serverless 编程框架对支持有状态的诉求越来越强烈。FunctionGraph 作为业界首个支持有状态的 Serverless 平台,为开发者提供多种状态一致性模型和自动化的并发处理机制,开发者通常只需要对函数中的简单结构体进行操作,即可实现状态数据的快速存取,整个状态管理过程由平台内置提供,无需与外部存储服务之间进行频繁交互,显著减少了涉及大量状态数据操作的网络访问次数,具有自动化、高性能、高可用等特点。
伸缩原子轻量化(Lightweight Scaling Unit):伸缩原子,指最小可伸缩的运行单元,如单个函数。在 Serverless microservice 应用开发中,函数应尽可能小型化,功能上保持逻辑内聚,以响应外部事件为主,对应用全局逻辑弱感知;伸缩原子的轻量化,不仅能够支持快速的独立扩缩容以及高并发下的快速弹性能力,也能够最大限度地保证应用的各个微服务函数能够“按需扩缩容”,从而在保障应用负载 QoS 的前提下,实现极致成本。
以事件驱动式函数架构为代表的 Serverless 编程模型,正在成为微服务应用开发的新一代标准框架。本文结合华为云 FunctionGraph 和 EventGrid 等在 Serverless 微服务方面的最佳实践,总结并提炼出七大 Serverless Microservice 实践标准, 为推动全域 Serverless 产业升级提供一些思考。
更进一步地,华为云事件网格服务 EventGrid 将于近期正式转商用,并联合 FunctionGraph 推出事件驱动式函数应用开发模型 EFG(EventGrid-FunctionGraph); 同时,基于七大实践标准并结合丰富的客户实践,EFG 将推出 Serverless Microservice 参考架构,为开发者构建事件驱动式 Serverless 解决方案提供可视化的架构抽象和优秀的业务建模支持。
参考资料
[1] Introduction to Microservices. https://www.nginx.com/blog/introduction-to-microservices/
[2] 周志明,《凤凰架构:构筑可靠的大型分布式系统》
[3] 刘方明, 李林峰, 王磊, 《华为 Serverless 核心技术与实践》.
[4] Understanding event-driven architecture – Part 1https://aws.amazon.com/blogs/compute/operating-lambda-design-principles-in-event-driven-architectures-part-2/
[5] Design principles in event-driven architectures – Part 2https://aws.amazon.com/cn/blogs/compute/operating-lambda-design-principles-in-event-driven-architectures-part-2/
[6] Anti-patterns in event-driven architectureshttps://aws.amazon.com/cn/blogs/compute/operating-lambda-anti-patterns-in-event-driven-architectures-part-3/
[7] Rzadca, K., Findeisen, P., Swiderski, J., Zych, P., Broniek, P., Kusmierek, J., ... & Wilkes, J. (2020, April). Autopilot: workload autoscaling at google. In Proceedings of the Fifteenth European Conference on Computer Systems (pp. 1-16).
[8] 历川, 平山, 冯嘉, Serverless 遇到 FinOps: Economical Serverless,https://www.infoq.cn/article/ckibtiofxn4whycfjt8b
反Twitter平台用户激增250万,这名29岁程序员如何凭一己之力扛住超8倍流量增长?
张勇、刘强东、马化腾接连“发飙”,痛批内部问题;头条抖音飞书开始优化,部分员工零赔偿;推特自马斯克接管以来首次大范围宕机|Q资讯
微信扫码关注该文公众号作者