目录
Redis在项目中的应用
做缓存(以SpringBoot项目中Redis做缓存为例)
RedisTemplate方法
使用Spring Cache注解来管理缓存的方式
缓存穿透
缓存雪崩
缓存和数据库中的数据一致性问题
Redis本身特性
Redis内存淘汰机制
allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
Redis中的持久化方式
快照(snapshotting)持久化(RDB)
AOF(append-only file)持久化
添加依赖:在项目的构建文件(如pom.xml
)中添加Spring Data Redis的依赖。
配置Redis连接信息:在配置文件(如application.properties
或application.yml
)中配置Redis的连接信息,包括主机、端口、密码等。
创建配置类:创建一个Java配置类,用于配置RedisTemplate
和相关的连接工厂、序列化器等。
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
// 配置Redis连接工厂
RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration();
standaloneConfig.setHostName("redisHost");
standaloneConfig.setPort(6379);
standaloneConfig.setPassword(RedisPassword.of("redisPassword"));
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(standaloneConfig);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 配置RedisTemplate
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setDefaultSerializer(new StringRedisSerializer());
redisTemplate.setKeySerializer(redisTemplate.getStringSerializer());
redisTemplate.setValueSerializer(redisTemplate.getDefaultSerializer());
redisTemplate.setHashKeySerializer(redisTemplate.getStringSerializer());
redisTemplate.setHashValueSerializer(redisTemplate.getDefaultSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
4. 创建Service类:在Service类中注入RedisTemplate
,并根据具体需求编写相应的缓存操作方法。
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Autowired
private RedisTemplate redisTemplate;
public Product getProductById(Long id) {
String cacheKey = "product:" + id;
// 先尝试从缓存中获取产品
Product product = (Product) redisTemplate.opsForValue().get(cacheKey);
// 如果缓存中不存在,则从数据库中获取并放入缓存
if (product == null) {
product = productRepository.findById(id);
redisTemplate.opsForValue().set(cacheKey, product);
}
return product;
}
public Product saveProduct(Product product) {
Product savedProduct = productRepository.save(product);
String cacheKey = "product:" + savedProduct.getId();
// 更新或新增缓存数据
redisTemplate.opsForValue().set(cacheKey, savedProduct);
return savedProduct;
}
public void deleteProduct(Long id) {
productRepository.deleteById(id);
String cacheKey = "product:" + id;
// 删除对应的缓存数据
redisTemplate.delete(cacheKey);
}
public Product updateProduct(Product product) {
Product updatedProduct = productRepository.save(product);
String cacheKey = "product:" + updatedProduct.getId();
// 更新缓存中的数据
redisTemplate.opsForValue().set(cacheKey, updatedProduct);
return updatedProduct;
}
}
添加Redis依赖:在pom.xml
文件中添加Redis相关依赖,例如spring-boot-starter-data-redis
。
配置Redis连接信息:在application.properties
(或application.yml
)文件中配置Redis连接信息,包括主机、端口、密码等。
创建Redis配置类:创建一个Java配置类,用于配置Redis连接工厂、缓存管理器等Redis相关的配置项。这个类通常使用@Configuration
注解标记。
启用缓存功能:在主类中添加@EnableCaching
注解启用Spring Cache,这样可以使用缓存注解来管理缓存。
定义缓存操作方法:在需要缓存的方法上添加缓存注解,例如@Cacheable
、@CachePut
、@CacheEvict
等,定义缓存的读取、更新和清除规则。
下面代码是一个简单的流程:
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 创建 Redis 缓存配置实例
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)); // 设置缓存的过期时间为 10 分钟
// 创建 Redis 缓存管理器,并关联 Redis 连接工厂和默认缓存配置
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(cacheConfiguration)
.build();
}
}
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Cacheable(value="products", key="#id")
public Product getProductById(Long id) {
// 从缓存中获取指定 id 的 Product 对象,如果缓存中不存在,则通过调用 productRepository.findById(id) 方法获取数据,并将数据放入缓存中
return productRepository.findById(id);
}
@CachePut(value="products", key="#product.id")
public Product saveProduct(Product product) {
// 将传入的 Product 对象保存到数据库中,并更新缓存中的数据或新增缓存数据(根据 key 的存在与否判断)
return productRepository.save(product);
}
@CacheEvict(value="products", key="#id")
public void deleteProduct(Long id) {
// 删除指定 id 的 Product 对象,并删除缓存中对应的数据
productRepository.deleteById(id);
}
@CachePut(value="products", key="#product.id")
public Product updateProduct(Product product) {
// 直接更新数据库中的 Product 对象,并更新缓存中对应的数据
return productRepository.save(product);
}
}
做验证码功能
做session共享,分布式Session存储,相对普通session的优势
数据结构:
地理位置:
Redis提供了6种内存淘汰机制:
volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
Redis4.0 版本后增加了以下两种:
volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key
Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。
快照持久化是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置:
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
根据配置,快照将被写入dbfilename选项指定的文件里面,并存储在dir选项指定的路径上面。如果在新的快照文件创建完毕之前,Redis、系统或者硬件这三者中的任意一个崩溃了,那么Redis将丢失最近一次创建快照写入的所有数据。
举个例子:假设Redis的上一个快照是2:35开始创建的,并且已经创建成功。下午3:06时,Redis又开始创建新的快照,并且在下午3:08快照创建完毕之前,有35个键进行了更新。如果在下午3:06到3:08期间,系统发生了崩溃,导致Redis无法完成新快照的创建工作,那么Redis将丢失下午2:35之后写入的所有数据。另一方面,如果系统恰好在新的快照文件创建完毕之后崩溃,那么Redis将丢失35个键的更新数据。
与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
appendonly yes
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。
举个例子,比如当你向Redis执行以下写指令时
SET key1 value1
SET key2 value2
这些命令将会被追加到AOF文件的末尾,使得AOF文件变为:
*3
$3
SET
$4
key1
$6
value1
*3
$3
SET
$4
key2
$6
value2
AOF(append-only file)始终都是一个文件,在这个文件中持续地追加所执行过的指令。
AOF持久化机制通过记录每个写命令的方式来保存数据库的状态。当Redis服务器接收到写命令时,它会将命令追加到AOF文件的末尾,形成一个有序的命令日志。
在Redis的配置文件中存在三种同步方式,它们分别是:
appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no #让操作系统决定何时进行同步
appendfsync always 可以实现将数据丢失减到最少,不过这种方式需要对硬盘进行大量的写入而且每次只写入一个命令,十分影响Redis的速度。另外使用固态硬盘的用户谨慎使用appendfsync always选项,因为这会明显降低固态硬盘的使用寿命。
为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec选项 ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。
appendfsync no 选项一般不推荐,这种方案会使Redis丢失不定量的数据而且如果用户的硬盘处理写入操作的速度不够的话,那么当缓冲区被等待写入的数据填满时,Redis的写入操作将被阻塞,这会导致Redis的请求速度变慢。
虽然AOF持久化非常灵活地提供了多种不同的选项来满足不同应用程序对数据安全的不同要求,但AOF持久化也有缺陷——AOF文件的体积太大。