spring整合redis以及优化和内存问题解决

引入

一、单体架构缓存

1.1、使用Map map = new HashMap<k,v>()做本地缓存

1、可以使用Map作为处理缓存问题,因为Map本身就是吧信息存储到内存中的
2、不足之处是当应用是分布式服务,多个微服务,用本地缓存就会出现bug,在某个微服务缓存了数据,负载均衡后可能会切换到别的微服务,这就导致了缓存数据的不一致性
引出了分布式缓存

二、分布式缓存redis

2.1、安装

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.2、yml

spring:
  redis:
    port: 6379
    host: 192.168.182.130

2.3、测试

@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);
    }
}

2.4、内存移除问题解决

如:

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了

分布式并发

原生StringRedisTemplate使用分布式锁
//伪代码
//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.命中直接返回数据

使用Redisson结局分布式缓存击穿问题

见引用博文:

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值