Go微服务: 关于分布式系统中的常见问题,分布式事务,以及常用解决方案

本文主要是介绍Go微服务: 关于分布式系统中的常见问题,分布式事务,以及常用解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

  • 在当今的互联网时代,分布式系统已成为支撑大规模服务、高并发和高性能应用的基石
  • 它们通过网络连接多台计算机,协同工作,共同完成任务,但这也引入了诸如数据一致性、网络延迟、容错性等挑战
  • 解决这些问题的关键在于设计和实施有效的分布式协议
  • 分布式很重要,因为微服务中需要用到分布式

常见的一些问题


1 ) 场景 1

  • 订单微服务在调用库存微服务进行扣减库存
  • 调用成功后,订单微服务进行新建订单
  • 这里可能会存在问题
    • A )先扣库存,后生成订单,新建订单的时候出问题了怎么办,这时候库存微服务如何处理?它已经扣完库存了
    • 这种场景是库存扣除了,但是订单生成失败
    • B )先新建订单,库存不可用了,库存扣减成功,但是扣减返回时网络不通了,新建订单就会超时,订单创建失败,并回滚了,但是库存扣了
  • 以上两种都是问题,而且经常发生,因为都是微服务,而且存在网络抖动
  • 库存的扣减和订单表不一致造成的问题,实质都是分布式事务要解决的问题

2 )场景 2

  • 关于支付的场景, 比如,下单了,但是不支付,也是非常正常
  • 有100个用户下单,但是不支付,库存一直被占用
  • 这是订单超时需要解决的问题

3 )综合来说

  • 分布式微服务的好处可以解决单体的问题,但是也带来了新的问题
  • 在不断解决问题中优化系统,让系统更易于维护
  • 使用业务上的流程规避微服务中的劣势

Mysql事务

  • 事务:通俗来说是同生共死,要么一起成功,要么一起失败
  • 官方解释事务:事务是程序中一系列严密的逻辑操作,所有操作必须全部成功完成,否则所有操作中的更改会一起失败回滚

Mysql事务的特性 ACID

  • 1 )原子性 Atomicity: 最小的单位,不能再切分;原子性关心的是功能
  • 2 )一致性 Consistency: 事务的执行使从一个状态转化为另一个状态,但是最整个事务的完整性保持稳定,例如:A->B转账, A, B的总额保持一致
    • 两条不同的sql, 一个是减法,一个是加法,在高并发的时候保证sql执行的正确性,一定要加锁来做转账;
    • 从业务上要规避中间状态,比如规定过一会儿再来查询
    • 一致性关心的是状态,没有部分成功的状态
  • 3 )隔离性 Isolation
    • 多个用户访问数据库的时候,比如操作同一张表,数据库为每一个用户开启事务,不能被其他事务干扰,多个并发事务之间相互隔离
    • 其实要达到这个效果,任意两个并发的事务,比如T1 和 T2, 在T1的角度看来,T2要么在之前就结束,T2要么在自身结束后才能开始
    • 执行的时候,不会干扰,被隔离了, 本质是一个个的执行
  • 4 )持久性 Durability
    • 当事务正确完成后,数据的改变是永久性的,最终是落盘的,不能一直在内存里

