Redis
一. 认识NoSQL
1.1技术的分类
1、解决功能性的问题:Java、JSP、RDBMS、Tomcat、HTML、Linux、JDBC、SVN
2、解决扩展性的问题:Struts、Spring、SpringMVC、Hibernate、Mybatis
3、解决性能的问题:NoSQL、Java线程、Hadoop、Nginx、MQ、ElasticSearch
★1.2 解决CPU及内存压力(面试题)
1.3 NoSQL数据库概述
NoSQL(NoSQL = Not Only SQL ),即“不仅仅是SQL”,泛指非关系型的数据库。
NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。
l 不遵循SQL标准。
l 不支持ACID。
l 远超于SQL的性能。
1.4 NoSQL适用场景
l 对数据高并发的读写
l 海量数据的读写
l 对数据高可扩展性的
1.5常用的NoSQL数据库
memcached
redis
mongodb
hbase
Cassandra
Neo4j
二. 认识Redis
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库
Ø Redis是一个开源的key-value存储系统。
Ø Redis可以用作数据库、缓存和消息中间件。
Ø Redis支持使用master-slave主从同步来实现高可用性,支持使用cluster集群来实现高性能。
三. 安装Redis
1) 准备工作:下载安装最新版的gcc编译器
yum install gcc
gcc --version
2) 安装Redis
a. 下载redis-6.2.1.tar.gz放/opt目录
b. 解压命令:tar -zxvf redis-6.2.1.tar.gz
c. 解压完成后进入目录:cd redis-6.2.1
3) 在redis-6.2.1目录下再次执行make命令(只是编译好)
4) 跳过make test 继续执行: make install
四 访问Redis
Redis是C/S架构,分为Server和Client。需要先启动Server,再通过client访问
前台启动:
后台启动:(推荐)
[root@localhost redis-6.2.1]# mkdir /myredis
[root@localhost redis-6.2.1]# cp /opt/redis-6.2.1/redis.conf /myredis/
[root@localhost redis-6.2.1]# vim /myredis/redis.conf
daemonize no 修改为 daemonize yes 由前台启动变为后台启动
[root@localhost redis-6.2.1]# redis-server /myredis/redis.conf
访问★==[root@localhost redis-6.2.1]# redis-cli==
127.0.0.1:6379> ping
PONG
Redis是单线程+多路IO复用技
串行 vs 多线程+锁(memcached) vs 单线程+多路IO复用(Redis)
★五. Redis五大数据类型
1.Redis key 命令
keys 查看当前库所有key(匹配:keys *1) |
---|
del key 删除指定的key数据 |
expire key 10 10秒钟:为给定的key设置过期时间 |
flushdb清空当前库 |
flushall通杀全部库 |
2.Redis String命令
Integer、Double、String都认为是String,其实还可以是图片、视频等二进制数据
set 添加键值对 |
---|
get 查询对应键值 |
incr |
**decr ** |
incrby / decrby <步长>将 key 中储存的数字值增减。自定义步长。 |
getrange <起始位置><结束位置> |
setex <过期时间> |
3. Redis list命令
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
lpush/rpush <key><value1><value2><value3> .... 从左边/右边插入一个或多个值。
lpop/rpop <key>从左边/右边吐出一个值。值在键在,值光键亡。
lrange <key><start><stop>
lindex <key><index>按照索引下标获得元素(从左到右)
llen <key>获得列表长度
linsert <key> before <value><newvalue>在<value>的后面插入<newvalue>插入值
4.Redis set命令
set集合,底层结构是哈希表,速度快;无序,唯一
sadd <key><value1><value2> .....
将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略
smembers <key>取出该集合的所有值。
srem <key><value1><value2> .... 删除集合中的某个元素。
sinter <key1><key2>返回两个集合的交集元素。
sunion <key1><key2>返回两个集合的并集元素。
sdiff <key1><key2>返回两个集合的差集元素(key1中的,不包含key2中的)
5.Redis hash命令
Redis是一个key-value的数据库。其中的value也可以是hash类型,value本身也是一个map,可以存储多个key-value
hset <key><field><value>给<key>集合中的 <field>键赋值<value>
hget <key1><field>从<key1>集合<field>取出 value
hdel <key><field> 删除<key>集合中指定<field>
hexists<key1><field>查看哈希表 key 中,给定域 field 是否存在。
hincrby <key><field><increment>为哈希表 key 中的域 field 的值加上增量 1 -1
6.Redis zset命令
Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。
不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合成员是唯一的,但是评分可以是重复了 。
zadd <key><score1><member 1><score2><member 2>…
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
**zrange <key><start><stop> [WITHSCORES]**
返回有序集 key 中,下标在<start><stop>之间的元素
带WITHSCORES,可以让分数一起和值返回到结果集。
zrevrangebyscore key max min [withscores] [limit offset count]
同上,改为从大到小排列。
zincrby <key><increment><member > 为元素的score加上增量
六Redis 配置文件
七 使用Jedis访问Redis
使用Jedis连接Redis,确认连接成功
public class TestJedis {
public static void main(String[] args) {
//创建Jedis对象,指明Redis服务器的IP和port
Jedis jedis = new Jedis("192.168.245.245",6379);
//测试连接是否成功
String result = jedis.ping();
System.out.println(result);//PONG
//关闭Jedis对象
jedis.close();
}
}
使用Jedis访问Redis
public class TestJedis2 {
public static void main(String[] args) {
//创建Jedis对象,指明Redis服务器的IP和port
Jedis jedis = new Jedis("192.168.245.245",6379);
//操作String
jedis.set("k1","v1");
jedis.mset("k2","v2","k3","v3");
//操作key
Set<String> keys = jedis.keys("*");
System.out.println(keys);
String value = jedis.get("k3");
System.out.println(value);
//操作List
jedis.del("course");
jedis.lpush("course","java","java","html","mysql");
List<String> list = jedis.lrange("course", 0, -1);
System.out.println(list);
//操作Hash
Map map = new HashMap();
map.put("name","zhangsan");
map.put("age","18");
map.put("birthDate","1999-12-23");
jedis.hset("zs",map);
//关闭Jedis对象
jedis.close();
}
}
使用Jedis连接池
public class TestJedis3 {
public static void main(String[] args) {
//指定Jedis连接池的配置信息
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(200);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWaitMillis(100*1000);
poolConfig.setBlockWhenExhausted(true);
poolConfig.setTestOnBorrow(true); // ping PONG
//创建Jedis对象,指明Redis服务器的IP和port
//这是直接找服务器的上的Redis数据库建立物理连接,效率低下
//可以考虑事先创建好多个物理连接,需要的时候直接拿来使用,效率高
//Jedis jedis = new Jedis("192.168.245.245",6379);
//创建连接池
JedisPool jedisPool =
new JedisPool(poolConfig, "192.168.245.245", 6379, 60000 );
//从连接池中获取已经创建好的连接
Jedis jedis = jedisPool.getResource();
//测试连接是否成功
String result = jedis.ping();
System.out.println(result);//PONG
//关闭Jedis对象
jedis.close();
}
}
八 手机验证码案例
public class PhoneCode {
public static void main(String[] args) {
//1.请输入手机号码
Scanner input = new Scanner(System.in);
System.out.println("请输入手机号码");
String phone = input.next();
//2.完成发送,并得到返回的验证码并输出
System.out.println("输入1完成发送:");
input.next();
String code = getCode(phone);
if("-1".equals(code)){
System.out.println("本手机今天输入验证码已经超过3次,欢迎明天继续超过3次!!");
return;
}
System.out.println("验证码是:"+code);
//3.请输入验证码
System.out.println("请输入验证码:");
String myCode = input.next();
//4.发送验证码,获取验证结果并输出
System.out.println("输入1完成发送:");
input.next();
boolean flag = verifyCode(myCode,phone);
if(flag){
System.out.println("成功");
}else{
System.out.println("失败");
}
}
/**
* 验证验证码是否正确
* @param myCode
* @param phone
* @return
*/
private static boolean verifyCode(String myCode, String phone) {
//从redis中获取验证码
Jedis jedis = new Jedis("192.168.245.245",6379);
String code = jedis.get("code:"+phone);
//判断验证码是否正确
boolean flag = false;
if(code!=null && code.equals(myCode)){ //code可能是null吗???2分钟过期key不存在
flag = true;
}
//返回结果
return flag;
}
/**
* 接收手机号码,生成验证码并返回
* @param phone
* @return
*/
private static String getCode(String phone) {
//生成验证码
String code = generateCode();
//验证码过期时间设为2分钟
Jedis jedis = new Jedis("192.168.245.245",6379);
jedis.setex("code:"+phone,120,code);
//判断本手机验证码是否超过3次
String count = jedis.get("count:" + phone);
if(count==null){ //第一次访问
//设置访问次数为1
jedis.set("count:" + phone,"1");
}else if(Integer.parseInt(count)<3){ //如果是第二次或者第三次访问
jedis.incr("count:" + phone);
}else{ //已经超过了3次
code ="-1";
}
//返回验证码
return code;
}
private static String generateCode() {
Random random = new Random();
String code = "";
for(int i=0;i<6;i++) {
int rand = random.nextInt(10);
code += rand;
}
return code;
}
}
九 Redis事务
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Redis事务的主要作用就是串联多个命令防止别的命令插队。
注意:此等重要的场合,对于事务的原子性闭口不提。
Redis实现事务的三个命令:Multi、Exec、discard
情况1: multi … 一切正常 discard 全部没有执行
情况2: multi … 一切正常 exec 全部正确执行
情况4:exec失败
没有保证所有操作的原子性
情况3:组队失败
如果在组队的时候失败,所有操作全部不执行,哪怕执行了exec。
十 乐观锁和悲观锁
1.悲观锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
2.乐观锁
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
3.Redis事务三特性
Ø 单独的隔离操作
n 事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Ø 没有隔离级别的概念
n 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
Ø 不保证原子性
n 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
4.Redis事务和MySQL事务的区别
MySQL事务遵守严格的ACID特征,而Redis 设计更多的是追求简单与高性能,所以事务不会也没有必要受制于传统 ACID 的束缚。
Redis 具备了一定的原子性,但不支持回滚,严格意义上无法保证原子性。
Redis 不支持回滚,也就无法保证业务上的数据一致性。
Redis 具备隔离性,但是没有隔离级别。
Redis 通过一定策略可以保证持久性。Redis 是否具备持久化,取决于 Redis 的持久化模式比如AOF、RDB及其策略设置。
十一.秒杀思路
十二 秒杀实现
1.先来熟悉秒杀的代码
一个页面,一个Servlet,一个业务类,功能简单。关键在于业务类对Redis的操作
问题1:访问项目,提示连接超时:connect time out
原因:IP地址或者端口错误;防火墙开启;Redis服务器没有启动
模拟高并发秒杀功能:使用专门的工具:ab(apache benchmark) jmeter
\1. 安装ab yum install httpd-tools
\2. 使用ab:
ab -n 1000 -c 100 -k -p ~/postfile -T application/x-www-form-urlencoded http://192.168.15.51:8080/Seckill/doseckill
需要准备好postfile:内容:prodid=0101&
ab命令是linux上运行的,访问的windows tomcat上的项目,这是一个远程访问
访问地址要是windows tomcat上的资源的位置
2.问题:出现了超卖现象
3.原因:没有使用事务,也没有上锁
4.解决:在Jedis访问Redis的代码中使用乐观锁解决超卖问题
5.问题:超卖问题解决了,出现了库存有剩余的情况
原因:乐观锁。失败之后是否会重新发起请求继续秒杀
解决:LUA脚本
十三 主从复制
1.什么叫主从复制:
一个主机可以搭配多个从机,数据相同;从机会获取主机的数据
好处:
数据有冗余,即使主机出问题,从机中还有完整的数据。容灾
减轻主机的负担:读写分离
2. 如何实现一主二从
\1. 方法1:三台物理机
\2. 方法2:三台虚拟机
\3. 方法3:一台虚拟机,通过端口来区分 6379 6380 6381
3. 实现:
- 新建三个配置文件:
redis6379.conf redis6380.conf redis6381.conf
- 启动三台主机(没有主从关系)
[root@localhost myredis]# redis-server /myredis/redis6379.conf
[root@localhost myredis]# redis-server /myredis/redis6380.conf
[root@localhost myredis]# redis-server /myredis/redis6381.conf
[root@localhost myredis]# ps -ef | grep redis
root 1743 1 0 11:16 ? 00:00:00 redis-server *:6379
root 1749 1 0 11:16 ? 00:00:00 redis-server *:6380
root 1755 1 0 11:16 ? 00:00:00 redis-server *:6381
root 1761 1167 0 11:16 pts/0 00:00:00 grep --color=auto redis
[root@localhost ~]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:84fea270d109a28a6a3737580f0c212b15d65aa8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
[root@localhost ~]# redis-cli -p 6380
[root@localhost ~]# redis-cli -p 6381
- 建立主从关系:配从不配主
127.0.0.1:6380>slaveof 192.168.245.245 6379
OK
127.0.0.1:6380>info replication
# Replication
role:slave
master_host:192.168.245.245
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_failover_state:no-failover
master_replid:37d530d2b5c08c108a14d93fb61e3e567ebd7faf
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0
127.0.0.1:6380> keys *(拜完大哥立刻进行全量复制)
-
“k2”
-
“k1”
127.0.0.1:6380> keys *(主机的新增或者删除修改的内容会进行增量复制)
-
“k2”
-
“k1”
-
“k3”
127.0.0.1:6380> keys *
-
“k2”
-
“k1”
127.0.0.1:6380> set k4 v4 (从机只能被读,不能写)
(error) READONLY You can’t write against a read only replica.
127.0.0.1:6380>
-
使用主从复制
主机挂掉,重启就行,一切如初
从机重启需重设:slaveof 127.0.0.1 6379
十四 主从复制-薪火相传
问题:中间的同时slave和master的服务器是否可以写???不可以!!!
风险是一旦某个slave(同时也是master)宕机,后面的slave都没法备份
十五 主从复制-反客为主
1. 手动
① 新大哥要手动的当大哥
② 小弟要手动的重新拜新大哥
③ 老大哥回来了,成立光杆司令,必须手动的拜新的大哥
如果这三个手动都变成自动,那该多好呀!!!
那就是哨兵机制,所有的这三个手动都有哨兵搞定。
1.2 复制原理:
l slave启动成功连接到master后会发送一个sync命令
l Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
l 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
l 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
l 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
十六 主从复制-哨兵模式
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
①调整为一主二仆模式,6379带着6380、6381
② 自定义的/myredis目录下新建sentinel.conf文件并进行配置
sentinel monitor mymaster 127.0.0.1 6379 1
-
启动哨兵
redis-sentinel /myredis/sentinel.conf
④演示自动的反客为主
优先级在redis.conf中默认:replica-priority 100,值越小优先级越高
偏移量是指获得原主机数据最全的
每个redis实例启动后都会随机生成一个40位的runid(通过info server获取查看)
十七 集群
Redis3.0开始提供了解决方案,就是无中心化集群配置。
Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
一个集群最少3个主机,一个主机最少一个1个从机,搭建集群最少6台电脑
集群步骤
1. 配置6个conf文件,使用端口进行区分
| include /myredis2/redis.confpidfile “/var/run/redis_6379.pid”
port 6379
dbfilename “dump6379.rdb”
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000 |
---|
cluster-enabled yes 打开集群模式
cluster-config-file nodes-6379.conf 设定节点配置文件名
cluster-node-timeout 15000 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换。
2. 启动6个主机
[root@localhost myredis2]# redis-server /myredis2/redis6379.conf
[root@localhost myredis2]# redis-server /myredis2/redis6380.conf
[root@localhost myredis2]# redis-server /myredis2/redis6381.conf
[root@localhost myredis2]# redis-server /myredis2/redis6389.conf
[root@localhost myredis2]# redis-server /myredis2/redis6390.conf
[root@localhost myredis2]# redis-server /myredis2/redis6391.conf
[root@localhost myredis2]# ps -ef | grep redis
root 2427 1 0 14:44 ? 00:00:00 redis-server *:6379 [cluster]
root 2433 1 0 14:45 ? 00:00:00 redis-server *:6380 [cluster]
root 2439 1 0 14:45 ? 00:00:00 redis-server *:6381 [cluster]
root 2445 1 0 14:45 ? 00:00:00 redis-server *:6389 [cluster]
root 2451 1 0 14:45 ? 00:00:00 redis-server *:6390 [cluster]
root 2457 1 0 14:45 ? 00:00:00 redis-server *:6391 [cluster]
root 2463 1167 0 14:45 pts/0 00:00:00 grep --color=auto redis
3. 通过命令搭建集群
redis-cli --cluster create --cluster-replicas 1
192.168.245.245:6379 192.168.245.245:6380 192.168.245.245:6381
192.168.245.245:6389 192.168.245.245:6390 192.168.245.245:6391
十八 RDB持久化
1. RDB(RedisDataBase)
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
配置文件名称dbfilename:默认为dump.rdb
配置文件位置 dir:rdb文件的保存路径,默认为Redis启动时命令行所在的目录下
持久化策略:格式:save 秒钟 写操作次数
RDB是整个内存的压缩过的Snapshot,RDB的数据结构,可以配置复合的快照触发条件,默认是1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次。
如果取消持久化
save “”
2.如何触发RDB快照
① save策略
\2. 手动save和bgsave
③ flushall
④ shutdown正常关闭redis
3.优势
l 适合大规模的数据恢复
l 对数据完整性和一致性要求不高更适合使用
l 节省磁盘空间
l 恢复速度快
十九 AOF持久化
1. 概念
以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据
注意:会记录整个的写操作过程(写、删除、修改)。文件越来越大。
默认AOF不开启:appendonly no
默认
AOF
文件
appendfilename “appendonly.aof”
AOF和RDB同时开启,系统默认取AOF的数据(rdb可能丢失最后一次持久化的内容)
2. AOF持久化流程
(1)客户端的请求写命令会被append追加到AOF缓冲区内;(没有写入文件呢??)
(2)AOF缓冲区根据==AOF持久化策略[always,everysec,no]==将操作sync同步到磁盘的AOF文件中;
(3)AOF文件大小超过==重写策略或手动重写(rewrite)==时,会对AOF文件rewrite重写,压缩AOF文件容量;
(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3. AOF持久化策略:
appendfsync always 随时持久化
appendfsync everysec 每秒持久化一次
# appendfsync no 不(主动)持久化
4.AOF重写策略
auto-aof-rewrite-percentage:设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)
auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写。
10M---->20M---->40M—80M(>64M)
5. AOF如何重写
redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作。
RDB中存储key-value的最后的值,但是AOF存对key-value的操作过程(delete、set)。
dump.rdb是二进制文件,不可读;但是aof文件是文本文件,可读。
优势:
①appendfsync always 备份机制更稳健,丢失数据概率更低
②可读的日志文本,通过操作AOF稳健,可以处理误操作
6. 到底使用RDB还是使用AOF
① 两个都不用:只是做纯内存缓存
② 使用RDB:对数据不敏感
③ 同时使用RDB和AOF:可以弥补RDB对数据不敏感
④不建议单独使用AOF
*2. AOF**持久化流程
(1)客户端的请求写命令会被append追加到AOF缓冲区内;(没有写入文件呢??)
(2)AOF缓冲区根据==AOF持久化策略[always,everysec,no]==将操作sync同步到磁盘的AOF文件中;
(3)AOF文件大小超过==重写策略或手动重写(rewrite)==时,会对AOF文件rewrite重写,压缩AOF文件容量;
(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3. AOF持久化策略:
appendfsync always 随时持久化
appendfsync everysec 每秒持久化一次
# appendfsync no 不(主动)持久化
4.AOF重写策略
auto-aof-rewrite-percentage:设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)
auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写。
10M---->20M---->40M—80M(>64M)
5. AOF如何重写
redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作。
RDB中存储key-value的最后的值,但是AOF存对key-value的操作过程(delete、set)。
dump.rdb是二进制文件,不可读;但是aof文件是文本文件,可读。
优势:
①appendfsync always 备份机制更稳健,丢失数据概率更低
②可读的日志文本,通过操作AOF稳健,可以处理误操作
6. 到底使用RDB还是使用AOF
① 两个都不用:只是做纯内存缓存
② 使用RDB:对数据不敏感
③ 同时使用RDB和AOF:可以弥补RDB对数据不敏感
④不建议单独使用AOF