分布式锁,分布式事务以及解决方案了解一下

一、分布式锁

1、什么是分布式锁?

场景1:常规的我们多线程访问同一代码块的时候,为了保证同一时间只能 由一个线程访问,保证数据安全一致性,通常我们使用synchronized关键字来对方法加锁,以达到保证数据安全性。

场景2:现在越来越多的项目,为了追求性能与高并发,采用了soa架构,微服务架构,于是就会出现多个模块单独的服务。这个时候呢就会有一个问题,如何保证多个节点的现场同步执行呢? 这种情况呢,就会用到了分布式锁。

2、分布式锁的解决方案与实现有哪些呢?

1、数据库解决方案思路:

        a.数据库建一张表,字段方法名并且作为唯一性,当一个方法执行时插入,则相当于获得锁,其他线程将无法访问,方法执行完则释放锁。

但是上面这种存在问题:

1、数据库单点,出现故障则将导致系统不可用。

2、没有失效时间,一旦操作方法异常,导致一直没有解锁,也将导致其他不可用用。

        b.使用select * from user u where username = '' for update 来对记录加上排他锁。操作完成后使用commit命令释放锁。

2、基于缓存实现:  通常有Memcached、Redis实现等,以下以Redis实现分布式锁为例

思路:主要用到的redis函数是setnx(),这个应该是实现分布式锁最主要的函数。首先是将某一任务标识名(这里用Lock:order作为标识名的例子)作为键存到redis里,并为其设个过期时间,如果是还有Lock:order请求过来,先是通过setnx()看看是否能将Lock:order插入到redis里,可以的话就返回true,不可以就返回false

具体实现参照:https://www.cnblogs.com/austinspark-jessylu/p/8043726.html

3.Zookeeper分布式锁

大致思路:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。

ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同不到所有的Follower机器上,所以性能上不如基于缓存实现。

二、分布式事务:

举个栗子吧:比如从支付宝转100元到余额宝,我们又两个方法1、支付宝减掉100,2、余额宝加上100。传统的在一个模块,一个服务,或者一个方法里面,我们就很好解决了,只需要注解一个事务就行了,是吧。

@Transactional(rollbackFor=Exception.class) 这样我们就可以保证两个方法数据的一致性了。

但是显然,现在我们的项目中,为了满足性能要求,不可能还这样传统单机实现。我们做成了两个服务,在两个不同的模块 1、支付宝,2、余额宝 这样就存在了我们提到的问题,分布式事务,这个时候如何解决呢?

通常来说呢 实现方式有如下几种:

1、两阶段提交协议(Two-phase Commit,2PC):架构图如下

简单来说,协调器先给A/B各发一条,准备的命令,等到都返回准备好了的命令的时候,在发起事务提交。这样来保证事务一致性,但是存在很多问题,就是通信上中断的情况,会导致事务一致无法提交,而可能使系统崩溃。这就可以使用第二种方案。

2、TCC补偿性,分为三个阶段TRYING-CONFIRMING-CANCELING(使用消息队列实现,比如mq)

猜你喜欢

转载自blog.csdn.net/xingsfdz/article/details/81105683