为了保证一个方法在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用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
文章图片
本地配置nginx服务代理 修改nginx配置文件
文章图片
配置nginx经行代理8080端口负载均衡到8081端口和
文章图片
#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
推荐阅读
- Java|使用两个注解,三步完成SpringBoot事件监听(反射,切面实现)
- redis|SpringBoot缓存使用Redis与@CaChe注解整合 简洁使用
- java|一文了解配置中心
- java|SpringCloud笔记一( 跨模块调用,服务注册发现(Eureka、Nacos))
- redis|springboot整合spring @Cache和Redis
- Spring|[01] 使用IDEA搭建SpringCloud项目方法_简单入门
- 物联网|MQTT协议学习总结
- cesium实战|cesium 三维坐标系绘制
- 一文彻底理解BIO、NIO、AIO