分布式事务

  • 分布式事务不能满足 ACID,但是在努力满足ACID

  • 尽管分布式事务设计目标是满足ACID,但在实际应用中,由于网络延迟、节点故障、分区、性能考量,往往需要对这些特性进行权衡

  • 例如,牺牲一定程度的隔离性以换取更高的性能(BASE理论),或者采用最终一致性模型来平衡一致性与可用性(CAP定理)

  • 因此,分布式事务的解决方案往往是折衷的艺术,根据具体场景选择最合适的策略

  • 下面我们从 ACID 层面来说

  • 1 )原子性(Atomicity):

    • 分布式事务的原子性通常是通过两阶段提交(2PC)、三阶段提交(3PC)等协议来保证
    • 这些协议在理论上可以实现原子性,但在实践中存在局限性。例如,两阶段提交可能导致参与者长时间锁定资源等待,且存在单点故障问题,若协调者故障,可能导致参与者长时间阻塞或不确定状态
    • 三阶段提交虽减少阻塞,但增加了复杂度和通信成本
  • 2 )一致性(Consistency):

    • 分布式系统为了保证高可用性和扩展性,往往采用弱一致性模型(如最终一致性、因果一致性),牺牲了强一致性
    • 这意味着在事务处理过程中,系统可能暂时处于不一致的状态,直到数据同步完成
    • 虽然通过补偿事务(如Saga)可以恢复一致性,但可能引入额外延迟和复杂性
  • 3 )隔离性(Isolation):

    • 在分布式系统中实现严格的隔离性(如序列化隔离)是非常昂贵的,因为它通常需要大量的锁或复杂的并发控制机制,这会直接影响系统的吞吐量和响应时间
    • 因此,许多分布式数据库和事务系统倾向于使用较弱的隔离级别(如读已提交、读未提交),这些级别虽然提高了性能但可能暴露并发事务间的数据不一致视图问题
  • 4 )持久性(Durability):

    • 虽分布式事务中,持久性一般通过日志记录和冗余备份等机制来保证,通常能够较好满足
    • 但极端情况下,如多数据中心级别的灾难、网络分割,可能导致数据同步出现问题,影响持久性保证
    • 此外,性能和持久性的平衡也是一个考虑因素,过度追求即时持久可能牺牲写入性能
  • 综上所述,虽然分布式事务设计的目标是尽量贴近ACID原则,但在分布式环境的实际应用中

  • 为了应对网络延迟、容错、提高可用性和扩展性,往往需要在某些方面做出妥协,如采用BASE(基本可用性、软状态、最终一致性、最终一致性)哲学,而不是严格遵循ACID

分布式系统中,哪些方面会造成数据不一致的问题

  • 1 )硬件故障
  • 2 )网络抖动
  • 3 )网络拥堵
  • 4 )其他原因
    • 代码bug
    • 系统问题:不兼容,日志级别较低
    • 断电
    • 磁盘已满

