``先聊一下概念:
redis雪崩:redis中大面积的key同时过期,导致请求越过redis到mysql 数据库收到高流量冲击,挂掉
redis穿透:redis 和mysql 都不存在查询的key,导致请求越过redis到mysql 数据库收到高流量冲击,挂掉
redis 击穿:redis 中key过期,,导致请求越过redis到mysql 数据库收到高流量冲击,挂掉
如何解决可以利用setnx 命令,下面的demo 用的是springData RedisTemplate
package com.test.one.springboottestpne.utils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* setNx 悲观锁 解决雪崩 击穿 穿透问题
* 事物+监听 解决秒杀 库存卖超问题。
*/
@Component
public class RedisLockTest extends Thread {
@Override
public void run() {
try {
setNx();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Autowired
StringRedisTemplate stringRedisTemplate;
public String setNx() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"开始获取缓存数据");
String key = stringRedisTemplate.opsForValue().get("key");
if (StringUtils.isNotBlank(key)){
System.out.println(Thread.currentThread().getName()+"开始获取缓存数据成功,返回");
return key;
}
System.out.println(Thread.currentThread().getName()+"获取缓存数据失败");
Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("1", "1");
if (aBoolean){
System.out.println(Thread.currentThread().getName()+"拿到锁成功,重新设置缓存");
stringRedisTemplate.expire("1",1, TimeUnit.MINUTES);
//处理业务逻辑
key = stringRedisTemplate.opsForValue().get("key");
if (StringUtils.isNotBlank(key)){
System.out.println(Thread.currentThread().getName()+"---------返回缓存数据");
stringRedisTemplate.delete("1");
return stringRedisTemplate.opsForValue().get("key");
}
//模拟查询数据库
Thread.sleep(2000);
stringRedisTemplate.opsForValue().set("key","11111111");
stringRedisTemplate.delete("1");
System.out.println(Thread.currentThread().getName()+"。。。。。。返回缓存数据");
return stringRedisTemplate.opsForValue().get("key");
}else {
Thread.sleep(500);
setNx();
}
return null;
}
package com.test.one.springboottestpne;
import com.test.one.springboottestpne.utils.RedisLockTest;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(value = {"classpath:application.properties"})
public class RedisTest {
@Autowired
RedisLockTest redisLockTest;
@Test
public void redisLock() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(100);
for (int i = 0;i<100;i++){
executorService.submit(redisLockTest);
}
Thread.sleep(1000000);
}
}
}`