分布式相关问题

95 阅读3分钟

1.分布式事务了解吗

XA分布式事务协议

两阶段提交( 2PC )

需要一个协调者节点。

第一阶段:协调者让参与者发出prepare,让参与者在本地进行数据更新,但数据未提交(此时的更新记录会记录undo logredo log),当所有参与者的本地更新准备好,告知协调者

image.png

第二阶段:如果协调者结点收到的第一阶段反馈都是正向反馈,则向所有事务参与者发送Commit请求,让参与者提交自己的本地事务。提交完毕后返回确认信息。

image.png

缺点:1.单点故障(协调者)2.性能(所有的准备好才会提交)3,丢失消息导致不一致问题
解决方式: 3PC 

三阶段提交( 3PC )

2.分布式锁

背景

本质:解决JUC无法提供跨JVM的互斥(同步)能力的问题

分布式锁应该具备的条件

1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行; 
2、高可用的获取锁与释放锁; 
3、高性能的获取锁与释放锁; 
4、具备可重入特性; 
5、具备锁失效机制,防止死锁; 
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。

分布式锁的三种实现方式

在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

基于数据库实现分布式锁; 
基于缓存(Redis等)实现分布式锁; 
基于Zookeeper实现分布式锁;

基于数据库实现分布式锁

建一个 方法名 的表,方法名 列唯一,线程想要执行这个方法(即获取到锁),必须在表中插入这行数据,并且在执行完毕后删除这条数据(释放锁)

缺点:

1、这把锁强依赖数据库的可用性,`数据库是一个单点`,一旦数据库挂掉,会导致业务系统不可用。
2、这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。
3、这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。
4、这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

解决方案:

1、数据库是单点?搞两个数据库,数据之前双向同步。一旦挂掉快速切换到备库上。
2、没有失效时间?只要做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。
3、非阻塞的?搞一个while循环,直到insert成功再返回成功。
4、非重入的?在数据库表中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。
基于Redis实现分布式锁