分布式事务的常用解决方案

  • 1 )二阶段提交

    • 两阶段提交是最传统的分布式事务协议,分为准备阶段和提交阶段:
      • 准备阶段:协调者询问参与者(资源管理器)是否准备好提交事务,参与者回复“准备好”或“取消”
      • 提交阶段:如果所有参与者都回复“准备好”,协调者命令所有参与者提交事务;若有任何参与者回复“取消”,则命令所有参与者回滚
    • 优点:理论上保证了强一致性
    • 缺点:性能差,阻塞问题严重,单点故障问题(协调者故障),不适合大规模分布式系统
    • 由此衍生出了,三阶段提交(3PC, Three-Phase Commit)
    • 三阶段提交是两阶段提交的改进版,新增了一个预提交阶段以减少阻塞:
      • 第一阶段(CanCommit):询问阶段
      • 第二阶段(PreCommit):预提交,参与者准备提交
      • 第三阶段(DoCommit):正式提交或回滚
      • 优点:减少了阻塞时间
      • 缺点:复杂度增加,同样存在单点故障问题,性能问题
  • 2 )TCC的补偿模式

    • 这是一种分布式事务解决方案,它通过将事务处理过程拆分为三个阶段来确保分布式系统中的操作成功完成或在失败时进行补偿。
    • 以下是TCC补偿模式的阶段划分:
      • A )Try阶段:业务系统尝试执行事务并锁定所需资源。在这一阶段,业务会进行业务检查,并预留好资源,但不会真正修改资源。例如,在库存扣减的业务中,Try阶段可能会增加freeze字段的数值,将库存冻结。
      • B ) Confirm阶段:如果Try阶段成功,业务系统将进入Confirm阶段并提交事务。在这一阶段,业务系统会对之前预留的资源进行真正的修改,并确认执行业务操作。在库存扣减的业务中,Confirm阶段会真正降低库存。
      • C ) Cancel阶段:如果Try阶段失败或出现其他异常情况,业务系统将回滚事务并释放所有锁定的资源。Cancel阶段会释放Try阶段预留的资源,并进行相应的补偿操作。在库存扣减的业务中,Cancel阶段会将冻结的数值返回去。
    • 实践TCC模式的注意点
      • A ) 幂等性:Confirm和Cancel操作需要设计为幂等,无论调用多少次,结果都相同,以防止重试时产生副作用。
      • B ) 事务补偿服务:TCC模式要求为每个操作编写额外的Confirm和Cancel逻辑,这增加了开发复杂度和维护成本。
      • C )异步处理:Cancel操作和部分Confirm操作可能需要异步处理,以提高系统响应速度,但需确保异步操作的可靠投递达。
      • D ) 监控与重试:TCC模式下的操作应有完善的监控和自动重试机制,确保Confirm和Cancel能够最终执行成功。
  • TCC模式是一种权衡了事务处理性能和一致性的解决方案,适用于那些对事务要求较高但又无法直接使用传统ACID事务模型的分布式场景。

  • 3 )基于本地消息实现的最终一致性

    • 基于本地消息实现的最终一致性是分布式系统中一种常用的模式,用于确保分布式服务间的数据最终达到一致状态,特别是在跨服务事务处理和异步通信的场景下。
    • 这种模式的核心思想是通过发布-订阅消息机制,结合消息的持久化存储,来确保在不同服务或组件之间操作的一致性。
    • 下面是基于本地消息实现最终一致性的一个基本步骤:
      • 1 ) 生成消息并持久化:当一个服务(称为生产者)需要执行一个操作,并且这个操作需要另一个服务(称为消费者)知晓时,生产者首先在本地生成一条消息,该消息描述了已完成的操作或需要执行的请求。这条消息会被持久化存储在本地的消息队列中,比如数据库的日志表。这样即使生产者服务宕机,消息也不会丢失。
      • 2 ) 发送消息:生产者随后尝试将消息发送给消息中间件(如RabbitMQ、Kafka等),或者直接通过HTTP、RPC等方式通知消费者服务。注意,这个步骤与消息的持久化是解耦的,即消息的发送成功与否不影响消息的持久化状态。
      • 3 ) 消费消息:消费者服务监听消息中间件,接收到消息后进行处理。如果处理成功,则一切正常;如果处理失败,根据设计可能会有重试机制,尝试再次处理,也可能需要人工介入。
      • 4 ) 消息确认与补偿:
        • 确认机制:一旦消费者成功处理了消息,通常会向生产者发送一个确认(ACK),告知操作已完成。在某些消息中间件中,这一步是自动完成的。
        • 补偿逻辑:如果消费者长时间未确认,或者消息处理失败且无法恢复,生产者端可能需要启动补偿逻辑,比如重发消息、执行逆向操作或触发人工审核等。
    • 优势
      • 解耦:生产者和消费者服务高度解耦,各自独立发展,降低了系统的耦合度。
      • 可靠性:通过消息持久化,确保了即使在系统崩溃或网络问题情况下,消息也不会丢失,提高了数据处理的可靠性。
      • 伸缩性:消息队列可以作为缓冲区,平滑处理高峰期流量,有助于系统的水平扩展。
    • 应用场景
      • 订单系统:下单后,通过消息通知库存系统减库存、物流系统发货等。
      • 支付系统:支付成功后,通过消息通知订单系统更新订单状态、积分系统增加用户积分等。
      • 微服务架构:各服务间的数据同步、事件驱动的业务流程等。
    • 注意事项
      • 幂等性:消费者处理消息需要设计为幂等,防止重复处理导致数据不一致。
      • 消息顺序性:某些场景下,消息的顺序非常重要,需要选择支持消息顺序性的消息队列或采取额外措施。
      • 消息丢失与重复:要确保消息处理逻辑能妥善处理消息的丢失与重复问题,通常通过唯一ID、状态机等机制来控制。
    • 通过上述机制,基于本地消息实现的最终一致性策略能够在分布式系统中有效地保证数据的一致性,同时保持系统的灵活性和可扩展性。
  • 4 )最大努力通知

    • 最大努力通知(Best Effort Notification)是一种通信协议或策略,主要用于描述在不可靠的网络环境下,发送方尽可能地尝试将消息送达接收方,但不保证消息一定能成功送达的机制。
    • 这种策略常应用于对即时性和可靠性要求不是极其严格的场景,如某些金融交易的确认通知、系统异步事件通知、或是资源受限的物联网(IoT)环境等。最大努力通知的核心特点包括:
      • 尽力而为:发送方不会因为一次发送失败就停止尝试,而是会根据预设的策略(如重试次数、重试间隔等)进行多次尝试发送消息。
      • 不保证送达:与ACID事务中的强一致性不同,最大努力通知不保证消息一定能够送达接收方。网络故障、系统崩溃、消息队列满等情况都可能导致消息丢失。
      • 可能的重复:在重试机制下,接收方可能会收到重复的消息。因此,接收方需要实现幂等性处理逻辑,即多次处理同一消息的结果与处理一次相同。
      • 可配置性:最大努力通知的策略往往是可配置的,例如重试的次数、时间间隔、是否需要回执确认等,可以根据具体应用场景调整。
      • 通知状态不确定:由于没有严格的确认机制,发送方往往无法确切知道消息是否以及何时被接收方成功处理。
    • 应用场景
      • 通知服务:如电子邮件通知、短信通知等,这些场景下消息的即时到达虽然重要,但非关键,允许一定程度的延迟或丢失。
      • 日志收集与监控:在分布式系统中收集日志或监控信息时,数据的完整性虽好,但更重要的是系统不应因日志传输问题而中断运行。
      • 资源有限的设备通信:在IoT领域,传感器或低功耗设备可能因电力、带宽限制而采用最大努力的方式发送数据到中心服务器。
    • 实现注意事项
      • 幂等性设计:确保接收方对重复消息的处理不会影响业务逻辑的正确性。
      • 超时与重试策略:合理设置消息发送的超时时间和重试逻辑,避免无休止的重试占用系统资源。
      • 消息去重:在接收方实施机制,如利用消息ID记录已处理消息,避免处理重复消息。
      • 反馈机制:尽管不是严格确认,但提供某种形式的反馈机制(如发送回执、错误报告)可以帮助优化和监控最大努力通知的过程。
    • 总之,最大努力通知策略是在牺牲一定可靠性的前提下,换取系统设计的简化、成本的降低和对不稳定网络环境更好的适应性。
  • 5 )基于可靠消息最终一致性

    • 基于可靠消息的最终一致性是一种分布式系统中常用的技术策略,用于确保不同服务或组件间的数据在一定时间内达到一致状态,即使在面临网络延迟、服务故障等情况下。
    • 这种方法依赖于消息队列或消息中间件来异步传递消息,通过确保消息的可靠传递和处理,达到最终一致性。以下是基于可靠消息实现最终一致性的一些关键环节和原则:
    • 基本流程
      • 生成并发送消息:当一个服务(生产者)完成某个操作后,它会生成一个消息,该消息包含该操作的细节或所需执行的任务,并将其发送到消息队列或消息中间件(如RabbitMQ、Kafka、Amazon SQS等)。关键在于确保消息的生成和发送过程是事务性的,即操作成功完成且消息成功入队,或两者都不发生。
      • 消息持久化存储:消息中间件通常会保证消息的持久化存储,即使在消息尚未被消费前,系统发生故障,消息也不会丢失。
      • 消费与确认:另一个服务(消费者)监听消息队列,拉取并处理消息。处理成功后,消费者会向消息中间件发送确认(ACK),表明消息已被正确处理。如果消息处理失败,消息可能被重新放入队列等待重试,或者根据策略被丢弃、记录错误或发送到死信队列。
      • 幂等性设计:消费者需要设计为幂等操作,即多次处理同一个消息产生的结果与处理一次相同,避免因消息重试导致的数据不一致。
      • 补偿机制:在某些情况下,如果消费者无法处理消息(如依赖服务不可用),可能需要触发补偿逻辑,以撤销或修复由已处理部分消息引起的数据不一致。
    • 关键特性
      • 可靠性:通过消息的持久化存储和事务性发送,确保消息不丢失,提高系统的可靠性。
      • 异步处理:消息队列允许生产和消费异步进行,提高了系统的响应速度和解耦。
      • 灵活性与可扩展性:容易扩展消息处理能力,通过增加消费者实例来提高处理速度,适应系统负载变化。
      • 故障隔离:生产者和消费者之间的松耦合,减少了单点故障的影响。
    • 应用场景
      • 订单系统:订单创建后,通过消息通知库存系统减少库存、物流系统安排配送等。
      • 支付系统:支付成功后,异步通知订单系统更新订单状态,发送确认邮件或短信。
      • 微服务架构:不同服务间的事件驱动流程,如用户注册后触发邮件通知、欢迎流程等。
    • 注意事项
      • 消息丢失与重复处理:确保消息不丢失的同时,也要处理消息重复消费的问题。
      • 消息顺序性:某些场景下消息的顺序很重要,需要选择支持有序消息的中间件或额外设计逻辑。
      • 监控与报警:建立有效的监控和报警机制,及时发现消息积压、处理延迟等问题。
    • 基于可靠消息的最终一致性策略是分布式系统设计中的重要组成部分,它平衡了数据一致性和系统性能、可用性之间的关系,尤其适用于高并发、分布式环境。

