在分布式系统中,跨服务和数据库提供统一、可靠的数据访问至关重要,但又极具挑战性。微服务和数据库的拓扑结构为分布、缓存、复制和同步带来了复杂性。
让我们探索有助于解决这些复杂性并简化构建强大、高性能分布式系统的常见数据访问模式。
概述
我们将通过示例介绍以下分布式数据访问模式:
- 每个服务都有数据库
- 共享数据库
- 每个区域的数据库
- CQRS 和事件源
- Saga 模式
- API 组成
- 缓存
- 物化视图
- 复制
- 联邦
- 多语言持久性
- 多数据中心复制
这些模式有助于构建数据库拓扑、有效缓存、同步更改、处理故障和扩展数据访问。
让我们更详细地了解每种模式。
每个服务都有数据库
每个服务数据库模式为每个微服务提供其自己的私有数据库。
例如,订单服务有自己的订单数据库。客户服务有自己的客户数据库。
好处:
- 解耦——服务不依赖于共享模式或数据库
- 所有权——明确所有权,因为每个服务都管理其数据库
- 规模——数据库可以根据服务需求独立扩展
- 简单性——避免数据库共享,使协调更简单
缺点:
- 数据隔离——跨服务交易和查询执行起来更加困难
- 一致性——如果同步不正确,服务之间的数据就会不一致
- 开销——管理多个数据库的运营开销更高
用例:
- 微服务采用的早期阶段
- 不共享数据的简单 CRUD 服务
- 服务团队希望完全控制数据
这种模式提供了一条解耦服务的快速途径,但通常会随着时间的推移而发展,以允许更好的数据共享。
共享数据库
通过共享数据库模式,服务可以共享对单个逻辑数据库的访问权限。
例如,多个服务通过不同的模式访问 Oracle 数据库中的同一个客户表。
好处:
- 简单——避免数据库之间复杂的数据同步和访问
- 一致性——与数据库事务的强一致性
- 已建立— 利用经过验证的 RDBMS 特性,如事务、索引、授权
缺点:
- 紧密耦合——服务与数据库模式紧密耦合
- 可扩展性——由于不同的服务有不同的需求,数据库很难扩展
- 单点故障——数据库是一个 SPOF,可能导致所有服务瘫痪
用例:
- 逐步将整体式架构转变为服务式架构
- 少数服务共享大部分数据
- 需要强大的数据一致性保证
共享数据库模式牺牲了简单性和一致性,以实现紧密耦合。它在增量迁移期间可以很好地工作,但通常会演变为拆分数据库。
每个区域的数据库
每个区域数据库模式在您运营的每个地理区域中部署数据库实例。
例如,跨区域部署 PostgreSQL 副本以实现低延迟读取。
好处:
- 性能— 每个区域内的读/写延迟较低
- 可用性——发生中断时故障转移到另一个区域数据库
- 数据局部性——让数据靠近用户
- 合规性——满足数据驻留和主权要求
缺点:
- 复杂性——需要跨区域同步数据
- 全局读取——从其他区域读取数据时延迟较高
- 复制滞后——更改需要时间在区域之间传播
用例:
- 全球分布的用户
- 数据主权法
- 停电时需要断开操作
- 要求极低的延迟
每个区域数据库平衡了延迟,同时增加了复杂性。它通常与联合等其他模式结合使用。
命令查询责任分离(CQRS)
CQRS 使用单独的服务或接口将读写分成不同的模型。
例如,为命令服务提供写优化的数据库,为查询服务提供读优化的物化视图。
好处:
- 优化模型——读写模型可以根据需要进行定制
- 可扩展性——读取和写入可以独立扩展
- 简单性——单独的接口避免单一方法的重载
- 性能——命令可以使用不影响读取的快速写入
缺点:
- 复杂性——需要逻辑来同步读写模型
- 最终一致性——由于异步传播,读取可能落后于写入
用例:
- 具有多次读写的协作域
- 需要独立扩展的尖锐读写模式
- 用户可以容忍最终一致性以获得较高的读取性能
当读写模式存在很大差异时,CQRS 是最佳选择。
事件溯源
通过事件源,所有状态变化都会被存储为随时间推移的一系列事件。
例如,不要存储最新的订单状态,而是存储每个 OrderCreated、OrderShipped、OrderDelivered 事件。
好处:
- 审计日志——完整的变更历史记录,有利于审计和调试
- 灵活性——事件是通用的,可以为许多读取模型提供支持
- 性能——通过顺序写入可以快速附加事件
- 重建状态——可以通过重播事件来重建状态
缺点:
- 复杂性——需要将事件与领域模型进行转换
- 数据增长——存储完整历史记录会增加存储需求
- 调试——从事件中重建状态很有挑战性
用例:
- 审计随时间的变化
- 根据历史事件重建预测
- 通过重播事件进行“时间旅行”调试
- 高写入吞吐量应用程序
事件源将变更集中为事件流。将其与 CQRS 结合可实现最大的读/写灵活性。
Saga 模式
Saga 模式使用一系列本地事务来协调跨多个服务的事务。
例如,Order Saga 跨服务发起 OrderCreated、FundsReserved、InventoryReserved 事件。
好处:
- 原子性——提供跨服务的事务一致性
- 协调——协调跨服务的本地事务
- 松耦合——服务通过事件编排而不是 2PC 参与
- 补偿——如果整个 Saga 失败,允许撤消已完成的步骤
缺点:
- 复杂性——需要将交易流程建模为 sagas
- 最终一致性——saga 执行期间数据最终一致
- 没有分布式回滚——当服务发生故障时,无法全局恢复所有服务
用例:
- 跨服务的长期业务交易
- 松耦合服务之间的协作
- 故障时需要采取的补偿措施
Saga 提供分布式协调,而无需紧密的服务耦合。
API 组成
API 组合将来自多个服务的数据聚合到单个 API 中。
API 层查询来自多个服务和数据库的数据并将其组合成聚合响应。
例如,提供由来自不同服务的订单、客户和产品数据组成的订单详情 API。
好处:
- 封装——向消费者隐藏内部结构
- 灵活性——变更实施不会影响消费者
- 性能——从缓存等最佳来源查找数据
- 可用性— 如果服务中断,则优雅地降级
缺点:
- 复杂性——组合逻辑通常复杂而脆弱
- 增加延迟——从服务中检索数据的额外网络跳数
- 版本控制——API 版本与各个服务版本相关联
用例:
- 向客户端呈现统一的领域模型
- 优化从缓存、索引中查找数据
- 跨服务的编排和聚合
- 遗留系统集成以隐藏内部结构
组合使编排集中化。对于具有高重用性的复杂情况,请使用 ESB 样式的工具。
缓存
缓存在靠近消费者的快速访问商店中重复的热数据。
例如,跨区域的产品目录或库存数据的 Redis 缓存。
好处:
- 性能——避免使用低延迟缓存数据进行远程读取
- 可扩展性——减少数据库负载
- 弹性——提供中断和故障的后备方案
缺点:
- 一致性——如果不正确刷新,数据可能会变得陈旧
- 复杂性——缓存失效、TTL 和刷新增加了逻辑
- 开销——运行缓存所需的额外存储和服务
用例:
- 加速数据查找
- 实现更高的读取可扩展性
- 通过后备缓存命中提高可用性
- 通过扩展缓存与数据库来降低成本
缓存可提高性能和可扩展性。请谨慎管理以减少陈旧数据。
物化视图
物化视图缓存查询和聚合的结果以便快速读取。
例如,汇总来自多个服务的指标的实时仪表板视图。
好处:
- 性能——快速检索预先计算的视图
- 自定义索引——针对特定访问模式优化存储
- 简单——减少消费者的复杂查询
- Scale — 通过复制的物化视图进行缩放读取
缺点:
- 新鲜度——需要逐步刷新具体化
- 存储开销——物化视图重复数据
- 维护——更改架构需要重新定义视图
用例:
- 加速缓慢的分析查询
- 来自多个数据源的聚合
- 提供优化的读取模型
- 快速访问实时仪表板和报告
物化视图用存储换取查询速度。非常适合分析和 UI。
复制
复制会在数据库内或跨区域复制数据。
例如,主从 PostgreSQL 复制或多区域 Redis。
好处:
- 性能——跨副本分散读取
- 可用性——如果主服务器发生故障,则故障转移到副本
- 刻度— 水平读取刻度
- 延迟——将副本放置在靠近消费者的位置
缺点:
- 复杂性——复制滞后可能导致读取过时
- 冲突——如果写入操作同时命中主服务器和副本服务器,则需要解决冲突
- 开销——复制数据的额外存储
用例:
- 提高读取密集型工作负载的性能
- 具有故障转移的高可用性
- 跨区域或可用区分布的数据
- 从单节点过渡到集群
复制可提高读取和灾难恢复能力。请仔细监控复制滞后。
联邦
联合(或分片)在数据库之间水平划分数据。
例如,按姓氏首字母在数据库之间对用户进行分片。
好处:
- 规模——添加数据库来扩展写入和存储
- 隔离——将数据放置在靠近用户的位置
- 性能— 每个数据库的工作集越小,性能就越高
缺点:
- 复杂性——需要联邦逻辑和分散/聚集访问
- 连接——跨分片连接具有挑战性
- 重新平衡——重新分配分片需要迁移
用例:
- 扩展写入和存储,超越单个数据库的限制
- 大型区域用户群和多数据中心访问
- 按客户 ID 分片进行隔离
联合分片数据库以满足规模和隔离需求。这增加了复杂性,但消除了单个数据库的限制。
多语言持久性
多语言持久化根据数据特点使用不同的数据模型和数据库。
例如,Cassandra 用于订单,Elasticsearch 用于产品搜索,Kafka 用于客户事件。
好处:
- 最佳拟合— 对每种数据类型使用最佳数据库
- 规模——目标数据库可以独立扩展
- 简单性——每个数据类型的架构和查询更简单
- 灵活性——轻松开发特定模型
缺点:
- 复杂性——集成不同的数据存储
- 一致性——保持分布式数据同步
- 技能— 需要具有多种数据库使用经验
用例:
- 规划具有多种访问模式的大规模
- 将适当的数据迁移到新系统
- 与遗留系统集成
- 混合交易/分析处理
多语言数据最大限度地提高了灵活性,同时需要数据库之间的集成逻辑。
多数据中心复制
多数据中心(多 DC)复制扩展了跨区域数据中心的复制。
例如,具有异步复制的全球分布的 MySQL 集群。
好处:
- 低延迟——每个数据中心内的本地读取
- 高可用性——跨数据中心的故障转移
- 合规性——数据驻留符合法规要求
缺点:
- 复杂性——跨数据中心协调写入
- 网络延迟——较长的 WAN 延迟会影响复制
- 成本——跨区域运营和复制
用例:
- 迁移到区域部署模型
- 最大限度减少全球用户的延迟
- 停电期间需要断开操作
- 双活双数据中心
多数据中心平衡延迟、可用性和主权。监控站点间的延迟。
关键要点
观察常见的分布式数据模式,我们发现以下原则:
- 尽可能将数据库与服务分离,以实现独立的扩展和发展。使用“每个服务一个数据库”和 CQRS 等模式。
- 跨区域和可用区将数据分发到靠近用户的位置,以提高性能和隔离性。这包括按区域和联合的数据库。
- 在缓存和物化视图中复制经常访问的数据,以减少事务数据库的负载。
- 使用 API Composition 和 Saga 模式协调跨服务访问。
- 使用复制和多语言持久性来扩展读取。
- 通过事件和多 DC 复制等技术保持缓存、服务和数据库之间的数据同步。
没有一种模式是万能的。重点是将数据库与服务分离,以实现更好的扩展和演进。然后围绕区域用户模式构建拓扑。最后使用多语言持久性优化具有重复和不同访问模式的某些数据。
数据访问模式提供了一套工具包,用于构建能够妥善处理规模、故障和变化的分布式系统。适当混合和搭配模式,以构建可扩展、有弹性的数据架构。
RA/SD 衍生者AI训练营。发布者:chris,转载请注明出处:https://www.shxcj.com/archives/3803