分布式事务和分布式hash

分布式事务是什么?


分布式事务就是保证各个微服务之间数据一致,本质上就是保证不一样数据库的数据一致性。一致性状态包含算法

  • 强一致性,任什么时候刻,全部节点中数据都是同样的
  • 弱一致性,数据更新后,只能访问到部分节点数据或者是所有访问不到
  • 最终一致性,不保证任什么时候刻同样,但随着时间推移最终会达到一致性状态

所以,存在以下几种方案:数据库

2PC ,二阶段提交是一种尽可能强一致性设计,引入一个事务协调者来协调和管理各参与者的提交和回滚,包含准备和提交两个阶段,阶段之间同步阻塞,准备阶段协调者有超时机制。编程

大体流程:服务器

  • 准备阶段 向各个参与者发送准备命令,能够理解为把除了提交事务以外的事情都作好。全部参与者都返回准备成功则下一阶段提交事务,不然下一阶段协调者就会向全部参与者发送回滚事务的请求,即分布式事务执行失败。
  • 提交阶段 可能提交事务也可能回滚事务,而且存在回滚失败或者提交失败,失败以后就会不断重试。

存在问题:负载均衡

  • 单点故障。协调者是一个单点。解决办法,经过选举获得新的协调者,各个组件都记录log
  • 同步阻塞,效率低。①阶段之间阻塞。②其中一个参与者占用了共享资源就只能阻塞等待。
  • 不肯定性。提交阶段协调者发送提交命令以后,只有一个参与者收到命令,可是两个都挂了,新的协调者并不知道接下来是提交或者是回滚。
  • 数据不一致。极端条件下数据不一致。

场景:目前支付宝使用2PC两阶段提交思想实现了分布式事务服务,它是一个分布式事务框架,用来保障在大规模分布式环境下事务的最终一致性。框架

3PC,为了解决2PC的不肯定性,包含准备,预提交,提交三个阶段。准备阶段只是询问参与者的状态,其余阶段分别对应2PC。相比2PC,参与者也有超时机制(防止在2PC协调者提交阶段准备发送命令的时候挂了,参与者一直阻塞等待的状况),而且新增了一个阶段使得故障恢复以后协调者的决策复杂度下降(解决2PC的不肯定性,在将要发生不肯定性时,新协调者发现有一个参与者处于预提交或者提交阶段,那么代表已经通过了全部参与者的确认了,因此此时执行的就是提交命令)异步

场景:没有找到具体实现,偏理论。分布式

2PC 和 3PC 都不能保证数据100%一致,所以通常都须要有定时扫描补偿机制。函数

TCC,2PC 和 3PC 都是数据库层面的,而 TCC 是业务层面的分布式事务。TCC指的是Try - Confirm - Cancel微服务

  • try,即资源的预留和锁定。
  • Confirm,指的是确认操做,其实就是真正的执行。
  • Cancel,指的时撤销操做,能够理解为撤销预留阶段的动做。

其也存在一个事务管理者,用来记录TCC全局事务状态提交或者回滚。其流程和2PC差很少。但业务的侵入较大、业务耦合度高,须要将原来一个接口能够实现的逻辑拆分为三个接口。

场景:TCC 须要提供三个接口,提升了编程的复杂性,而且依赖于业务方来配合提供这样的接口,推行难度大,因此通常不推荐使用这种方式。

本地消息表,利用各个系统本地事务来实现分布式事务。系统中会定义一个存放本地消息的表,通常都是放在数据库中。

大体流程:

  • 当A被其余系统调用须要业务执行时,将业务的执行操做和将消息放入本地消息表中的操做放在同一个事务中。
  • A定时轮询本地消息表往mq中生产消息,失败则重试。
  • B消费mq中的消息,并处理业务逻辑,若是本地事务失败则重试,若是是业务失败则通知A进行回滚。

场景:跨行转帐可经过该方案实现。在银行一的用户A向银行二的用户B转帐

  • 银行一:在一个本地事务中扣掉A的钱并将转帐消息写入本地消息表中,若是本地事务失败则失败,若是本地事务成功,系统定时轮询消息表并往mq中生产转帐消息,失败则重试。
  • 银行二:mq 消息会被银行二消费并往 B 的帐户增长转帐金额,执行失败会不断重试。

消息事务,只有阿里的RocketMQ支持,实现了最终一致性。

大体流程:

  • A向mq发送准备消息,失败则直接取消,成功则执行本地事务。
  • 本地事务执行成功,向mq发送确认消息,失败则回滚消息。
  • B按期消费mq中的确认消息,执行本地事务并回送ack消息,若是本地事务执行失败,会不断尝试,若是是业务失败,会向A发起回滚请求。
  • mq会按期轮询全部准备消息,调用A提供的反查事务状态接口,若是该准备消息本地事务执行成功则重发确认消息,否者直接回滚。

场景:用户注册成功后发送邮件、电商系统给用户发送优惠券等须要保证最终一致性的场景。

最大努力通知,是最简单的一种柔性事务,适用于一些对最终一致性不敏感的业务,且被动方的处理结果,并不会影响主动方的处理结果。

大体流程:

  • A本地事务执行完成以后,向MQ生产消息。
  • 会存在一个服务消费MQ消息并调用系统B的接口。
  • 若是B执行成功则OK,不然会一直尝试N次,超过则放弃。

场景:最多见的场景就是支付回调,支付服务收到第三方服务支付成功通知后,先更新本身库中订单支付状态,而后同步通知订单服务支付成功。若是这次同步通知失败,会经过异步脚步不断重试地调用订单服务的接口。

分布式Hash是什么?


咱们从分布式系统中负载均衡的问题来描述分布式hash。

常见的负载均衡算法以下:

随机访问策略。随机访问,可能形成服务器负载压力不均衡。

轮询策略。请求均匀分配,可是浪费了性能高的服务器的资源。

权重轮询策略。根据权重轮询,权重须要静态配置,没法自动调节。

Hash取模策略。经过hash取模,伸缩性差,当新增或者下线服务器机器时候,用户与服务器的映射关系会大量失效。

一致性哈希策略。简单来讲就是将整个哈希值(int范围)空间组织成一个虚拟的hash圆环,将每一个服务器标识符跟int最大hash取模,获得一些对应在hash环上的点。用户在访问的时候,根据用户的标识符使用一样的hash函数取模,获得hash环上的一点,但这一点极可能没有服务器映射在上面,因此会顺时针行走,遇到的第一台服务器就是应该处理该用户请求的服务器。

优势:

  • 能够任意动态添加、删除节点,每次添加、删除一个节点仅影响hash环上相邻的节点。

缺点:

  • 会存在数据倾斜问题,由于hash值范围很大(int范围),用户请求量也很大(hash取模分布相对均匀),而服务器数量相对不多(hash取模分布很不均匀),就会形成数据倾斜问题。解决办法就是设置虚拟服务器,每一个真实服务器映射不少个虚拟服务器,这样服务器数据大幅增长,hash取模分布相对均匀。
相关文章
相关标签/搜索