当前位置: 首页 > Web前端 > JavaScript

微服务架构:Redis分布式锁

时间:2023-03-27 13:48:49 JavaScript

Redis分布式锁实现原理及不同实现比较Redis分布式锁并发问题基于Redis的分布式锁集群架构在单体架构上,乐观锁和悲观锁可以在并发下锁定同步的代码块,我们经常使用synchronized来锁定方法。但是在有负载均衡的集群模式下,普通的synchronized是不能同时锁定两个服务器的请求的。这是理解秒杀项目的难点之一:一个人,一个订单并发安全问题使用集群架构的难点。先从单体项目说起,这个比较容易理解。如果有两个线程:线程1查询顺序判断是否存在。然后第二个线程会查询订单,判断是否存在。在synchronized的作用下,两个线程不会出问题。现在,我们不再是一台服务器,而是多台。在现在的JVM中,锁的原理是在JVM内部维护一个锁监听对象。监控对象使用我们的常量池中的userId。然后,这个常量池被维护在JVM内部。当ID相同时,永远是同一个锁,也就是说锁监视器是同一个。所以不管是线程1还是线程2,当他们两个要获取锁的时候,锁监视器都会记录线程ID。当另一个线程再次获取锁时,肯定不行,因为锁监视器已经记录了一个。但是,当我们部署一个新的服务器时,我们部署了一个新的JVM。这两个JVM也有自己的常量池。当JVM2使用userId作为锁时,它的monitor对象会有一个新的锁monitor,和JVM1的monitor是不一样的。现在我们的线程3在获取锁的时候,使用了自己的monitor,monitor显示是空的,所以也可以成功获取到锁。当然,线程4挂掉也没问题。也就是说,JVM内部的锁监视器可以保证这些线程是互斥的,但是多个JVM就会有多个JVM监视器,线程有多少锁监视器就会成功进入同步代码块。所以我们要解决的问题就是让这些锁监视器在多个JVM的情况下使用同一个锁。分布式锁的实现原理以及不同实现方式的比较。synchronized就是利用JVM内部的锁监视器来控制线程。在JVM内部,因为只有一个锁监视器,所以只有一个线程可以获取锁,线程可以实现。阶段是互斥的。但是当有多个JVM时,就会有多个锁监视器。这时候synchronized就会显得苍白,直接让JVM内部的锁监视器失效。所以锁监视器必须在JVM之外,让所有的JVM都能找到一个唯一的锁监视器获取锁,这样只有一个线程获取锁,实现了多个JVM的线程互斥。所以在分布式系统或集群模式下对多线程可见且互斥的锁就是分布式锁。分布式锁的核心是实现多进程之间的互斥,实现方式有很多种,常见的有3种:Mysql和Redis。Redis中有一个setnx互斥命令。wangredis设置数据时,只有在没有数据的时候才设置成功,有数据的时候设置失败。基于Redis实现的分布式锁,分布式锁的实现必须实现两个基本方法,获取锁和释放锁。获取锁互斥条件:保证只有一个线程可以获取锁。非阻塞:尝试一次,成功返回true,失败返回false。这个我们可以使用redis的setnx,可以保证只有一个可以返回1。为了保证原子性,使用EX。Releasethelock手动释放del锁思考问题:如果redis在获取到锁后crash了,那么释放锁的动作永远不会执行,其他线程也无法进入。我的服务已经挂了,整个线程进入死锁状态。所以需要在获取锁的时候加上一个过期时间,避免服务器宕机造成的死锁。Redis分布式锁1.0锁的名称不能硬编码,不同的业务有不同的锁。欢迎关注我的公众号:敲代码的老贾,回复“领取”送《Java面试》信息,阿里、腾讯、字节、美团、饿了么等大厂