云服务应用架构指南之架构风格

云服务正在改变服务应用的设计方式,与传统单体架构不同的是,现在的云服务应用正被分解为更小、更加去中心化的模式。这些服务通过API或者异步信息或者时间来通信。应用通过按需增加实例的方式来进行水平扩展。

这些变化带来了新的挑战。应用状态变成了分布式,运维操作也变成了并行且异步的。整个系统对待错误发生需要保持弹性,部署必须是自动化并且可以预测的。监控和检测对于获取系统内部信息至关重要。

传统 VS 现代

传统 现代
单体、中心化 解构、去中心化
按照预定的伸缩性(可扩展固定数量)做设计 为弹性伸缩设计
关系数据库 多种持久化技术混用
强一致性 最终一致性
串行、同步处理模式 并行、异步处理模式
为避免出错设计 为错误、故障而设计
偶尔大更新 频繁小更新
手动管理 自动自我管理
雪花服务器 统一的基础架构

[TOC]

架构指南

限制带来了新的挑战,所以明白权衡取舍的原则很重要。以下几个取舍的原则

  • 复杂度:对于你接下来要开发的领域,这个架构是不是过于简单或者过于繁琐
  • 异步消息和最终一致性:异步消息虽然可以解耦服务,增加弹性和扩展性(消息是可以重试的),但也带来了最终一致性的问题
  • 内部服务通信:虽然通过分离服务来解耦了,但是不同服务间的通信增加了无法容忍的延时风险和网络拥塞。
  • 管理性:它可能带来了管理、监控、发布更新等新的挑战

N-tier 架构风格

原则

  • 分层可以把职责和依赖管理分离,每一层有它独有的责任,高层可以使用底层的服务,但反之则不行
  • 一个N-tier应用可以有closed和open两种不同风格的分层模式
    • closed:每一层只能向下访问直接毗邻的层
    • open:每一层可以访问所有在其下面的层

优势、挑战和何时选用

  • 何时选用:当开发比较简单的Web应用或者进行本地部署到云端部署的迁移时,N层架构都是合适的
  • 优势
    • 移植性比较强
    • 比较缓的学习曲线
    • 非常自然的对传统应用模型的变更
    • 对多种多样环境有很好的适应性
  • 挑战:
    • 很容易形成做事简单但并没有什么价值的中间层服务
    • 单体的设计会阻止独立部署
    • 在大系统中很难管理网络安全问题

最佳实践

  • 在负载上使用自动伸缩
  • 使用异步消息来解耦层次
  • 缓存半静态数据
  • DB做高可用设计
  • 部署防火墙在前端和互联网之间
  • 把每一层部署不同的子网中,使用子网做网络边界
  • 限制各层次直接访问数据层,只允许来自中间层的请求

Web-Queue-Worker

原则

  • 核心是Web Front End 负责处理客户端请求,Worker负责处理一些资源敏感性、长时间处理的业务或者批处理任务。Web Front与Worker通过消息队列通信
  • Web Front和Worker都是无状态的,Session的状态被存在在分布式的缓存中

优势、挑战和何时选用

  • 何时选用:长时间运行的任务或者批处理操作
  • 优势:
    • 相对简单的架构
    • 部署和管理都比较简单
    • 关注点分离比较清晰
    • 使用异步信息解耦front end 和worker
    • front和worker可以独立扩展
  • 挑战:
    • 如果不小心设计,front和worker可能会变成庞大的单体组件然后难以维护和更新
    • front和worker当需要分享数据类型或者代码时,它们之间可能存在隐藏的依赖关系,

最佳实践

  • 选择用最合适的持久化机制,包括缓存
  • 如果应用的负载可以预测,那么使用预先规划的自动伸缩策略,否则就使用基于度量指标的自动伸缩策略

Microservice

