Redis
之持久化与一致性
一、 对象序列化
1.1. 将对象转成JSON
字符串
创建一个实体类:
@Data
public class UserEntity {
private String name;
private String pass;
private Integer age;
}
对象转字符串
@RestController
public class RedisController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/addData")
public String add() {
UserEntity userEntity = new UserEntity();
userEntity.setAge(12);
userEntity.setName("张三");
userEntity.setPass("123456");
stringRedisTemplate.opsForValue().set("user", JSONObject.toJSONString(userEntity));
return "success";
}
}
结果:
1.2. 将对象序列化后存储(二进制)
需要实现序列换接口:
@Data
class UserEntity implements Serializable {
private static final long serialVersionUID = -2700793157456551921L;
private String name;
private String pass;
private Integer age;
}
设置和获取:
@RestController
public class RedisController {
/** 使用@Autowired会报错,使用@Resource通过名字获取注入的类 */
@Resource
private RedisTemplate<String, Object> redisTemplate;
/** 设置 */
@GetMapping("/addData")
public String add() {
UserEntity userEntity = new UserEntity();
userEntity.setAge(12);
userEntity.setName("张三");
userEntity.setPass("123456");
redisTemplate.opsForValue().set("user", userEntity);
return "success";
}
/** 获取 */
@GetMapping("/getDate")
public UserEntity get() {
UserEntity user = (UserEntity) redisTemplate.opsForValue().get("user");
return user;
}
}
结果:
获取:
二、 持久化机制
2.1. 全量同步和增量同步的区别
全量同步: 就是每天定时(避开高峰期)或者采用一个周期实现将数据拷贝到一个地方也就是RDB
存储。
增量同步: 比如采用对行为的操作实现对数据的同步,也就是AOF
。
全量与增量的比较: 增量同步比全量同步更加消耗服务器的内存,但是能够更加的保证数据的同步。
2.2. RDB
和AOF
实现持久化的区别
Redis
提供了两种持久化的机制,分别为RDB
、AOF
实现,RDB
采用定时(全量)持久化机制,但是服务器因为某种原因宕机后可能数据会丢失,AOF
是基于数据日志操作实现的持久化,所以AOF
采用增量同步的方案。
Redis
已经帮助我默认开启了RDB
存储。
2.3. Redis
的RDB
同步配置
开启RDB
同步配置:
# Redis默认采用rdb方式实现数据的持久化,以快照的形式将数据持久化到磁盘的是一个二进制的文件dump.rdb
RDB
相关配置
# Redis会将数据集的快照dump到dump.rdb文件中,可以通过配置文件来修改Redis服务器dump快照的频率.
save 900 1 # 在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 # 在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 # 在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
RDB
同步流程:
2.4. Redis
的AOF
同步配置
AOF
是以执行命令的形式实现同步
开启AOF
同步:
# redis.conf文件中将 appendonly从no改为yes
appendonly yes
AOF
相关配置:
appendfsync always # 每次有数据修改发生时都会写入AOF文件,能够保证数据不丢失,但是效率非常低。
appendfsync everysec # 每秒钟同步一次,可能会丢失1s内的数据,但是效率非常高。
appendfsync no # 从不同步。高效但是数据不会被持久化。
同步流程:
三、Springboot
整合注解版Redis
开启缓冲注解:
@SpringBootApplication
@EnableCaching
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
控制器上使用:
@RestController
public class RedisController {
@GetMapping("/getDate")
@Cacheable(cacheNames = "user", key = "'getDate'")
public UserEntity get() {
UserEntity userEntity = new UserEntity();
userEntity.setAge(12);
userEntity.setName("张三");
userEntity.setPass("123456");
return userEntity;
}
}
这里需要注意,实体类UserEntity
需要实现序列化的接口,因为Redis
注解缓冲使用的二进制对象缓冲,否则会报一下SerializationFailedException
异常:
{
"timestamp":"2019-12-02T15:33:34.162+0000",
"status":500,
"error":"Internal Server Error",
"message":"Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.mly.redis.UserEntity]",
"path":"/getDate"
}
所以实体类需要和上一个例子一样:
class UserEntity implements Serializable {
private static final long serialVersionUID = -2700793157456551921L;
private String name;
private String pass;
private Integer age;
}
四、 一致性解决同步问题
MySQL
与Redis
一致性问题的解决
- 直接清除
Redis
的缓冲,重新读取数据库 - 使用
mq
异步订阅MySQL
的binlog
实现增量同步- 使用
alibaba
的cancal
github
地址:https://github.com/alibaba/canal/wiki
- 使用
五、所有例子的依赖文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>