Redis基础
一、Redis入门
1.1 Redis简介
- Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. 翻译为:Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存等。
- Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到10万+的QPS(Queries-per-second每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。
- NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库(数据之间没有关系)。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。
- redis是C语言开发,安装redis需要先将官网下载的源码进行编译,编译依赖gcc环境。如果没有gcc环境,需要安装gcc。
1.2 Redis服务常用口令
1.2.1 启动相关口令
- 前端模式启动(不使用这种模式)
直接运行bin/redis-server以前端模式启动,前端模式启动的缺点是启动完成后,不能再进行其他操作,如果要操作必须使用ctrl+c,同时redis-server程序结束,不推荐使用此方法。
./redis-server
- 后端模式启动(推荐使用)
修改redis.conf配置文件,修改daemonize yes 以后端模式启动。daemonize:后台运行
vim redis.conf
- 启动时,指定配置文件
cd /usr/local/soft/redis/bin
./redis-server redis.conf
- 查看启动的后台进程
ps -aux | grep redis
- redis启动客户端
- 进入redis/bin目录,启动"redis-cli"
./redis-cli
- 停止redis
- 在客户端向Redis发送shutdown命令
- 在Redis客户端里面输入shutdown
1.3 Redis可视化工具
通过上述演示我们发现通过命令行可以连接redis数据库服务器,但是在命令行中操作redis稍微麻烦一些。我们平时可以使用可视化工具操作redis服务器。
使用Redis Desktop Manager 软件,安装后创建连接就可以看到redis里面的表和数据
二、Redis数据类型
2.1 数据类型介绍
Redis的5种数据类型
redis是一种高级的key-value的存储系统,键是string类型,其中value支持五种数据类型,对于键和值的描述如下所示:
- 键(key):
- 键不能重复
- 作用:标识存储的数据
- 数据类型:string
- 命名规则:
- 不能太长:因为查询的效率低,查询起来不方便
- 不能太短:容易重复,同时可读性也差
- 按照规范:HEIMA_STU_LIST
- 值(value):支持5种数据类型
|值的数据类型| 值的格式说明|
|--|---|
|string |字符串类型,类似于Java中String|
|hash |由键值对组成,类似于Java中Map|
|list |列表类型,类似于Java中List,元素是存取有序,可以重复。|
|set |集合类型,类似于Java中Set,元素是存取无序,不可重复|
|sorted set/zset |有序的集合类型,每个元素有一个分数用来决定它的顺序。|
2.2 string类型
字符串类型是Redis中最为基础的数据存储类型,它在Redis中以二进制保存。无论存入的是字符串、整数、浮点类型都会以字符串写入。
在Redis中字符串类型的值最多可以容纳的数据长度是512M,是最常用的类型·
2.2.1 常用命令
命令 | 功能 |
---|---|
set 键 值 | 添加或修改一个键和值,键不存在就是添加,存在就是修改 |
get 键 | 获取值,如果存在就返回值,不存在返回nil(就是C语言中NULL) |
del 键 | 删除指定的键和值,返回删除的个数 |
SETEX key seconds value | 设置指定key的值,并将 key 的过期时间设为 seconds 秒。此处的value是指key对应的value值。等价于:SET key value ex seconds |
EXPIRE key seconds | 如果一个key已经存在,要设置一个过期时间 |
SETNX key value/set key value nx | 保存键值对,如果key存在则不保存,不存在则保存 |
MGET key1 [key2..] | 获取所有(一个或多个)给定 key 的值 |
使用场景举例:
- 用户登录后端保存短信验证码,并设置失效时间;
- 代替后端session功能,实现分布式缓存(是将数据分散存储在多台独立的设备上)等;
2.3 hash类型
Redis中的Hash类型可以看成是键和值都是String类型的Map容器,每一个Hash可以存储4G个键值对。
该类型非常适合于存储对象的信息。如一个用户有姓名,密码,年龄等信息,则可以有username、password和age等键。它的存储结构如下:
2.3.1 常用命令
命令 | 功能 |
---|---|
hset 键 字段 值 | 添加键,字段,值 |
hget 键 字段 | 通过键,字段得到值 |
hmset 键 字段 值 字段 值 | multiply多个,一次添加多个字段和值 |
hmget 键 字段 字段 | 通过键,获取多个字段和值 |
hdel 键 字段 字段 | 删除一个或多个字段的值 |
hgetall 键 | 得到这个键下所有的字段和值 |
HKEYS 键 | 获取哈希表中所有字段 |
HVALS 键 | 获取哈希表中所有值 |
Hash数据结构的应用场景:
- 购物车
以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素,如下图所示
2.4 list类型
在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其左部(left)和右部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4G个。
2.4.1 常用命令
命令 | 行为 |
---|---|
lpush 键 元素 元素... | left 从左边向指定的键中添加1个或多个元素,返回列表中元素的个数 |
rpush 键 元素 元素... | right 从右边向指定的键中添加1个或多个元素 |
lpop 键 | 从左边删除一个元素,返回被删除的元素 |
rpop 键 | 从右边删除一个元素,返回被删除的元素 |
lrange 键 开始 结束 | 得到键中指定范围的元素的数据 每个元素都有一个索引号,从左向右0~n 从右向左索引号:-1~-(n+1),每个元素有2个索引号 如果要取出整个列表中所有的元素,索引号应该是:0~-1 |
lindex 键 索引值 | 查询指定索引的元素 |
llen 键 | 获取列表的长度 |
BRPOP key1 [key2 ] timeout | 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止,超时时间单位默认是秒 |
LREM key | 删除元素个数 value值 从表头删除指定个数的元素 |
使用场景:
- 微信朋友圈点赞,要求按照点赞顺序显示点赞好友信息。如果取消点赞,移除对应好友信息。
- list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中,如京东每日的手机销量排行、学校每次月考学生的成绩排名等,
2.5 set类型
在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。Set可包含的最大元素数量是4G,和List类型不同的是,Set集合中不允许出现重复的元素。
2.5.1 常用命令
命令 | 行为 |
---|---|
sadd 键 元素 元素... | 向一个键中添加1个或多个元素 |
smembers 键 | 得到这个集合中所有的元素 |
sismember 键 元素 | 判断指定的元素在集合中是否存在,存在返回1,不存在返回0 |
srem 键 元素 元素... | 通过键删除一个或多个元素 |
sinter key1 [key2] | 返回给定所有集合的交集(集合中都共有的部分) |
应用场景:
- 需要去重的少量信息,比如:身份证信息、手机号码等作为黑名单|白名单;
- 共同好友查询,使用set的交集;
- eg: zhang:{11,22,33,44} lisi:{22,33,66,88}
- zhangsan和lisi共同的好友:交集取22 33即可.
2.6 zset/sortedset类型
Redis 有序集合(sorted set)和set集合一样也是无序不可以重复。不同的是每个元素都会关联一个分数(排序因子)。
redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复,每个集合可存储40多亿个成员。
2.6.1 常用命令
命令 | 行为 |
---|---|
zadd 键 分数 值 分数 值 | 添加1个或多个元素,每个元素都有一个分数 |
zrange 键 开始索引 结束索引 | 获取指定范围的元素,得到所有的元素,索引是0到-1 |
zrange 键 开始索引 结束索引 | withscores 查询指定的元素和对应的分数 |
zrevrange 键 开始索引 结束索引 | withscores 按照分数倒叙获取指定的元素和对应的分数 |
zrem 键 值 值 | 删除一个或多个值 |
zcard 键 | 得到元素个数 |
zrank 键 值 | 得到元素的索引号 |
zscore 键 值 | 得到元素的分数 |
应用场景:
- b站视频点击量排名
- 新浪热点文章点击量、收藏量等排名
三、Redis的其他操作
3.1 Redis的通用命令
命令 | 功能 |
---|---|
keys 匹配字符 | 查询所有的键,可以使用通配符 * 匹配多个字符 ? 匹配1个字符 |
del 键1 键2 | 删除任何的值类型,而且可以同时删除多个键 |
exists 键 | 判断指定的键是否存在,不存在返回0 存在返回1 |
type 键 | 判断指定的键,值的类型。返回是类型的名字 |
select 数据库编号 | 选择其它的数据库 |
move 键 数据库编号 | 将当前数据库中指定的键移动到另一个数据库中 |
TTL key | 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位 从Redis2.8开始:如果key不存在或者已过期,返回-2;如果key存在并且没有设置过期时间(永久有效),返回-1 |
flushall | redis的flushall命令用来清空redis所有的库,测试可以使用,开发中最好不要用。 |
3.2 在Java中操作Redis
Redis 的 Java 客户端很多,官方推荐的有三种:
- Jedis
- Lettuce
- Redisson
Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-boot-starter-data-redis。
3.2.1 Jedis
Jedis 是 Redis 的 Java 版本的客户端实现。
maven坐标:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
使用 Jedis 操作 Redis 的步骤:
- 获取连接
- 执行操作
- 关闭连接
Jedis类常用方法:每个方法就是redis中的命令名,方法的参数就是命令的参数
在每次访问Redis数据库的时候,都需要创建一个Jedis对象。每个Jedis对象似于JDBC中Connection对象,类似于mybatis中session对象。
连接和关闭 | 功能 |
---|---|
new Jedis(host, port) | 创建Jedis连接对象,参数: host: 服务器地址 port:端口号6379 |
void close() | 关闭连接 |
对string操作的方法 | 说明 |
---|---|
set(String key,String value) | 添加字符串类型的键和值 |
String get(String key) | 通过键得到字符串的值 |
del(String ... keys) | 删除一个或多个键 |
mset(key1,value1,key2,value2,...) | 一次性添加多个字符串数据, |
List<String> mget(key1,key2,key3...) | 一次性获取所有的字符串 |
对hash操作的方法 | 说明 |
---|---|
hset(String key,String field,String value) | 添加一个hash类型的键,字段和值 |
hset(key, map集合) | 向hash中添加多个数据 |
Map<String,String> hgetall(String key) | 通过一个键得到所有的字段和值,返回Map |
对list操作的方法 | 说明 |
---|---|
lpush(String key,String...values) | 从左边添加多个值到list中 |
List<String> lrange(String key,long start,long end) | 通过键得到指定范围的元素 |
对set操作的方法 | 说明 |
---|---|
sadd(String key,String...values) | 添加一个或多个元素 |
Set<String> smembers(String key) | 通过键得到集合所有的元素 |
对zset操作的方法 | 说明 |
---|---|
zadd(String key, double score, String member) | 添加一个键,分数和值 |
Set<String> zrange(String key, long start, long end) | 查询一个指定范围的元素 |
3.3 SpringDataRedis(掌握)
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
网址:Spring Data Redis
接口对象:
- redisTemplate.opsForHash()
- redisTemplate.opsForValue()
- redisTemplate.opsForList()
- redisTemplate.opsForZSet()
- redisTemplate.opsForSet()
maven坐标:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.4.8</version>
</dependency>
Spring Boot提供了对应的Starter,maven坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对类似 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
- ValueOperations:简单K-V操作(String类型)
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对hash类型的数据操作
- ListOperations:针对list类型的数据操作
使用步骤:
导入对应maven坐标 --> 在application.yml文件配置相关信息 --> 在容器中取到redisTemplate类型为RedisTemplate --> 操作方法
配置:
spring:
#Redis相关配置
redis:
host: 192.168.200.128 # 连接linux系统的redis
port: 6379 # 端口号
database: 0 #操作的是0号数据库
#spring.redis.database:指定使用Redis的哪个数据库,Redis服务启动后默认有16个数据库,编号分别是从0到15。可以通过修改Redis配置文件来指定数据库的数量。
因为默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别。如果我们想要存储的key是正常的key,我们可以重写配置类
tips:这里的重写是指 Spring Boot 框架会自动装配 RedisTemplate 对象,但是我们要修改默认的key序列化器所以重写这个配置类,springboot的就不会生效
/**
* Redis配置类
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/*
1.RedisConnectionFactory 是获取RedisConnection对象的,RedisConnection相当于jdbc中的连接对象Connection表示和
Redis进行连接
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
//创建Redis模板对象
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
//默认的Key序列化器为:JdkSerializationRedisSerializer
//StringRedisSerializer支持字符串类型的转化,而且默认使用UTF-8编码
//下面代码的意思是使用StringRedisSerializer序列化器替换默认的Key序列化器JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
3.3.1 String操作
常见命令:
- set 键 值 -- set()
- get 键 -- get()
- del 键
/**
* 操作String类型的数据
*/
@Test
public void test01String(){
//获取操作String类型的接口对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//存值
valueOperations.set("city123","beijing");
//取值
String value = (String) valueOperations.get("city123");
System.out.println(value);
//存值,同时设置过期时间 TimeUnit:超时时间单位
/*
void set(K key, V value, long timeout, TimeUnit unit);
key :字段key
value:key对应的值
timeout:超时时间
TimeUnit:超时时间单位
*/
valueOperations.set("username","suoge",10, TimeUnit.SECONDS);
//存值,如果存在则不执行任何操作
Boolean aBoolean = valueOperations.setIfAbsent("city1234", "nanjing");
System.out.println(aBoolean);
}
3.3.2 hash操作
常见操作:
- hset 键 字段 值 -- put()
- hget 键 值
- hmset 键 字段 值 字段 值
- hmget 键 字段 字段
- hdel 键 字段 字段
- hgetall 键
/**
* 操作Hash类型数据
*/
@Test
public void testHash(){
//获取操作Hash类型的接口对象
HashOperations hashOperations = redisTemplate.opsForHash();
//存值 下面的代码相当于命令:hset person name xiaoming
//pseron表示键,name表示字段名 xiaoming表示字段值
hashOperations.put("person","name","xiaoming");
hashOperations.put("person","age","20");
hashOperations.put("person","address","bj");
//取值
//下面的代码相当于执行命令:hget 键 字段===》hget person age===>表示根据键和字段名获取字段值
String age = (String) hashOperations.get("person", "age");
System.out.println(age);
//获得hash结构中的所有字段
//下面的代码相当于执行命令:HKEYS 键===》HKEYS person
Set keys = hashOperations.keys("person");
for (Object key : keys) {
System.out.println(key);
}
//获得hash结构中的所有值
//HVALS 键
List values = hashOperations.values("person");
for (Object value : values) {
System.out.println(value);
}
}
3.3.3 list操作
/**
* 操作List类型的数据
*/
@Test
public void testList(){
//获取操作列表类型的接口对象
ListOperations listOperations = redisTemplate.opsForList();
//存值
//命令lpush 键 元素 元素...
listOperations.leftPush("mylist","a");
listOperations.leftPushAll("mylist","b","c","d");
//取值
//命令:lrange 键 开始 结束
//下面的代码是查询所有
List<String> mylist = listOperations.range("mylist", 0, -1);
for (String value : mylist) {
System.out.println(value);
}
//获得列表长度 命令:llen 键
Long size = listOperations.size("mylist");
for (int i = 0; i < size; i++) {
//出队列
//命令:rpop 键
//从右边删除一个元素,返回被删除的元素
String element = (String) listOperations.rightPop("mylist");
System.out.println(element);
}
}
3.3.4 set集合操作
/**
* 操作Set类型的数据
*/
@Test
public void testSet(){
//获取操作set类型的接口对象
SetOperations setOperations = redisTemplate.opsForSet();
//存值
//sadd 键 元素 元素...
setOperations.add("myset","a","b","c","a");
//取值
//smembers 键 : 得到这个集合中所有的元素
Set<String> myset = setOperations.members("myset");
for (String o : myset) {
System.out.println(o);
}
//删除成员
//srem 键 元素 元素...
setOperations.remove("myset","a","b");
//取值
myset = setOperations.members("myset");
for (String o : myset) {
System.out.println(o);
}
}
3.3.5 zset集合操作
/**
* 操作ZSet类型的数据
*/
@Test
public void testZset(){
//获取操作zSet类型的接口对象
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
//存值
//Boolean add(K var1, V var2, double var3) var1 表示键 var2 表示值 var3表示分数
zSetOperations.add("myZset","a",10.0);//myZset 表示键 a 表示值 10.0 表示分数
zSetOperations.add("myZset","b",11.0);
zSetOperations.add("myZset","c",12.0);
zSetOperations.add("myZset","a",13.0);
//取值
//命令:zrange 键 开始索引 结束索引
//获取指定范围的元素,得到所有的元素,索引是0到-1
Set<String> myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println(s);
}
//修改分数
//下面的方法表示在原来分数上进行加20
zSetOperations.incrementScore("myZset","c",20.0);
//删除成员
zSetOperations.remove("myZset","a","b");
//取值
Set<ZSetOperations.TypedTuple> myZset = zSetOperations.rangeWithScores("myZset", 0, -1);
for (ZSetOperations.TypedTuple typedTuple : myZset) {
Double score = typedTuple.getScore();
Object value = typedTuple.getValue();
System.out.println(score+"---"+value);
}
}
3.3.6 通用操作
/**
* 通用操作,针对不同的数据类型都可以操作
*/
@Test
public void testCommon(){
//获取Redis中所有的key
Set<String> keys = redisTemplate.keys("*");
for (String key : keys) {
System.out.println(key);
}
//判断某个key是否存在
Boolean itcast = redisTemplate.hasKey("itcast");
System.out.println(itcast);
//删除指定key
redisTemplate.delete("myZset");
//获取指定key对应的value的数据类型
DataType dataType = redisTemplate.type("myset");
System.out.println(dataType.name());
}
3.3.7 整合连接池
关于redis连接池并没有什么效果,配置好之后会优化获取连接性能
pom引入依赖:
<!-- redis创建连接池,默认不会创建连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置连接池
# 配置redis环境
spring:
redis:
# 默认连接本地localhost,如果仅仅连接本地redis服务,则可不写
host: 192.168.200.128
# 默认端口是6379,则省略不写
port: 6379
# redis实例中分为16分片库,索引位从0~15,默认操纵的是0
database: 0
lettuce:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 1 # 连接池中的最小空闲连接
-
四、Redis持久化机制
4.1 Redis持久化
Redis是一个内存存储的数据库,内存必须在通电的情况下才能够对数据进行存储。如果 ,在使用redis的过程中突然发生断电,数据就会丢失。为了防止数据丢失,redis提供了数据持久化的支持。
redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化。redis支持两种持久化方式,一种是RDB(快照)也是默认方式,另一种是Append Only File(缩写AOF)的方式。
Redis持久化的两种方式:
- RDB:Redis DataBase 默认的持久化方式,以二进制的方式将数据写入文件中。每隔一段时间写入一次。
- AOF:Append Only File 以文本文件的方式记录用户的每次操作,数据还原时候,读取AOF文件,模拟用户的操作,将数据还原。
4.2 RDB持久化介绍
RDB是默认的持久化方式。这种方式就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为:dump.rdb。
可以通过配置设置自动做快照持久化的方式。如下面配置的是RDB方式数据持久化时机,必须两个条件都满足的情况下才进行持久化的操作:
关键字 时间(秒) | 修改键数 | 解释 |
---|---|---|
save | 900 | 1 |
save | 300 | 10 |
save | 60 | 10000 |
缺点:
可能导致数据丢失。因为RDB是每隔一段时间写入数据,所以系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
优点:
持久化效率高,持久化的是内存中的数据
数据库宕机后,数据恢复的效率要更高;
4.3 AOF的存储方式
- 由于快照方式是在一定间隔时间做一次的,所以如果redis宕机,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用AOF持久化方式。
- AOF指的是Append only file,使用AOF持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是appendonly.aof).当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
- AOF指的是Append only file,使用AOF持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是appendonly.aof).当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。也可以通过该文件完成数据的重建。该机制可以带来更高的数据安全性,所有的操作都是异步完成的。
|Redis中提供了3种同步策略| 说明|
|-|-|
|每秒同步| 每过一秒记录一次|
|每修改同步 |每次修改(增删改)都会记录一次|
|不同步 |由系统记录操作|
AOF默认是关闭的,首先需要开启AOF模式
appendonly no/yes 默认是no,关闭。如果要打开,设置成yes。
AOF持久化时机
关键字 | 持久化时机 | 解释 |
---|---|---|
appendfsync | everysec | 每秒记录 |
appendfsync | always | 每修改记录 |
appendfsync | no | 完全依赖操作系统,性能最好,持久化无法保证 |
4.4 Redis持久化机制RDB和AOF的区别
4.4.1 RDB持久化机制优点和缺点
优点:
- 方便备份与恢复
- 启动效率更高
- 性能最大化
为什么启动效率更高:
相比于AOF机制,如果数据集很大,RDB的启动效率会更高。因为RDB文件中存储的是数据,启动的时候直接加载数据即可,而AOF是将操作数据库的命令存放到AOF文件中,然后启动redis数据库服务器的时候会将很多个命令执行加载数据。如果数据量特别大的时候,那么RDB由于直接加载数据启动效率会比AOF执行命令加载数据更高
性能最大化:
对于Redis的服务进程而言,在开始持久化时,会在后台开辟子线程,由子线程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
缺点:
- 不能完全避免数据丢失
- 因为RDB是每隔一段时间写入数据,所以系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
- 会导致服务器暂停的现象
- 由于RDB是通过子线程来协助完成数据持久化工作的,因此当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。就是数据量过大,会开辟过多的子线程进行持久化操作,那么会占用服务器端的大量资源,那么有可能会造成服务器端卡顿。同时会造成服务器停止几百毫秒甚至一秒。
4.4.2 AOF持久化机制优点和缺点
优点:
- AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。也可以通过该文件完成数据的重建。该机制可以带来更高的数据安全性,所有的操作都是异步完成的。
缺点:
- 运行效率比RDB更慢:根据同步策略的不同,AOF在运行效率上往往会慢于RDB。
- 文件比RDB更大:对于相同数量的数据集而言,AOF文件通常要大于RDB文件。