原则

  • 微服务架构中,服务实例都是小、独立、关系松散的
  • 每一个服务有独立的代码仓库,并且独立部署,一个团队可以仅更新部分服务而不需要重新构建部署整个完整的应用
  • 服务只需要持久化自己的数据或者程序状态,这与传统的有一个统一的层来负责持久化不同
  • 常见于微服务中的技术架构
    • Management
    • ServiceDiscovery
    • API Gateway

优势、挑战和何时选用

  • 何时选用: 大应用但是又有急切的发布频率、需要高度扩展的复杂应用、非常复杂的业务领域
  • 优势:
    • 独立的部署和开发方式
    • 错误隔离
    • 可以混合技术栈
    • 可以独立的伸缩服务数量
  • 挑战:
    • 复杂度会急剧上升
    • 缺乏管理,去中心化导致服务分散
    • 网络拥塞和延迟
    • 每个服务负责自己数据的持久化,因此数据一致性可能是一个挑战。尽可能保证最终一致性。
    • 更新服务可能会导致服务不可用, 如果不精心设计,可能会导致兼容性问题
    • 微服务是高度的分布式系统,需要评估团队是否有经验能力完成开发

最佳实践

  • 将一些通用问题比如身份认证和SSL终止交给gateway
  • 服务通信应该通过设计良好的API,避免泄露实现细节,API应该抽象的是业务模型,而非服务内部实现细节
  • 避免服务间的耦合,耦合情况包括共享数据库、刚性通信协议
  • 服务间应该具有低耦合、高内聚的特性,需要一起变动更改的函数就应该一起打包和部署。两个服务之间如果存在过于频繁的通信可能是紧密耦合和低内聚力的症状。
  • 隔离故障,使用弹性策略来防止服务中的级联崩溃

CQRS

原则

  • 在复杂应用中,CRUD可能会变得笨重。拿读来说,应用可能经理多种查询之后才能返回需要的数据,对象映射可能是非常复杂的。拿写来说,可能存在复杂的验证和业务逻辑,导致的结果就是获得了一个非常庞大复杂的模型
  • CQRS的某些实现使用事件源模式,使用此模式,应用程序状态存储为一系列事件。每个事件表示对数据得意组更改。

优势挑战和何时使用

  • 何时使用:在读取和写入的负载完全不对称的情况下。这不是一个最顶层的架构设计,仅适用于需要分离读写的子系统中
  • 优势:
    • 读写负载不同可以独立伸缩
    • 优化数据结构:读写可分别优化对应场景的结构
    • 安全:可以轻松保证只有正确的领域服务才能进行写数据的行为
    • 关注点分离: 分离读写领域能够使模型变得更加容易维护
  • 挑战:
    • 最终一致性导致可能读到的数据是过时的
    • 尽管CQRS并不需要消息系统,但是通常是使用消息系统来负责处理Command并且发布更新事件。因此,应用必须处理消息发送失败和重复消息的情况

最佳实践

Event-driven architecture

原则

  • 事件模型有独立解耦的特点,消费者和生产者可以独立扩展、修改
  • Pub/Sub广播事件模型可以无需关注多少消费者在监听
  • 事件流模型就如同严格按照顺序写日志,客户端不会订阅监听流,而是由客户端自己决定从流的什么位置开始读取,这也就意味着客户端可以在任意时间进行处理,并可重复处理事件。
  • 事件流模型可以使用多种转换服务进行流式处理

优势挑战和何时使用

  • 何时使用
    • 多种子系统处理同类事件
    • 最小时延情况下实时处理信息
    • 复杂事件处理,比如模式匹配或者多个窗口下的事件聚合
    • 高流量的数据处理模式
  • 优势
    • 生产者、消费者是解耦的
    • 没有点对点的交互,这对添加消费者到系统中来说是非常容易的
    • 高度伸缩性和分布式架构
    • 不同子系统对于同一事件流有不同的处理模式
  • 挑战
    • 保证事件的分发对于高流量系统来说是很难的
    • 事件保证只处理一次或者按顺序执行是很难的。消费者通常会开启多个实例,这样就对按顺序处理事件或者说处理非幂等逻辑来说就很难。