赞
踩
1、可以使用Map作为处理缓存问题,因为Map本身就是吧信息存储到内存中的
2、不足之处是当应用是分布式服务,多个微服务,用本地缓存就会出现bug,在某个微服务缓存了数据,负载均衡后可能会切换到别的微服务,这就导致了缓存数据的不一致性
引出了分布式缓存
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
redis:
port: 6379
host: 192.168.182.130
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class GuliMallApplicationTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test1(){
Integer append = stringRedisTemplate.opsForValue().append("k1", "hello world");
log.info("redis append:{}",append);
}
}
如:
io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 482344960 byte(s) of direct memory (used: 528482304, max: 1006632960)
这样的问题是spring2.0下,redis使用的是letture客户端,手动换成jedis客户端
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
大量并发访问一个不存在的数据,解决:对查询的数据为null也储存到redis中。
大量并发同时发访问多个数据,多个数据并且都过期了,解决:对放入redis中的数据设置随机过期时间。
大量并发访问某个热点数据,且这个热点数据正好过期了,解决:对访问这个数据的服务或者业务加锁lock。
对需要做缓存的业务加锁如: synchronized 、JUC(lock)等
伪代码:
public class ThreadLoclTest{
public Object method(){
synchronized(this){
数据 = 查缓存
if(有缓存数据){
return 数据;
}
数据 = 去db查;
把db查到的数据存到redis中;
return 数据
}
}
}
这里一定注意一定要把db中查到的数据写到锁里面,否则并发会有问题,由于redis存储有网络波动问题,会导致大量并发访问时,可能还没存到redis中,线程就去访问db了
//伪代码 //1.查询是否缓存命中 //2.没有命中则进行分布式锁业务开发 //2.1 分布式锁开发模板 //每个线程唯一的uuid String uuid = UUID.randomUUID().toString(); //redis加锁命令 set lock uuid ex <时间> nx 要满足原子性 Boolean lock1 = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 30, TimeUnit.SECONDS); if (lock1) { //true则抢分布式锁成功 System.out.println("抢占分布式锁成功。。。。。。"); try { //业务 } finally { //lua脚本 释放分布式锁 解锁要满足原子性 String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"; Long lock = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid); } } else { //没抢到锁继续自选抢锁 //todo设置睡眠时间 return 当前方法 } //3.命中直接返回数据
见引用博文:
https://blog.csdn.net/weixin_45031570/article/details/126002868?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126002868%22%2C%22source%22%3A%22weixin_45031570%22%7D&ctrtid=mkGrK
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。