|
2 | 2 | 在分布式环境中,需要一种跨JVM的互斥机制来控制共享资源的访问。例如,为避免用户操作重复导致交易执行多次,使用分布式锁可以将第一次以外的请求在所有服务节点上立马取消掉。如果使用事务在数据库层面进行限制也能实现的但会增大数据库的压力。 |
3 | 3 |
|
4 | 4 | ## 实现方式 |
5 | | -来源: https://blog.csdn.net/xlgen157387/article/details/79036337 |
| 5 | +来源: https://blog.csdn.net/xlgen157387/article/details/79036337 https://www.hollischuang.com/archives/1716 https://www.jianshu.com/p/c2b4aa7a12f1 |
6 | 6 | ### 数据库 |
7 | 7 | 在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。 |
8 | 8 |
|
@@ -32,10 +32,51 @@ INSERT INTO method_lock (method_name, desc) VALUES ('methodName', '测试的meth |
32 | 32 | delete from method_lock where method_name ='methodName'; |
33 | 33 | ``` |
34 | 34 |
|
| 35 | +优点:易于理解实现 |
| 36 | + |
35 | 37 | 缺点: |
36 | 38 |
|
37 | | -1. 没有锁失效机制,因为有可能出现成功插入数据后,服务器宕机了,对应的数据没有被删除,当服务恢复后一直获取不到锁,所以,需要在表中新增一列,用于记录失效时间,并且需要有定时任务清除这些失效的数据; |
38 | | -2. 数据库的可用性和性能将直接影响分布式锁的可用性及性能,所以,数据库需要双机部署、数据同步、主备切换 |
39 | | -3. 实现复杂 |
| 39 | +1. 没有锁失效自动删除机制,因为有可能出现成功插入数据后,服务器宕机了,对应的数据没有被删除,当服务恢复后一直获取不到锁,所以,需要在表中新增一列,用于记录失效时间,并且需要有定时任务清除这些失效的数据; |
| 40 | +2. 吞吐量很低 |
| 41 | +3. 单点故障问题 |
40 | 42 |
|
41 | 43 | ### 基于Redis |
| 44 | +NX是Redis提供的一个原子操作,如果指定key存在,那么NX失败,如果不存在会进行set操作并返回成功。我们可以利用这个来实现一个分布式的锁,主要思路就是,set成功表示获取锁,set失败表示获取失败,失败后需要重试。再加上EX参数可以让该key在超时之后自动删除。 |
| 45 | + |
| 46 | +```java |
| 47 | +public void lock(String key, String request, int timeout) throws InterruptedException { |
| 48 | + Jedis jedis = jedisPool.getResource(); |
| 49 | + |
| 50 | + while (timeout >= 0) { |
| 51 | + String result = jedis.set(LOCK_PREFIX + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, DEFAULT_EXPIRE_TIME); |
| 52 | + if (LOCK_MSG.equals(result)) { |
| 53 | + jedis.close(); |
| 54 | + return; |
| 55 | + } |
| 56 | + Thread.sleep(DEFAULT_SLEEP_TIME); |
| 57 | + timeout -= DEFAULT_SLEEP_TIME; |
| 58 | + } |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +优点: |
| 63 | + |
| 64 | +1. 吞吐量高 |
| 65 | +2. 有锁失效自动删除机制,保证不会阻塞所有流程 |
| 66 | + |
| 67 | +缺点: |
| 68 | + |
| 69 | +1. 单点故障问题 |
| 70 | +2. 锁超时问题:如果A拿到锁之后设置了超时时长,但是业务还未执行完成且锁已经被释放,此时其他进程就会拿到锁从而执行相同的业务 |
| 71 | + |
| 72 | +### 基于ZooKeeper |
| 73 | +当客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁只需要判断有序节点中序号最小的一个。当释放锁的时候,将这个瞬时节点删除 |
| 74 | + |
| 75 | +优点: |
| 76 | + |
| 77 | +1. 解决锁超时问题。因为Zookeeper的写入都是顺序的,在一个节点创建之后,其他请求再次创建便会失败,同时可以对这个节点进行Watch,如果节点删除会通知其他节点抢占锁 |
| 78 | + |
| 79 | +缺点: |
| 80 | + |
| 81 | +1. 性能不如Redis |
| 82 | +2. 强依赖zk,如果原来系统不用zk那就很麻烦了 |
0 commit comments