关于redis堆外内存溢出,以及(穿透雪崩击穿)问题

Posted 记忆未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于redis堆外内存溢出,以及(穿透雪崩击穿)问题相关的知识,希望对你有一定的参考价值。

lettuce堆外内存溢出bug

 

当进行压力测试时后期后出现堆外内存溢出OutOfDirectMemoryError

 

产生原因:

 

1)、springboot2.0以后默认使用lettuce作为操作redis的客户端,它使用netty进行网络通信

 

2)、lettuce的bug导致netty堆外内存溢出。netty如果没有指定堆外内存,默认使用Xms的值,可以使用-Dio.netty.maxDirectMemory进行设置

 

解决方案:

 

由于是lettuce的bug造成,不要直接使用-Dio.netty.maxDirectMemory去调大虚拟机堆外内存,治标不治本。

 

1)、升级lettuce客户端。但是没有解决的

 

2)、切换使用jedis

 

lettuce和jedis是操作redis的底层客户端,RedisTemplate是再次封装

 1  
 2  
 3 <dependency>
 4   <groupId>org.springframework.boot</groupId>
 5   <artifactId>spring-boot-starter-data-redis</artifactId>
 6   <exclusions>
 7     <exclusion>
 8       <groupId>io.lettuce</groupId>
 9       <artifactId>lettuce-core</artifactId>
10     </exclusion>
11   </exclusions>
12 </dependency>
13 <dependency>
14     <groupId>redis.clients</groupId>
15     <artifactId>jedis</artifactId>
16 </dependency>

 

缓存:穿透、雪崩、击穿

 

穿透

 

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

 

解决方案

 

缓存空对象,MVC拦截器

 

雪崩

 

缓存雪崩是指在我们设置缓存时key采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

 

解决方案

 

规避雪崩:缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。

 

如果缓存数据库是分布式部署,将热点数据均匀分布在不同缓存数据库中。

 

设置热点数据永远不过期。

 

出现雪崩:降级 熔断

 

事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。

 

事中:本地ehcache缓存 + hystrix限流&降级,避免mysql崩掉

 

事后:利用 redis 持久化机制保存的数据尽快恢复缓存

 

击穿

 

缓存击穿 指 并发查同一条数据。缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

 

缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

 

解决方案

 

设置热点数据永远不过期。

 

加互斥锁:业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db去数据库加载,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

 

扩展

 

如果是单机服务可以使用 synchronized(this), JUC(look)

 

锁时序问题

 

之前的逻辑是查缓存没有,然后取竞争锁查数据库,这样就造成多次查数据库。

 

解决方法:

 

竞争到锁后,再次确认缓存中没有,再去查数据库。

 

锁竞争模拟,多个服务同事操作同一个命令

 
 
 
 
 
 
 

复制微服务

 
 
 
 
 
 
 

分布式缓存

 

本地缓存问题:每个微服务都要有缓存服务、数据更新时只更新自己的缓存,造成缓存数据不一致

 

解决方案:分布式缓存,微服务共用 缓存中间件

 

分布式项目时,但本地锁只能锁住当前服务,需要分布式锁

 

redis分布式锁的原理:setnx,同一时刻只能设置成功一个

 
 
set 命令 -- Redis中国用户组(CRUG)

redis

 

设置好了锁,玩意服务出现宕机,没有执行删除锁逻辑,这就造成了死锁

 

解决:设置过期时间

 

业务还没执行完锁就过期了,别人拿到锁,自己执行完去删了别人的锁

 

解决:锁续期(redisson有看门狗),。删锁的时候明确是自己的锁。如uuid

 

判断uuid对了,但是将要删除的时候锁过期了,别人设置了新值,那删除了别人的锁