redis缓存基本使用和缓存问题解决

一、缓存

1、缓存使用

为了系统性能的提升,我们一般都会将部分数据放入缓存中,加速访问。而 db 承担数据落盘工作。
哪些数据适合放入缓存?
(1)即时性、数据一致性要求不高的
(2)访问量大且更新频率不高的数据(读多,写少)

举例:电商类应用,商品分类,商品列表等适合缓存并加一个失效时间(根据数据更新频率来定),后台如果发布一个商品,买家需要 5 分钟才能看到新的商品一般还是可以接受的。

伪代码如下:

bash 复制代码
data = cache.load(id);//从缓存加载数据
If(data == null){
	data = db.load(id);//从数据库加载数据
	cache.put(id,data);//保存到 cache 中
}
return data;

注意:在开发中,凡是放入缓存中的数据我们都应该指定过期时间,使其可以在系统即使没有主动更新数据也能自动触发数据加载进缓存的流程。避免业务崩溃导致的数据永久不一致问题。
2、整合 redis 作为缓存
2.1、引入 redis-starter

bash 复制代码
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.2、配置 redis

bash 复制代码
spring:
	redis:
		host: 192.168.56.10
		port: 6379

3、使用 RedisTemplate 操作 redis

bash 复制代码
	@Autowired
	StringRedisTemplate stringRedisTemplate;
	@Test
	public void testStringRedisTemplate(){
		ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
		ops.set("hello","world_"+ UUID.randomUUID().toString());
		String hello = ops.get("hello");
		System.out.println(hello);
	}

4、切换使用 jedis

为什么要切换?

产生堆外内存溢出OutOfDirectMemoryError:

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

2)、lettuce的bug导致netty堆外内存溢出 可设置:-Dio.netty.maxDirectMemory

解决方案:不能直接使用-Dio.netty.maxDirectMemory去调大堆外内存

1)、升级lettuce客户端。 2)、切换使用jedis

bash 复制代码
<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>

二、缓存失效问题

先来解决大并发读情况下的缓存失效问题;
1、缓存穿透

1.1 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中,将去查询数据库,但是数据库也无此记录,我们没有将这次查询的null写入缓存 ,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

1.2 风险:利用不存在的数据进行攻击,数据库瞬时压力增大,最终导致崩溃。
1.3 解决:
缓存空结果、并且设置短的过期时间

2、缓存雪崩

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

2.2 解决:
原有的失效时间基础上增加一个随机值 ,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低 ,就很难引发集体失效的事件。
3、缓存击穿

3.1 对于一些设置了过期时间的 key,如果这些 key 可能会在某些时间点被超高并发地访问,是一种非常"热点"的数据。

3.2 这个时候,需要考虑一个问题:如果这个 key 在大量请求同时进来前正好失效,那么所有对这个 key 的数据查询都落到 db,我们称为缓存击穿。

3.3 解决:

加锁

大量并发只让一个去查,其他人等待,查到以后释放锁其他人获取到锁,先查缓存,就会有数据,不用去db
总结

1、空结果缓存,解决缓存穿透

2、设置过期时间(加随机值),解决缓存雪崩

3、加锁,解决缓存击穿

相关推荐
IvorySQL1 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·1 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德1 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫1 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i2 小时前
完全卸载MariaDB
数据库·mariadb
期待のcode2 小时前
Redis的主从复制与集群
运维·服务器·redis
纤纡.2 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn2 小时前
【Redis】渐进式遍历
数据库·redis·缓存
橙露2 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot
冰暮流星2 小时前
sql语言之分组语句group by
java·数据库·sql