一、RDB和AOF的优缺点
RDB 模式优点:
RDB快照保存了某个时间点的数据,可以通过脚本执行redis指令bgsave(非阻塞,后台执行)或者save(会阻塞写操作,不推荐)命令自定义时间点备份,可以保留多个备份,当出现问题可以恢复到不同时间点的版本,很适合备份,并且此文件格式也支持有不少第三方工具可以进行后续的数据分析
比如: 可以在最近的24小时内,每小时备份一次RDB文件,并且在每个月的每一天,也备份一个ROB文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
RDB可以最大化Redis的性能,父进程在保存 RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘工I/O操作。
RDB在大量数据,比如几个G的数据,恢复的速度比AOF的快
RDB 模式缺点:
不能实时保存数据,可能会丢失自上一次执行RDB备份到当前的内存数据如果你需要尽量避免在服务器故障时丢失数据,那么RDB不适合你。虽然Redis允许你设置不同的保存点(save point)来控制保存RDB文件的频率,但是,因为ROB文件需要保存整个数据集的状态,所以它并不是一个轻松的操作。因此你可能会至少5分钟才保存一次RDB文件。在这种情况下,一旦发生故障停机,你就可能会丢失好几分钟的数据。
当数据量非常大的时候,从父进程fork子进程进行保存至RDB文件时需要一点时间,可能是毫秒或者秒,取决于磁盘IO性能
在数据集比较庞大时,fork()可能会非常耗时,造成服务器在一定时间内停止处理客户端﹔如果数据集非常巨大,并且CPU时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒或更久。虽然 AOF重写也需要进行fork(),但无论AOF重写的执行间隔有多长,数据的持久性都不会有任何损失。
AOF 模式优点:
数据安全性相对较高,根据所使用的fsync策略(fsync是同步内存中redis所有已经修改的文件到存储设备),默认是appendfsync everysec,即每秒执行一次 fsync,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync会在后台线程执行,所以主线程可以继续努力地处理命令请求)
由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中不需要seek, 即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,可以通过 redis-check-aof 工具来解决数据一致性的问题
Redis可以在 AOF文件体积变得过大时,自动地在后台对AOF进行重写,重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为Redis在创建新 AOF文件的过程中,append模式不断的将修改数据追加到现有的 AOF文件里面,即使重写过程中发生停机,现有的 AOF文件也不会丢失。而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作
AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,也可以通过该文件完成数据的重建
AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此 AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了FLUSHALL.命令,但只要AOF文件未被重写,那么只要停止服务器,移除 AOF文件末尾的FLUSHAL命令,并重启Redis ,就可以将数据集恢复到FLUSHALL执行之前的状态
AOF 模式缺点:
即使有些操作是重复的也会全部记录,AOF 的文件大小要大于 RDB 格式的文件
AOF 在恢复大数据集时的速度比 RDB 的恢复速度要慢
根据fsync策略不同,AOF速度可能会慢于RDB
bug 出现的可能性更多
RDB和AOF 的选择:
如果主要充当缓存功能,或者可以承受数分钟数据的丢失, 通常生产环境一般只需启用RDB即可,此也是默认值
如果数据需要持久保存,一点不能丢失,可以选择同时开启RDB和AOF,一般不建议只开启AOF
二、master和slave同步过程
主从同步完整过程:
1)从服务器连接主服务器,发送PSYNC命令
2)主服务器接收到PSYNC命令后,开始执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有写命令
3)主服务器BGSAVE执行完后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照至内存
5)主服务器快照发送完毕后,开始向从服务器发送缓冲区中的写命令
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
7)后期同步会先发送自己slave_repl_offset位置,只同步新增加的数据,不再全量同步
三、哨兵的使用和实现机制
哨兵 (Sentinel) 工作原理
sentinel 架构和故障转移
Sentinel 进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用。
哨兵(Sentinel) 是一个分布式系统,可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossip protocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master
每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定配置时间(此项可配置)内未得到回应,则暂时认为对方已离线,也就是所谓的”主观认为宕机”简称SDOWN。当“哨兵群”中的多数Sentinel进程在对Master主服务器做出SDOWN 的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,这种方式就是“客观宕机”,简称 ODOWN,通过一定的vote算法,从剩下的slave从服务器节点中,选一台提升为Master服务器节点,然后自动修改相关配置,并开启故障转移(failover)。
Sentinel 机制可以解决master和slave角色的自动切换问题,但单个 Master 的性能瓶颈问题无法解决,类似于MySQL中的MHA功能
Redis Sentinel中的Sentinel节点个数应该为大于等于3且最好为奇数
客户端初始化时连接的是Sentinel节点集合,不再是具体的Redis节点,但Sentinel只是配置中心不是代理。
Redis Sentinel 节点与普通redis 没有区别,要实现读写分离依赖于客户端程序。
sentinel中的三个定时任务
*每10秒每个sentinel对master和slave执行info
发现slave节点
确认主从关系
*每2秒每个sentinel通过master节点的channel交换信息(pub/sub)
通过sentinel__:hello频道交互
交互对节点的“看法”和自身信息
*每1秒每个sentinel对其他sentinel和redis执行ping
实现哨兵
1.环境准备(centos8)
10.0.0.8 master
10.0.0.18 slave
10.0.0.28 slave
哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用redis架构
注意: master 的配置文件中masterauth 和slave 都必须相同
所有主从节点的redis.conf中关健配置
#在所有主从节点执行以下指令
[root@centos8 ~]#dnf -y install redis
[root@centos8 ~]#vim /etc/redis.conf #修改配置
bind 0.0.0.0
masterauth "123456"
requirepass "123456"
replicaof 10.0.0.8 6379
[root@centos8 ~]#systemctl enable --now redis
2.编辑哨兵的配置文件
sentinel配置
Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持.默认监听在26379/tcp端口.
哨兵可以不和Redis服务器部署在一起,但一般部署在一起,所有redis节点使用相同的以下示例的配置文件
三个哨兵服务器的配置都如下
[root@centos8~]#grep -vE "^#|^$" /etc/redis-sentinel.conf
port 26379
daemonize no
pidfile "/var/run/redis-sentinel.pid"
logfile "/var/log/redis/sentinel.log"
dir "/tmp"
sentinel monitor mymaster 10.0.0.8 6379 2 #修改此行
sentinel auth-pass mymaster 123456 #增加此行
sentinel down-after-milliseconds mymaster 3000 #修改此行
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
#以下内容在修改上述配置并重启服务后自动生成,不需要修改
sentinel myid 50547f34ed71fd48c197924969937e738a39975b #此行自动生成必须唯一,修改此值需重启redis和sentinel服务
# Generated by CONFIG REWRITE
protected-mode no
supervised systemd
sentinel leader-epoch mymaster 0
sentinel known-replica mymaster 10.0.0.28 6379
sentinel known-replica mymaster 10.0.0.18 6379
sentinel current-epoch 0
3.启动哨兵
三台哨兵服务器都要启动
#确保每个哨兵主机myid不同
[root@redis-slave1 ~]#cat /etc/redis-sentinel.confsentinel
myid 50547f34ed71fd48c197924969937e738a39975c
[root@redis-slave2 ~]#cat /etc/redis-sentinel.confsentinel
myid 50547f34ed71fd48c197924969937e738a39975d
[root@redis-master ~]#systemctl enable --now redis-sentinel.service
[root@redis-slave1 ~]#systemctl enable --now redis-sentinel.service
[root@redis-slave2 ~]#systemctl enable --now redis-sentinel.service
4.检查sentinel状态
[root@redis-master ~]#redis-cli -p 26379
127.0.0.1:26379> INFO sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.8:6379,slaves=2,sentinels=3
#两个slave,三个sentinel服务器,如果sentinels值不符合,检查myid可能冲突
四、redis cluster集群创建和使用
Redis Cluster特点如下:
1. 所有Redis节点使用(PING机制)互联
2. 集群中某个节点的是否失效,是由整个集群中超过半数的节点监测都失效,才能算真正的失效
3. 客户端不需要proxy即可直接连接redis,应用程序中需要配置有全部的redis服务器IP
4. redis cluster把所有的redis node 平均映射到 0-16383个槽位(slot)上,读写需要到指定的redis node上进行操作,因此有多少个redis node相当于redis 并发扩展了多少倍,每个redis node 承担16384/N个槽位
5. Redis cluster预先分配16384个(slot)槽位,当需要在redis集群中写入一个key -value的时候,会使用CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。
基于Redis 5 的 redis cluster 部署
1.创建 redis cluster集群的环境准备
1)每个redis 节点采用相同的硬件配置、相同的密码、相同的redis版本
2) 所有redis服务器必须没有任何数据
3) 准备六台主机,centos8,地址如下:
10.0.0.8
10.0.0.18
10.0.0.28
10.0.0.38
10.0.0.48
10.0.0.58
2.启用 redis cluster 配置
所有6台主机都执行以下配置
1)安装redis
[root@CentOS8 ~]# dnf -y install redis
2)修改redis配置,开启cluster功能的参数
[root@CentOS8 ~]# sed -i.bak -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e '/masterauth/a masterauth 123456' -e '/# requirepass/a requirepass 123456' -e '/# cluster-enabled yes/a cluster-enabled yes' -e '/# cluster-config-file nodes-6379.conf/a cluster-config-file nodes-6379.conf' -e '/cluster-require-full-coverage yes/c cluster-require-full-coverage no' /etc/redis.conf
3)启动redis
[root@CentOS8 ~]# systemctl enable --now redis
3.创建集群
在任意主机上执行以下指令:
[root@CentOS8 ~]# redis-cli -a 123456 --cluster create 10.0.0.8:6379 10.0.0.18:6379 10.0.0.28:6379 10.0.0.38:6379 10.0.0.48:6379 10.0.0.58:6379 --cluster-replicas 1 # --cluster-replicas 1 表示每个master对应一个slave节点
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.0.0.38:6379 to 10.0.0.8:6379
Adding replica 10.0.0.48:6379 to 10.0.0.18:6379
Adding replica 10.0.0.58:6379 to 10.0.0.28:6379
M: 4e971f4b951ec745e898ea5b70c1ce974d42959f 10.0.0.8:6379
slots:[0-5460] (5461 slots) master #master 及slot分配
M: ec23f48e2b30ff99e1566aea4bce9cc90fe544fb 10.0.0.18:6379
slots:[5461-10922] (5462 slots) master
M: 5133e4cf741893404b9ad3c0c209d9797fa76b08 10.0.0.28:6379
slots:[10923-16383] (5461 slots) master
S: a8d73bb04db8eca50c556ab1bb7fff42b7d16efd 10.0.0.38:6379
replicates 4e971f4b951ec745e898ea5b70c1ce974d42959f
S: 751540d01f4159fbf8dc35a26cfc916aa89f10bd 10.0.0.48:6379
replicates ec23f48e2b30ff99e1566aea4bce9cc90fe544fb
S: dae87a2f536d6fb95c9d4b82a8134b214369e82b 10.0.0.58:6379
replicates 5133e4cf741893404b9ad3c0c209d9797fa76b08
Can I set the above configuration? (type 'yes' to accept): yes #输入yes,自动创建集群
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.........
>>> Performing Cluster Check (using node 10.0.0.8:6379)
M: 4e971f4b951ec745e898ea5b70c1ce974d42959f 10.0.0.8:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 751540d01f4159fbf8dc35a26cfc916aa89f10bd 10.0.0.48:6379
slots: (0 slots) slave
replicates ec23f48e2b30ff99e1566aea4bce9cc90fe544fb
S: dae87a2f536d6fb95c9d4b82a8134b214369e82b 10.0.0.58:6379
slots: (0 slots) slave
replicates 5133e4cf741893404b9ad3c0c209d9797fa76b08
M: ec23f48e2b30ff99e1566aea4bce9cc90fe544fb 10.0.0.18:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: a8d73bb04db8eca50c556ab1bb7fff42b7d16efd 10.0.0.38:6379
slots: (0 slots) slave
replicates 4e971f4b951ec745e898ea5b70c1ce974d42959f
M: 5133e4cf741893404b9ad3c0c209d9797fa76b08 10.0.0.28:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
#观察以上结果,可以看到3组master/slave
master:10.0.0.8---slave:10.0.0.38
master:10.0.0.18---slave:10.0.0.48
master:10.0.0.28---slave:10.0.0.58
4.查看主从状态
[root@CentOS8 ~]# redis-cli -a 123456 -c INFO replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.38,port=6379,state=online,offset=364,lag=0
master_replid:fa0f8a1be1845bd091687c3f92906ce4e0d66b8a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:364
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:364
5.验证集群状态
[root@CentOS8 ~]# redis-cli -a 123456 cluster info
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:615
cluster_stats_messages_pong_sent:633
cluster_stats_messages_sent:1248
cluster_stats_messages_ping_received:628
cluster_stats_messages_pong_received:615
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1248
[root@CentOS8 ~]# redis-cli -a 123456 --cluster info 10.0.0.8:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.8:6379 (4e971f4b...) -> 0 keys | 5461 slots | 1 slaves.
10.0.0.18:6379 (ec23f48e...) -> 0 keys | 5462 slots | 1 slaves.
10.0.0.28:6379 (5133e4cf...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
6.查看集群node对应关系
[root@CentOS8 ~]# redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
751540d01f4159fbf8dc35a26cfc916aa89f10bd 10.0.0.48:6379@16379 slave ec23f48e2b30ff99e1566aea4bce9cc90fe544fb 0 1603940888015 5 connected
dae87a2f536d6fb95c9d4b82a8134b214369e82b 10.0.0.58:6379@16379 slave 5133e4cf741893404b9ad3c0c209d9797fa76b08 0 1603940889025 6 connected
ec23f48e2b30ff99e1566aea4bce9cc90fe544fb 10.0.0.18:6379@16379 master - 0 1603940888000 2 connected 5461-10922
a8d73bb04db8eca50c556ab1bb7fff42b7d16efd 10.0.0.38:6379@16379 slave 4e971f4b951ec745e898ea5b70c1ce974d42959f 0 1603940887000 4 connected
4e971f4b951ec745e898ea5b70c1ce974d42959f 10.0.0.8:6379@16379 myself,master - 0 1603940883000 1 connected 0-5460
5133e4cf741893404b9ad3c0c209d9797fa76b08 10.0.0.28:6379@16379 master - 0 1603940887000 3 connected 10923-16383
[root@CentOS8 ~]# redis-cli -a 123456 --cluster check 10.0.0.8:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.8:6379 (4e971f4b...) -> 0 keys | 5461 slots | 1 slaves.
10.0.0.18:6379 (ec23f48e...) -> 0 keys | 5462 slots | 1 slaves.
10.0.0.28:6379 (5133e4cf...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 10.0.0.8:6379)
M: 4e971f4b951ec745e898ea5b70c1ce974d42959f 10.0.0.8:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 751540d01f4159fbf8dc35a26cfc916aa89f10bd 10.0.0.48:6379
slots: (0 slots) slave
replicates ec23f48e2b30ff99e1566aea4bce9cc90fe544fb
S: dae87a2f536d6fb95c9d4b82a8134b214369e82b 10.0.0.58:6379
slots: (0 slots) slave
replicates 5133e4cf741893404b9ad3c0c209d9797fa76b08
M: ec23f48e2b30ff99e1566aea4bce9cc90fe544fb 10.0.0.18:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: a8d73bb04db8eca50c556ab1bb7fff42b7d16efd 10.0.0.38:6379
slots: (0 slots) slave
replicates 4e971f4b951ec745e898ea5b70c1ce974d42959f
M: 5133e4cf741893404b9ad3c0c209d9797fa76b08 10.0.0.28:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
7.验证集群写入key
#经过算法计算,当前key的槽位需要写入指定的node
[root@CentOS8 ~]# redis-cli -a 123456 -h 10.0.0.8 SET key1 value1
(error) MOVED 9189 10.0.0.18:6379 -->需要把key1写入slot 9189所在的节点
[root@CentOS8 ~]# redis-cli -a 123456 -h 10.0.0.18 SET key1 value1
OK
[root@CentOS8 ~]# redis-cli -a 123456 -h 10.0.0.18 get key1
"value1" -->key计算后所在的节点才可以写入
#对应的slave节点可以KEYS *,但不能GET key1,必须到master上执行GET key1
[root@CentOS8 ~]# redis-cli -a 123456 -h 10.0.0.48 get key1
(error) MOVED 9189 10.0.0.18:6379
[root@CentOS8 ~]# redis-cli -a 123456 -h 10.0.0.48 keys "*"
1) "key1"
# redis cluster 计算key所属的slot
[root@CentOS8 ~]# redis-cli -h 10.0.0.8 -a 123456 --no-auth-warning cluster keyslot hello
(integer) 866
[root@CentOS8 ~]# redis-cli -h 10.0.0.8 -a 123456 --no-auth-warning cluster keyslot fang
(integer) 9844
#使用选项-c 以集群模式连接,自动重定向到相应节点
[root@CentOS8 ~]# redis-cli -c -h 10.0.0.8 -a 123456 --no-auth-warning
10.0.0.8:6379> cluster keyslot linux
(integer) 12299
10.0.0.8:6379> set linux good
-> Redirected to slot [12299] located at 10.0.0.28:6379
OK
10.0.0.28:6379> get linux
"good"