前置知识
刚性事务和柔性事务
分布式知识
CAP
分布式系统在设计时只能在一致性,可用性和分区容错性中满足两种,无法兼顾三种。
C: 在分布式环境中,一致性是指数据在多个副本之间是否能够保持一致的特性。在一致性的要求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。
A: 可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。
P: 分区容错性约束了一个分布式系统需要具有如下特性:分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。
对于共享数据系统,最多只能同事用于 CAP 其中的两个,任意两个都有其适应的场景。分布式系统中最重要的是满足业务需求,而不是追求高度抽象,绝对的系统特性。
- | 说明 |
---|---|
放弃一致性(C) | 这里所说的放弃C,并不是完全不需要数据一致性,如果真这样,那么系统的数据也没意义,系统也就没价值。放弃C指放弃数据的强一致性,而保留数据的最终一致性。这样的系统无法保证数据保持实时的一致性,但是能够承诺的是,数据最终会达到一个一致的状态。这就引入了一个时间窗口的概念,具体多久能够达到数据一致取决于系统的设计,主要包括数据副本在不同节点之间的复制时间长短。 |
放弃可用性(A) | 相对于放弃P来说,放弃A正好相反,其做法是一旦系统遇到网络分区或其他故障时,那么受到影响的服务需要等待一定的时间,因此在等待期间系统无法对外提供正常的服务,即不可用。 |
放弃分区容错性(P) | 如果希望能够避免系统出现分区容错性问题,一种较为简单的做法是将所有的数据(或者仅仅是与事务相关的数据)都放在一个分布式节点上。这样的做法虽然无法100%地保证系统不会出错,但至少不会碰到由于网络分区带来的负面影响。但同时需要注意的是,放弃P的同时也就意味着放弃了系统的可拓展性。 |
BASE
BA 指的是基本业务可用性,支持分区失败,S 表示柔性状态,也就是允许短时间内不同步,E 表示最终一致性。原子性和持久性必须从根本上保障,为了可用性,性能和服务降级的需要,只有降低一致性和隔离性的要求。
即分布式事务的两阶段提交,对应技术上的 XA,JTA。
2PC
两阶段提交将一个事务分为两个阶段:
第一阶段:事务管理器要求每个涉及到事务的数据库预提交操作,并反应是否可以提交。
第二阶段:事务管理器综合结果,要求每个数据库提交数据或者回滚数据。
两阶段提交防范应用非常广泛,几乎所有的商业 OLTP 数据库都支持,但是两阶段提交方案锁定资源时间长,对性能影响大,基本不适合解决为服务的问题。
缺陷:
柔性事务有两个特性,基本可用和柔性状态。所谓基本可用是指分布式系统出现故障的时候允许损失一部分的可用行。柔性状态是指允许系统存在中间状态,这个中间状态不会影响系统整体的可用性,比如数据读写分离的主从同步延迟等。柔性事务的一致性指的是最终一致性。
基于可靠消息(消息中间件)的最终一致性解决方案
消息发送的一致性是指产生消息的业务动作与消息发送一致,也就是说如果业务操作成功,那么由这个业务操作所产生的消息一定要发送出去,否则就丢失。
public void completeOrderService() {
// 处理订单
order.process();
// 发送会计原始凭证消息
pipe.sendAccountingVouchetMessage();
}
在上面的情况中,如果业务操作成功,执行消息发送之前应用发生故障,消息发送不出去,导致消息丢失。如果消息系统或者网络异常,也会导致消息发送不出去,最终结果是数据不一致。
public void completeOrderService() {
// 发送会计原始凭证消息
pipe.sendAccountingVouchetMessage();
// 处理订单
order.process();
}
将两个操作调换了一下顺序,情况更加不可控了,消息发出去了业务可能失败,也会造成数据不一致的情况。
保证消息一致性的变通做法:
消息重复发送问题和业务接口的幂等性设计
对与没有确认的消息,采取按规则重新投递的方式进行处理。对于以上流程,消息的重复发送会导致业务接口出现重复调用的问题。消息消费过程中消息重复发送的主要原因就是消费者成功接收处理完消息后,消息中间件没有及时更新投递状态导致的。
独立消息服务方案:
优点:
缺点:
名称 | 数据类型 | 允许空 | 默认值 | 属性 | 释义 |
---|---|---|---|---|---|
uuid | varchar(50) | No | — | unique | UUID |
version | int(11) | No | 0 | — | 版本号 |
editer | varchar(100) | Yes | NULL | — | 修改者 |
creater | varchar(100) | Yes | NULL | — | 创建者 |
edit_time | datetime | Yes | 0000-00-00 00:00:00 | — | 最后修改时间 |
create_time | datetime | No | 0000-00-00 00:00:00 | — | 创建时间 |
msg_id | varchar(50) | No | — | — | 消息ID |
msg_body | longtext | No | — | — | 消息内容 |
msg_date_type | varchar(50) | Yes | — | — | 消息数据类型 |
consumer_queue | varchar(100) | No | — | — | 消费队列 |
send_times | int(6) | No | 0 | — | 消息重发次数 |
is_dead | varchar(20) | No | — | — | 是否死亡 |
status | varchar(20) | No | — | — | 状态 |
remark | varchar(200) | Yes | — | — | 备注 |
field0 | varchar(200) | Yes | — | — | 扩展字段0 |
field1 | varchar(200) | Yes | — | — | 扩展字段1 |
field2 | varchar(200) | Yes | — | — | 扩展字段2 |
TCC 事务补偿型方案
实现:一个完整的业务活动由一个主业服务于若干的从业服务组成。主业服务负责发起并完成整个业务活动。从业务服务提供 TCC 型业务操作。业务活动管理器控制业务活动的一致性,它登记业务活动的操作,并且业务活动提交时确认所有 TCC 型操作的 Confirm 操作,在业务活动取消时调用所有 TCC 型操作的 Cancel 操作。
成本:实现 TCC 操作的成本较高,业务活动结束的时候 Confirm 和 Cancel 操作的执行成本,业务活动的日志成本。
使用范围:强隔离性,严格一致性要求的业务活动,适用于执行时间较短的业务,比如出账户或者收费。
特点:不与具体的服务框架耦合,位于业务服务层,而不是资源层,可以灵活的选择业务资源的锁定粒度。TCC里对每个服务资源操作的是本地事务,数据被锁住的时间短,可扩展性好,可以说是为独立部署的SOA服务而设计的。
尽最大努力通知型
实现: 业务活动的主动方在完成处理之后向业务活动的被动方发送消息,允许消息丢失。业务活动的被动方根据定时策略,向业务活动的主动方查询,恢复丢失的业务消息。
约束: 被动方的处理结果不影响主动方的处理结果。
成本: 业务查询与校对系统的建设成本。
使用范围:最业务最终一致性的时间敏感度低,跨企业的业务活动。
特点:业务活动的主动方在完成业务处理之后,向业务活动的被动方发送通知消息。主动方可以设置时间阶梯通知规则,在通知失败后按规则重复通知,知道通知N次后不再通知。主动方提供校对查询接口给被动方按需校对查询,用户恢复丢失的业务消息。
适用范围: 银行通知,商户通知。
下一张节我们会使用消息队列来实现一个分布式事务框架。
原文:https://www.cnblogs.com/paulwang92115/p/12163452.html