这篇关于Go微服务: 关于分布式系统中的常见问题,分布式事务,以及常用解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1037628

相关文章

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Eureka高可用注册中心registered-replicas没有分布式注册中心

自己在学习过程中发现,如果Eureka挂掉了,其他的Client就跑不起来了,那既然是商业项目,还是要处理好这个问题,所以决定用《Spring Cloud微服务实战》(PDF版在全栈技术交流群中自行获取)中说的“高可用注册中心”。 一开始我yml的配置是这样的 server:port: 8761eureka:instance:hostname: 127.0.0.1client:fetch-r

React+TS前台项目实战(十七)-- 全局常用组件Dropdown封装

文章目录 前言Dropdown组件1. 功能分析2. 代码+详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局Dropdown组件封装,可根据UI设计师要求自定义修改。 Dropdown组件 1. 功能分析 (1)通过position属性,可以控制下拉选项的位置 (2)通过传入width属性, 可以自定义下拉选项的宽度 (3)通过传入classN

springboot家政服务管理平台 LW +PPT+源码+讲解

3系统的可行性研究及需求分析 3.1可行性研究 3.1.1技术可行性分析 经过大学四年的学习,已经掌握了JAVA、Mysql数据库等方面的编程技巧和方法,对于这些技术该有的软硬件配置也是齐全的,能够满足开发的需要。 本家政服务管理平台采用的是Mysql作为数据库,可以绝对地保证用户数据的安全;可以与Mysql数据库进行无缝连接。 所以,家政服务管理平台在技术上是可以实施的。 3.1

