分布式锁通常有很多抉择,基于 Redis 的,基于 Zookeeper 的,基于数据库等等计划。
Redis 用于缓存数据,在我的项目中都有应用,所以应用 Redis 来做分布式锁的会略微多些。
如果用 Redis 来做锁,能够间接用开源的计划,比方 redisson。
最常见的应用形式如下所示:
RLock lock = redisson.getLock("anyLock");
lock.lock();
run();
lock.unlock();
获取锁对象,调用 lock()加锁,执行业务逻辑,调用 unlock()开释锁。
只管框架提供的应用形式曾经很简洁了,然而咱们还是有必要对锁做一层包装。做包装的目标是为了进步扩展性和易用性。
形象接口
如果说咱们间接应用 redisson 的原生 API 做加锁,那么很多中央都会呈现 RLock 相干的代码,忽然有一天,因为某些起因,须要将锁进行替换,这个时候改变的范畴就比拟大了。每个应用了 RLock 的中央都得改。
如下图:很多 Service 都用到了 RLock.lock()办法,当咱们须要替换锁的时候,所有波及到的类和办法都得批改,改变的点如红色局部所示。
所以咱们须要做一层形象,能够定义一个 DistributedLock 接口来提供锁相干的能力,提供多种实现,这样不便替换和扩大。
如下图:每个 Service 中都是用的 DistributedLock 接口来加锁,当咱们须要替换锁的实现时,应用的中央不须要改变,只须要替换 DistributedLock 的实现即可。
主动开释
主动开释指的是对于加锁之后,业务逻辑执行结束须要主动敞开锁。依照后面 Redisson 的形式咱们须要手动调用 unlock()来开释持有的锁。
当然 Redisson 也提供了超时开释的性能,失常状况下必定是业务执行结束就要开释锁了,同一个锁的下个申请能力持续接着解决。
手动开释资源最容易呈现的问题就是遗记开释,所以在 JDK7 中引入了 try-with-resources 来主动开释资源,置信大家都很相熟。
所以咱们在封装的时候,尽量不要让使用者去手动开释,缩小出错的概率。对于有后果的咱们能够应用 Supplier 来传递你的逻辑,对于没有返回后果的能够用 Runnable 来传递你的逻辑。
/**
* 加锁
* @param key 锁 Key
* @param waitTime 尝试加锁,等待时间 (ms)
* @param leaseTime 上锁后的生效工夫 (ms)
* @param success 锁胜利执行的逻辑
* @param fail 锁失败执行的逻辑
* @return
*/
<T> T lock(String key, int waitTime, int leaseTime, Supplier<T> success, Supplier<T> fail);
应用:
String result = distributedLock.lock("1001", 1000, () -> {System.out.println("进来了。。。。");
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}
return "success";
}, () -> {System.out.println("加锁失败。。。。");
return "fail";
});
容灾解决
另一个须要留神的问题就是锁的可用性,万一对应的 Redis 出问题了,这个时候去加锁必定会失败,如果不做任何解决,就会影响失常的业务操作,导致业务不可用。
咱们除了实现 Redis 的锁之外,还能够实现其余的锁,比方数据库锁。当 Redis 锁不可用的时候降级为数据库锁,尽管性能有所影响,然而不会影响业务。
如果数据库锁也不可用了(题外话:所有都不可用可能性十分小),那还是让业务操作失败比拟好。因为咱们用加锁的场景,必定是为了避免并发场景带来的问题,如果当锁不可用时,你将异样生产了,让业务操作继续下去,就有可能呈现没有加锁的业务问题。
当然监控也十分须要,Redis, 数据库等监控。在出故障的时候,及时有人员染指。
监控体系
Redis, 数据库,Zookeeper 这些承载分布式实现的中间件的监控必定是必须要有的。另一个监控就是更细粒度的对应锁这个动作的监控。
比方加锁的工夫,开释锁的工夫,在锁外面执行业务的工夫,锁的并发量,执行次数,加锁失败的次数。
这些数据指标都十分重要,可能帮忙你及时发现问题。比方 10 秒内几百次加锁失败,都降级成了数据库锁,这个时候你收到了警报,一看就晓得 Redis 出问题了,及时解决。
监控形式就轻易了,每个公司都不一样,你能够裸露数据给 Prometheus 抓取,也能够集成 Cat 做好埋点,只有能监控,能告警就能够了。
对于作者 :尹吉欢,简略的技术爱好者,《Spring Cloud 微服务 - 全栈技术与案例解析》,《Spring Cloud 微服务 入门 实战与进阶》作者, 公众号 猿天地 发起人。
我整顿了一份很全的学习材料,感兴趣的能够微信搜寻「猿天地 」,回复关键字「 学习材料」获取我整顿好了的 Spring Cloud,Spring Cloud Alibaba,Sharding-JDBC 分库分表,任务调度框架 XXL-JOB,MongoDB,爬虫等相干材料。