目录
前言
与Redis集群相对应的,就是单点Redis,Redis搭建集群出现的原因,也是解决单点Redis所存在的问题。主要存在以下四种问题,也有相对应的解决办法,本文也将从四个方面介绍~
一、rides持久化
持久化就是将数据记录到磁盘当中,当Redis宕机时,可以通过磁盘恢复数据。对Redis数据进行持久化,有RDB和AOF两种策略,两者根本区别在就是在存储方式上,一种是基于快照方式,一种命令日志方式。
1、RDB持久化
概念 : RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
快照文件称为RDB文件,默认是保存在当前运行目录。
1.1执行时机:
RDB持久化在四种情况下会执行:
- 手动执行save命令时
- 手动执行bgsave命令时
- Redis停机时
- 触发RDB执行条件时
1) save命令
执行下面的命令,可以立即执行一次RDB:
save命令会导致主进程执行RDB,这个过程中其它所有命令都会被阻塞。
所以平时禁止使用,只有在数据迁移时可能用到。
2)bgsave命令
这个命令可以异步执行RDB:因为这个命令执行后会开启独立进程完成RDB,主进程可以持续处理用户请求,不受影响。
3)停机时
Redis停机时会执行一次save命令,实现RDB持久化。
4)触发RDB条件
1.2、RDB执行原理
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。
fork采用的是copy-on-write技术:
-
当主进程执行读操作时,访问共享内存;
-
当主进程执行写操作时,则会拷贝一份数据,执行写操作。
RDB方式bgsave的基本流程:
-
fork主进程得到一个子进程,共享内存空间
-
子进程读取内存数据并写入新的RDB文件
-
用新RDB文件替换旧的RDB文件
RDB的缺点:
-
RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险
-
fork子进程、压缩、写出RDB文件都比较耗时
RDB附加作用:
数据分析,根据解析RDB快照文件,获取redis中的数据,分析问题。
2、AOF持久化
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
2.1、配置AOF频率
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
AOF的命令记录的频率也可以通过redis.conf文件来配:有三种策略
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 表示写命令执行完先放入AOF缓冲区,每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
三种策略对比:
2.2、AOF文件重写
AOF文件记录的是操作命令,有时对同一个key多次操作,而对我们有意义的就是最后一次操作,之前的操作命令都是无用的,所以可以通过重写AOF文件,抛去瓤余的操作记录.
3、RDB对比AOF
二、Redis主从集群
搭建Redis集群实现读写分类,可以提高并发能力
1、搭建主从集群
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
2、主从数据同步原理
实现主节点与从节点的数据同步,分为第一次全部数据的同步和更新性部分数据的同步,又叫全量同步和增量同步。
2.1、全量同步
master判断salve是否是第一次连接的依据:
-
Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
-
offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以根据replid是否一致, 判断到底需要同步哪些数据。
2.2、增量同步
repl_backlog原理
这个文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。
3、Redis主从同步优化
主从同步可以保证主从数据的一致性,非常重要。
可以从以下几个方面来优化Redis主从就集群:
什么时候执行全量同步?
什么时候执行增量同步?
-
在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
-
Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
-
适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
-
限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
总结
-
简述全量同步和增量同步区别?
-
全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
-
增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
-
slave节点第一次连接master节点时
-
slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
-
slave节点断开又恢复,并且在repl_baklog中能找到offset时
三、Redis哨兵
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。实现了高可用
1、哨兵到的作用
1.1、服务状态监控
1.2、选举新master
选举依据 :
-
首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
-
然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
-
如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
-
最后是判断slave节点的运行id大小,越小优先级越高。
master切换流程 :
-
sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
-
sentinel给所有其它slave发送slaveof 192.168.200.130 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
-
最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
总结
Sentinel的三个作用是什么?
-
监控; 故障转移; 通知
Sentinel如何判断一个redis实例是否健康?
-
每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线
-
如果大多数sentinel都认为实例主观下线,则判定服务下线
故障转移步骤有哪些?
-
首先选定一个slave作为新的master,执行slaveof no one
-
然后让所有节点都执行slaveof 新master
-
修改故障节点配置,添加slaveof 新master
四、Redis分片机群
实现了海量数据存储和高并发写的问题.
1、分片集群结构
2 、散列插槽
概念 :
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
-
key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
-
key中不包含“{}”,整个key都是有效部分
分片插槽设计 :
-
每一个实例都知道其他master实例上有哪些茶巢
-
可以使用{key}将相同key数据放到同样的master上
-
为什么设计插槽? 相当于把数据平摊成16384份,就方便将来做数据迁移. 只需要把其中一部分插槽和数据迁移.
总结 :
Redis如何判断某个key应该在哪个实例?
-
将16384个插槽分配到不同的实例
-
根据key的有效部分计算哈希值,对16384取余
-
余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个Redis实例?
-
这一类数据使用相同的有效部分,例如key都以{typeId}为前缀
3、集群伸缩
概念: 就是添加或者移除节点;
-
添加节点时,先创建节点再添加节点到分片集群,最后分配插槽
-
删除节点时,先将节点上的插槽和数据转移到其他节点,再删除节点.
添加节点
1.建立连接:
1.1得到下面的反馈:询问要移动多少个插槽,我们计划是3000个:
1.2新的问题来了:那个node来接收这些插槽??
1.3显然是我们要添加的节点,将要添加的节点的id复制上去
1.4这里询问插槽是从哪里移动过来的?
-
all:代表全部,也就是三个节点各转移一部分
-
具体的id:目标节点的id
-
done:没有了
这里我们要从7001获取,因此填写7001的id:填完后,点击done,这样插槽转移就准备好了,
1.5询问确认要转移吗?输入yes:
1.6然后,通过命令查看结果:
1.7可以看到: 目的达成。
4、故障转移
自动故障转移
手动故障转移: