其他
我对云原生软件架构的观察与思考
第一篇 - 云原生基础设施 (已发布,文末点击阅读原文查看) 第二篇 - 云原生软件架构(本文) 第三篇 - 云原生应用交付与运维体系(待续)
前言
控制复杂性。由于业务的复杂性,需要我们用更好的手段帮助研发组织克服认知障碍,更好的分工协作。分而治之,关注点分离等手段皆是如此。
应对不确定性。业务在快速发展,需求在不断变化。即使再完美的软件架构,然而随着时间的推移,团队的变化,软件架构的调整不可避免。读《设计模式》,《微服务设计》等书字里行间写的都是“解耦”两字,让我们关注架构中确定性和不确定性的分离,提升架构的稳定性和应变能力。
管理系统性风险。管理系统中的确定性以及不确定性风险,规避已知陷阱,对未知的风险做好准备。
缘起 - 12要素应用
构建水平伸缩的弹性应用架构,更好支撑互联网规模应用。 提升研发流程的标准化、自动化水平,提升研发效率。 减少开发环境和生产环境的差异,并使用持续交付实施敏捷开发。 提升应用的可移植性,适合云化部署,降低资源成本和管理复杂性。
松耦合架构设计
API 优先的应用架构设计
Single responsibility principle - 单一职责原则 Open/closed principle - 开放/封闭原则 Liskov substitution principle - 里氏替换原则 Interface segregation principle - 接口隔离原则 Dependency inversion principle - 依赖翻转原则
Event Driven Architecture 的崛起
分布式的松耦合架构大大增加了应用基础设施的复杂性。基于云的部署交付方式和云服务(消息队列、函数计算服务等)可以使得该架构的稳定性,性能和成本效益进一步提高。 与传统同步处理方式相比,异步事件处理存在与事件排序、幂等性、回调和异常处理相关的要求,整体设计难度更大一些。 在大多数情况下,由于缺乏跨多个系统的分布式事务支持,维护数据一致性是非常具有挑战性的。开发者可能需要权衡可用性和一致性之间的关系。比如通过Event Sourcing(事件溯源)实现最终一致性,详情: https://martinfowler.com/eaaDev/EventSourcing.html 互操作性。在现实世界中,事件无处不在,然而不同生产者对事件的描述却不尽相同。开发者希望无论事件是从哪里发出,都能够以一致的方式构建事件驱动的应用程序。CloudEvents(https://cloudevents.io/) 是一种以通用、一致的方式描述事件数据的规范,由 CNCF Severless 工作组提出,提升了事件驱动应用的可移植性。目前,阿里云 EventBridge、Azure Event Grid 等事件处理中间件,以及 Knative Eventing ,阿里云函数计算等 FaaS 技术已经提供了对 CloudEnvents 的支持。
面向交付的应用架构
应用和运行环境解耦
自包含可观测性
Logging – 日志(事件流):用于记录离散的事件,包含程序执行到某一点或某一阶段的详细信息。不但包括应用、 OS 执行过程的日志,还应包含运维过程中的日志信息,如操作审计等。 Metrics – 监控指标:通常是固定类型的时序数据,包括 Counter、Gauge、Histogram 等,是可聚合的数据。系统的监控能力是多层次的,既包含计算、存储,网络等基础设施服务层次的监控指标,也应该包含业务应用的性能监控和业务指标监控。 Tracing – 链路追踪 - 记录单个请求的完整处理流程,可以为分布式应用的开发者提供了完整的调用链路还原、调用请求量统计、应用依赖分析等能力,能够帮助开发者快速分析和诊断分布式应用架构下的性能和稳定性瓶颈。
面向失败的设计 - Design For Failure
首先是“Failures can and will happen”,我们需要提升服务器的可替换性。在业界有一个非常流行的隐喻:“Pets vs. Cattle”,宠物和家畜。我们面对一个架构选择:对于应用所在服务器我们是需要精心伺候,防止系统宕机,出现问题后不惜一切代价抢救 (Pet);还是倾向于出现问题后,可以通过简单抛弃和替代进行恢复(Cattle)。云原生架构的建议是:允许失败发生,确保每个服务器,每个组件都能够在不影响系统的情况下发生故障并且具备自愈和可替代能力。这个设计原则的基础是应用配置和持久化状态与具体运行环境的解耦。Kubernetes 的自动化运维体系让服务器的可替换性变得更加简单。
更多关于交付和运维架构的更多稳定性思考,我们会在下一篇文章中和大家分享。
应用基础设施能力下沉
服务治理能力与业务逻辑解耦
侵入性:服务治理本质是横向的系统级关注,是与业务逻辑正交的。但在现有微服务框架中,其实现方式和生命周期与业务逻辑耦合在一起的。服务治理能力的增强需要微服务框架的升级,会导致整个系统所有组件的重新构建和部署,导致升级和维护成本提升。
实现绑定:由于微服务框架代码库通常由特定语言实现,难以支持多语言(polyglot)实现。随着业务的快速发展,异构系统之间的集成逐渐成为挑战。
新一代分布式应用运行时
生命周期(Lifecycle) 网络(Networking) 状态(State) 捆绑(Binding)
最底下基础设施是各种云平台或者边缘环境。 其上是 Dapr 运行时和“building block” (构件)。Dapr 构件解耦了外部服务和服务的消费者,可以按需加载。构件以统一的 HTTP/gPRC API 为应用层提供服务访问。我们可以将外部服务从 Amazon DyanamoDB 切换为 Azure ComosDB ,上层应用无需修改任何代码。Dapr 运行时作为一个独立的 sidecar 进程,独立于应用逻辑。 应用通过轻量化的 SDK 来简化对构件 API 的调用,基于 gRPC/HTTP 开放协议可以轻松支持多语言。
Serverless 的机遇与挑战
Workflow Orchestration 工作流编排:以阿里云 Serverless 工作流为例,可以通过一个声明式的业务流程来编排任务。这种方式简化了开发和运行业务流程所需要的任务协调、状态管理以及错误处理等繁琐工作,让开发者聚焦于业务逻辑开发。
Event Choreography 事件协调:函数服务之间通过事件交换消息,由事件总线等消息中间件来进行事件的转发,并触发其他函数执行。下面是一个示例应用场景,通过 EventBridge,将订单,用户通知、商家通知、接单、结单等基于函数实现的业务逻辑串联在一起。这种方式更加灵活,系统的健壮性也更好。但是缺点是缺乏显式的建模,开发和维护相对较复杂。
应用运行时的敏捷进化
体积更小 - 对于微服务分布式架构而言,更小的体积意味着更少的下载带宽,更快的分发下载速度。
启动速度更快 - 对于传统单体应用,启动速度与运行效率相比不是一个关键的指标。原因是,这些应用重启和发布频率相对较低。然而对于需要快速迭代、水平扩展的微服务应用而言,更快的的启动速度就意味着更高的交付效率,和更加快速的回滚,以及更快的故障恢复速度。
占用资源更少 - 运行时更低的资源占用,意味着更高的部署密度和更低的计算成本。
趋势总结
更多参考:
https://martinfowler.com/architecture/ https://www.ibm.com/cloud/blog/7-missing-factors-from-12-factor-applications https://www.infoq.com/articles/microservices-design-ideals/ https://www.infoq.com/articles/architecture-trends-2020/ https://theburningmonk.com/2020/08/choreography-vs-orchestration-in-the-land-of-serverless/