企业网站推广方式和策略,软件定制开发如何做,网站页数,做外贸网站的好处集群环境下的秒杀问题
前序
【Redis场景1】用户登录注册
【Redis场景2】缓存更新策略(双写一致)
【Redis场景3】缓存穿透、击穿问题
【Redis场景拓展】秒杀问题-全局唯一ID生成策略
【Redis场景4】单机环境下秒杀问题 在单机环境下的并发问题#xff0c;我们可以使用相关…集群环境下的秒杀问题
前序
【Redis场景1】用户登录注册
【Redis场景2】缓存更新策略(双写一致)
【Redis场景3】缓存穿透、击穿问题
【Redis场景拓展】秒杀问题-全局唯一ID生成策略
【Redis场景4】单机环境下秒杀问题 在单机环境下的并发问题我们可以使用相关锁来解决但是在集群环境中笔者测试通过Nginx做的反向代理和负载均衡请求的时候锁会出现失效的问题。
原因我们部署多个服务(存在多个tomcat服务器)每个tomcat都有一个属于自己的jvm.每个锁在同容器中有效但是跨容器后就无法实现互斥效果。
引出分布式锁
分布式就是指数据和程序可以不位于一个服务器上而是分散到多个服务器以网络上分散分布的地理信息数据及受其影响的数据库操作为研究对象的一种理论计算模型。分布式锁提供了多个服务器节点访问共享资源互斥的一种手段。
一个最基本的分布式锁需要满足
互斥 任意一个时刻锁只能被一个线程持有高可用 锁服务是高可用的。并且即使客户端的释放锁的代码逻辑出现问题锁最终一定还是会被释放不会影响其他线程对共享资源的访问。可重入一个节点获取了锁之后还可以再次获取锁
分布式锁的实现
基于redis中的SETNX 实现分布式锁基于Zookeeper的节点唯一性和有序性实现互斥的分布式锁基于MySQL本身的互斥锁机制
基于Redis的分布式锁
基本实现
GitHub完整代码https://github.com/xbhog/hm-dianping/tree/20230211-xbhog-redisCloud
锁接口实现20230211-xbhog-redisCloud
/*** author xbhog* describe:* date 2023/2/16*/
public interface ILock {boolean tryLock(Long timeOutSec);void unLock();
}加锁解锁实现类
Override
public boolean tryLock(Long timeOutSec) {String threadId ID_PREFIX Thread.currentThread().getId();Boolean isLock stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX keyName, threadId , timeOutSec, TimeUnit.SECONDS);//防止拆箱引发空值异常return Boolean.TRUE.equals(isLock);
}
Override
public void unlock() {//通过del删除锁stringRedisTemplate.delete(KEY_PREFIX name);
}锁误删问题 现在有两个锁线程1获取锁时由于业务的阻塞超时释放了这是线程2开始操作获取锁在线程2执行业务期间线程1业务在一段时间内不阻塞且业务完成这是开始执行释放锁的操作但是这是锁是线程2由此造成锁的误删问题
正确流程 解决的方式
修改之前的分布式锁实现满足在获取锁时存入线程标示可以用UUID表示 在释放锁时先获取锁中的线程标示判断是否与当前线程标示一致
如果一致则释放锁如果不一致则不释放锁
核心逻辑在存入锁时放入自己线程的标识在删除锁时判断当前这把锁的标识是不是自己存入的如果是则进行删除如果不是则不进行删除。
处理流程 代码实现
private static final String ID_PREFIX UUID.randomUUID().toString(true) -;
Override
public boolean tryLock(Long timeOutSec) {String threadId ID_PREFIX Thread.currentThread().getId();Boolean isLock stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX keyName, threadId , timeOutSec, TimeUnit.SECONDS);//防止拆箱引发空值异常return Boolean.TRUE.equals(isLock);
}
Override
public void unLock() {String threadId ID_PREFIX Thread.currentThread().getId();//获取当前分布式锁中的valueString id stringRedisTemplate.opsForValue().get(KEY_PREFIX keyName);//锁相同则删除if(threadId.equals(id)){stringRedisTemplate.delete(KEY_PREFIX keyName);}}