Spring中事务的传播机制

一、前言 首先事务传播机制解决了什么问题 Spring 事务传播机制是包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。 事务的传播级别有 7 个,支持当前事务的:REQUIRED、SUPPORTS、MANDATORY; 不支持当前事务的:REQUIRES_NEW、NOT_SUPPORTED、NEVER,以及嵌套事务 NESTED,其中 REQUIRED 是默认的事务传播级别。

帆软报表常用操作

欢迎来到我的博客,代码的世界里,每一行都是一个故事 🎏:你只管努力,剩下的交给时间 🏠 :小破站 帆软报表常用操作 多序号实现使用数据集作为参数空白页或者竖线页修改页面Title金额,或者保留两位小数等等设置日期格式显示图片使用公式 多序号实现 所用函数为SEQ(),如果一张报表中需要用到多个序号,那么就需要加入参数SEQ(1),SEQ(

常用MQ消息中间件Kafka、ZeroMQ和RabbitMQ对比及RabbitMQ详解

1、概述   在现代的分布式系统和实时数据处理领域,消息中间件扮演着关键的角色,用于解决应用程序之间的通信和数据传递的挑战。在众多的消息中间件解决方案中,Kafka、ZeroMQ和RabbitMQ 是备受关注和广泛应用的代表性系统。它们各自具有独特的特点和优势,适用于不同的应用场景和需求。   Kafka 是一个高性能、可扩展的分布式消息队列系统,被设计用于处理大规模的数据流和实时数据传输。它

微服务中RPC的强类型检查与HTTP的弱类型对比

在微服务架构中,服务间的通信是一个至关重要的环节。其中,远程过程调用(RPC)和HTTP是两种最常见的通信方式。虽然它们都能实现服务间的数据交换,但在类型检查方面,RPC的强类型检查和HTTP的弱类型之间有着显著的差异。本文将深入探讨这两种通信方式在类型检查方面的优缺点,以及它们对微服务架构的影响。 一、RPC的强类型检查 RPC的强类型检查是其核心优势之一。在RPC通信中,客户端和服务端都使

中国341城市生态系统服务价值数据集(2000-2020年)

生态系统服务反映了人类直接或者间接从自然生态系统中获得的各种惠益,对支撑和维持人类生存和福祉起着重要基础作用。目前针对全国城市尺度的生态系统服务价值的长期评估还相对较少。我们在Xie等(2017)的静态生态系统服务当量因子表基础上,选取净初级生产力,降水量,生物迁移阻力,土壤侵蚀度和道路密度五个变量,对生态系统供给服务、调节服务、支持服务和文化服务共4大类和11小类的当量因子进行了时空调整,计算了

XMG 常用的手势

// 创建点按手势     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];    tap.numberOfTabsRequired=2; //点击的次数