持久化
①What's the Persistence?
保存数据到磁盘,防止机器宕机或重启时的数据丢失。存储到内存的数据会丢失
②How to make Persistence?
-
RDB(Default Mode)
通过快照完成,符合一定条件时将内存中所有数据进行快照并存储到硬盘上(RDB文件)
*一定条件:手动触发(BGSAVE/SAVE)、自动触发(配置SAVE 时间+至少改动键个数)
**手动触发两种方式(BGSAVE/SAVE)区别: BGSAVE是SAVE的优化版本
-
BGSAVE(RDB快照过程):Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成(覆盖旧的RDB文件)后自动结束。阻塞只发生在fork阶段,一段时间很短;父进程继续接受并处理客户端发来的命令(写命令)。运行bgsave名字对应的Redis日志如下:
Background saving started by pid 3152 DB saved on disk RDB: 0MB of memory userd by copy-on-write Background saving terminated with success
-
SAVE:阻塞当前Redis服务器,直到RDB过程完成为止(父进程进行快照),对于内存比较大的实例会造成长时间阻塞,先上环境不建议使用。运行save命令对应Redis日志如下:DB saved on disk
RDB的优点:
-
RDB是一个紧凑压缩的二进制文件,代表Redis在某一个时间点上的数据快照。非常适合用于备份,全量复制等场景。比如每6小时执行bgsave备份,并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复。
-
Redis加载RDB恢复数据远远快于AOF方式。
RDB的缺点:
-
RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。
-
RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB笨笨,存在老版本Redis服务无法兼容新版RDB格式的问题。
针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决
-
AOF
将发送到Redis服务端的每一条命令都记录下来,保存到硬盘的AOF文件,位置同RDB文件
流程:
1) 所有的写入命令会追加到aof_buf(缓冲区)中(文本协议格式)。
2) AOF缓冲区根据对应的策略向硬盘做同步操作。
3) 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
目的:去除数据的中间执行过程,保留最终数据命令即可(set a 1 set a 2 --> set a 2)
*3.1手动触发:
直接调用bgrewriteaof命令
*3.2自动触发:
*3.3重写过程:
①执行AOF重写请求。
如果当前进程正在执行AOF重写,请求不执行并返回如下响应:
ERR Background append only file rewriting already in progress
如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成后再执行,返回如下响应:
Background append only file rewriting scheduled
②父进程执行fork创建子进程,开销等同于bgsave过程。
③ 主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入AOF缓冲区并更具appendfsync策略同步到硬盘,保证原有AOF机制正确性。
由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,Redis使用"AOF重写缓冲区"保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。
④子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞。
⑤新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体见info persistence下的aof_*相关统计。
父进程把AOF重写缓冲区的数据写入到新的AOF文件。
使用新AOF文件替换老文件,完成AOF重写。
4) 当Redis服务重启时,可以加载AOF文件进行数据恢复。
① AOF持久化开启且存在AOF文件时,优先加载AOF文件,打印如下日志:
DB loaded from append only file: 5.841 seconds
②AOF关闭或者AOF文件不存在时,加载RDB文件,打印如下日志:
DB loaded from disk:5.586 seconds
③ 加载AOF/RDB文件城后,Redis启动成功。
④AOF/RDB文件存在错误时,Redis启动失败并打印错误信息
主从复制(读写分离)架构
①What's this?
默认主库可以接收用户请求(写命令)以及读命令,而从库只能接收读命令(可以配置)
*主从复制的过程:
- 当从库和主库建立MS关系后,会向主数据库发送SYNC命令;
- 主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程);如果是无磁盘复制,会将快照直接通过网络发送给数据库,并将期间接收到的写命令缓存起来;
- 当快照完成后,主Redis会将快照文件和所有缓存的写命令发送给从Redis;
- 从Redis接收到后,会载入快照文件并且执行收到的缓存的命令;
- 之后,主Redis每当接收到写命令时就会将命令发送从Redis,从而保证数据的一致;
主从架构:
主从从架构:(减轻主库压力-->又要接命令又要同步)
② If one of the database Shutdown..
*从库宕机
在Redis中从库重新启动后会自动加入到主从架构中,自动完成同步数据(增量复制,不是RDB);
*主库宕机
①人肉运维(手动操作)
第一步:在从数据库中执行SLAVEOF NO ONE命令,断开主从关系并且提升为主库继续服务;
第二步:将主库重新启动后,执行SLAVEOF命令,将其设置为其他库的从库,这时数据就能更新回来;
②哨兵(Sentinel)
**作用:独立于Redis的进程;监控主从数据库运行状态;哨兵之间互相监控;主数据库出错时自动将从库转成主库;
集群架构
①What's the Cluster?
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的节点(Redis库)检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot(插槽)上(集群中每个节点分得插槽数总和),cluster 负责维护node<->slot<->value。如果插槽没有对应节点,则无法使用该插槽
②Save the data
接收写命令(set key value) --> 通过key计算插槽值,根据插槽值找到对应节点 --> 重定向到该节点所在库执行写命令
*通过key计算插槽值:插槽值=key的有效部分使用CRC16算法计算出哈希值,再将哈希值对16384取余
**有效部分:eg1: key={hello}_abc --> 有效部分:hello eg2: key=hello_abc --> 有效部分:hello_abc
③If one of the database Shutdown..
- 集群中的每个节点都会定期的向其它节点发送PING命令,并且通过有没有收到回复判断目标节点是否下线;
- 集群中每一秒就会随机选择5个节点,然后选择其中最久没有响应的节点放PING命令;
- 如果一定时间内目标节点都没有响应,那么该节点就认为目标节点疑似下线;
- 当集群中的节点超过半数认为该目标节点疑似下线,那么该节点就会被标记为下线;
- 当集群中的任何一个节点下线,就会导致插槽区有空档,不完整,那么该集群将不可用;
- 如何解决上述问题?
- 在Redis集群中可以使用主从模式实现某一个节点的高可用
- 当该节点(master)宕机后,集群会将该节点的从数据库(slave)转变为(master)继续完成集群服务;
集群+主从模式:
①Normal condition
②Break Down(主库宕机)
④Some problem in cluster..
- 多键的命令操作(如MGET、MSET),如果每个键都位于同一个节点,则可以正常支持,否则会提示错误。
- 集群中的节点只能使用0号数据库(可以设置,redis中默认有16个数据库),如果执行SELECT切换数据库会提示错误。