Java|基于SpringBoot和Redis(Redisson的分布式锁的使用)

为了保证一个方法在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用Java并发处理相关的API(如ReentrantLcok或synchronized)进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。


基于SpringBoot和Redis:Redisson的分布式锁的使用

  • Github下载地址
  • 分布式的三大特性 CAP
    • Consistency (一致性)
    • Availability (可用性)
    • Partition Tolerance (分区容错性)
  • 利用nginx创建本地分布式系统
    • 下载安装nginx服务
    • 本地配置nginx服务代理
    • nginx启动
  • 基于redisson实现分布式锁
    • 配置redisson
    • lock-unlock
    • semaphore
    • 读写锁
    • 红锁
  • 进行测试

Github下载地址 Github下载地址点击跳转
分布式的三大特性 CAP Consistency (一致性) 【Java|基于SpringBoot和Redis(Redisson的分布式锁的使用)】所有节点在同一时间的数据完全一致,这就是分布式的一致性。一致性的问题在并发系统中不可避免,对于客户端来说,一致性指的是并发访问时更新过的数据如何获取的问题。从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致。
Availability (可用性) 即服务一直可用,而且是正常响应时间。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。
Partition Tolerance (分区容错性) 即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。
分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的整体。比如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,对于用户而言并没有什么体验上的影响。
利用nginx创建本地分布式系统 下载安装nginx服务 nginx官网https://nginx.org/en/download.html
Java|基于SpringBoot和Redis(Redisson的分布式锁的使用)
文章图片

本地配置nginx服务代理 修改nginx配置文件
Java|基于SpringBoot和Redis(Redisson的分布式锁的使用)
文章图片

配置nginx经行代理8080端口负载均衡到8081端口和
Java|基于SpringBoot和Redis(Redisson的分布式锁的使用)
文章图片

#IIS配置多台Server,weight是权重,权重越大,被访问的几率越大 upstream tomcatserver{ server 127.0.0.1:8081 weight=1; server 127.0.0.1:8082 weight=1; } location / { roothtml; indexindex.html index.htm; proxy_pass http://tomcatserver; }

nginx启动 nginx安装目录下启动cmd
nginx -s reload 重新读取配置文件
start nginx启动
基于redisson实现分布式锁 配置redisson
package com.mabo.redis; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; @Configuration public class RedissonConfig { /** * @Author mabo * @Description获取redis连接对象 */@Bean() public RedissonClient redisson() throws IOException { //1.创建配置 Config config = new Config(); //2.根据 Config 创建出 RedissonClient 示例。 config.useSingleServer().setAddress("redis://127.0.0.1:6379"); return Redisson.create(config); } }

lock-unlock 使用过程和java锁的lock基本一致,java多线程锁的相关使用详情请见此处点击跳转
package com.mabo.redis.lockAndUnlock; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.concurrent.TimeUnit; @Controller public class LockTest { static inta=0; @Autowired RedissonClient redissonClient; @ResponseBody @RequestMapping(value = "https://www.it610.com/hello",produces = "application/json") public String hello(HttpServletRequest request) throws IOException, InterruptedException { RLock lock = redissonClient.getLock("lock"); try { // 2.加锁 boolean res = lock.tryLock((long)30, (long)10, TimeUnit.SECONDS); if (res) { //成功获得锁,在这里处理业务 a++; System.out.println(a); } } catch (Exception e) { //TODO } finally { lock.unlock(); } return "test lock ok"; } }

semaphore
package com.mabo.redis.semaphore; import org.redisson.api.RSemaphore; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; @Controller public class SemaphoreLock {@Autowired RedissonClient redissonClient; @Autowired RedisTemplate redisTemplate; @ResponseBody @RequestMapping(value = "https://www.it610.com/addSemaphore",produces = "application/json") public String addSemaphore(HttpServletRequest request) throws InterruptedException { Object semaphore1 = redisTemplate.boundValueOps("semaphore").get(); if (semaphore1==null){ redisTemplate.boundValueOps("semaphore").set(2); } RSemaphore semaphore = redissonClient.getSemaphore("semaphore"); semaphore.acquire(); return semaphore1.toString(); } @RequestMapping(value = "https://www.it610.com/decSetSemaphore",produces = "application/json") public String decSetSemaphore(HttpServletRequest request) throws InterruptedException { Object semaphore1 = redisTemplate.boundValueOps("semaphore").get(); RSemaphore semaphore = redissonClient.getSemaphore("semaphore"); semaphore.release(); return "decSetSemaphore"; }}

读写锁
package com.mabo.redis.readWriteLock; import org.redisson.api.RLock; import org.redisson.api.RReadWriteLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class ReadLock { @Autowired RedissonClient redissonClient; @Autowired private RedisTemplate redisTemplate; @ResponseBody @RequestMapping(value = "https://www.it610.com/read",produces = "application/json") public String read(){ RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock"); //读之前加读锁,读锁的作用就是等待该lockkey释放写锁以后再读 RLock rLock = readWriteLock.readLock(); try { rLock.lock(); Object o = redisTemplate.boundValueOps("1").get(); inta = (int)o; System.out.println(a); //TimeUnit.SECONDS.sleep(2); returnString.valueOf(a); } catch (Exception e) { e.printStackTrace(); return null; } finally { rLock.unlock(); } }}

package com.mabo.redis.readWriteLock; import org.redisson.api.RLock; import org.redisson.api.RReadWriteLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class WriteLock { @Autowired RedissonClient redissonClient; @Autowired private RedisTemplate redisTemplate; @ResponseBody @RequestMapping(value = "https://www.it610.com/write",produces = "application/json") public String read(){ RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock"); //读之前加读锁,读锁的作用就是等待该lockkey释放写锁以后再读 RLock wLock = readWriteLock.writeLock(); try { inta=0; wLock.lock(); Object o = redisTemplate.boundValueOps("1").get(); if (o==null){ redisTemplate.boundValueOps("1").set(0); } else { a = (int)o; a++; redisTemplate.boundValueOps("1").set(a); } //TimeUnit.SECONDS.sleep(10); return String.valueOf(a); } catch (Exception e) { e.printStackTrace(); return null; } finally { wLock.unlock(); }} }

红锁
package com.mabo.redis.redissonRedLock; import org.redisson.RedissonRedLock; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.concurrent.TimeUnit; @Controller public class RedissonRedLockTest { @Autowired RedissonClient redissonClient; @ResponseBody//连续在浏览器输入三个当前路径,就可以发现第三个执行需要15秒,加锁成功 @RequestMapping(value = "https://www.it610.com/redLock",produces = "application/json") public String redLock() { RLock lock1 = redissonClient.getLock("lock1"); RLock lock2 = redissonClient.getLock("lock2"); RLock lock3 = redissonClient.getLock("lock3"); RedissonRedLock redLock=new RedissonRedLock(lock1,lock2,lock3); try { redLock.tryLock(10, TimeUnit.SECONDS); TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }finally { redLock.unlock(); } return "redLock"; } }

进行测试 在浏览器输入localhost:8080+路径 即可看到效果,这里主要测试后端的分布式服务
例如localhost:8080/hello

    推荐阅读