2020-10-25

1、RDB和AOF的优缺点

RDB 模式优点

  RDB快照保存了某个时间点的数据,可以通过脚本执行redis指令bgsave(非阻塞,后台执行)或者save(会阻塞写操作,不推荐)命令自定义时间点备份,可以保留多个备份,当出现问题可以恢复到不同时间点的版本,很适合备份,并且此文件格式也支持有不少第三方工具可以进行后续的数据分析。
  比如: 可以在最近的24小时内,每小时备份一次RDB文件,并且在每个月的每一天,也备份一个RDB文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
RDB可以最大化Redis的性能,父进程在保存 RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘工/0操作。
  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 出现的可能性更多

2、master和slave同步过程

主从模式(master/slave),可以实现Redis数据的跨主机备份。
程序端连接到高可用负载的VIP,然后连接到负载服务器设置的Redis后端real server,此模式不需要在程序里面配 置Redis服务器的真实IP地址,当后期Redis服务器IP地址发生变更只需要更改redis 相应的后端real server即可, 可避免更改程序中的IP地址设置。

主从复制特点
一个master可以有多个slave
一个slave只能有一个master
数据流向是单向的,master到slave

主从复制实现
Redis Slave 也要开启持久化并设置和master同样的连接密码,因为后期slave会有提升为master的可能,Slave 端切换master同步后会丢失之前的所有数据,而通过持久化可以恢复数据一旦某个Slave成为一个master的slave,Redis Slave服务会清空当前redis服务器上的所有数据并将master的数据导入到自己的内存,但是如果只是断开同步关系后,则不会删除当前已经同步过的数据。

当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。否则的话,由于延迟等问题,部署的服务应该要避免自动启动。
参考案例: 导致主从服务器数据全部丢失
在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动启动。

默认redis 状态为master,需要转换为slave角色并指向master服务器的IP+PORT+Password
REPLICAOF MASTER_IP PORT 指令可以启用主从同步复制功能,早期版本使用 SLAVEOF 指令

配置redis主从(redis默认自身为主master)
在从节点上执行
replicaof  
修改配置文件配置从节点
vim redis.conf
masterauth 123456
replicaof  
requirepass 123456
1)从服务器连接主服务器,发送PSYNC命令
2)主服务器接收到PSYNC命令后,开始执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有
写命令
3)主服务器BGSAVE执行完后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照至内存
5)主服务器快照发送完毕后,开始向从服务器发送缓冲区中的写命令
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
7)后期同步会先发送自己slave_repl_offset位置,只同步新增加的数据,不再全量同步

3、哨兵的使用和实现机制

Sentinel 进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时
候,可以实现Master和Slave服务器的切换。Sentinel节点应为奇数,否则可能出现脑裂。

哨兵(Sentinel) 是一个分布式系统,可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言
协议(gossip protocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement
Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master
每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活”
着,如果发现对方在指定配置时间(可配置的)内未得到回应,则暂时认为对方已离线,也就是所谓的”主
观认为宕机” (主观:是每个成员都具有的独自的而且可能相同也可能不同的意识),英文名称:Subjective
Down,简称SDOWN
有主观宕机,对应的有客观宕机。当“哨兵群”中的多数Sentinel进程在对Master主服务器做出SDOWN
的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线
判断,这种方式就是“客观宕机”(客观:是不依赖于某种意识而已经实际存在的一切事物),英文名称是:
Objectively Down, 简称 ODOWN
通过一定的vote算法,从剩下的slave从服务器节点中,选一台提升为Master服务器节点,然后自动修
改相关配置,并开启故障转移(failover)。

sentinel中的三个定时任务
每10秒每个sentinel寸master和slave执行info
发现slave节点
确认主从关系
每2秒每个sentinel通过master节点的channel交换信息(pub/sub)
通过sentinel__:hello频道交互
交互对节点的“看法”和自身信息
每1秒每个sentinel对其他sentinel和redis执行ping

配置Sentinel

vim redis-sentinel.conf
bind 0.0.0.0
port 26379
daemonize yes
pidfile "redis-sentinel.pid"
logfile "sentinel_26379.log"
dir "/tmp" #工作目录
sentinel myid 50547f34ed71fd48c197924969937e738a39975b #此行为启动sentinel服务后自动生成
sentinel monitor mymaster 10.0.0.8 6379 2 #指定当前master服务器的地址和端口
#                主从集群名称  masterip masterport
#2为法定人数限制(quorum),即有几个sentinel认为master down了就进行故障转移,一般此值是所有
sentinel节点(一般总数是>=3的 奇数,如:3,5,7等)的一半以上的整数值,比如,总数是3,即
3/2=1.5,取整为2,是master的ODOWN客观下线的依据
sentinel auth-pass mymaster 123456 #master的密码,注意此行要在上面行的下面
sentinel down-after-milliseconds mymaster 30000 #(SDOWN)判断所有节点的主观下线的时
间,单位:毫秒,建议3000
sentinel parallel-syncs mymaster 1 #发生故障转移后,同时向新master同步数据的slave数量,
数字越小总同步时间越长,但可以减轻新master的负载压力
sentinel failover-timeout mymaster 180000 #所有slaves指向新的master所需的超时时间,单
位:毫秒
sentinel deny-scripts-reconfig yes #禁止修改脚本
logfile /var/log/redis/sentinel.log
#启动哨兵#
redis-sentinel 配置文件

4、redis cluster集群创建和使用

创建集群

原生命令(5版本)

redis-cli -a 123456 --cluster create 10.0.0.8:6379 10.0.0.18:6379 10.0.0.28:6379 10.0.0.18:6380 10.0.0.28:6380 10.0.0.8:6380 --cluster-replicas 1 #建立集群并设置主从 --cluster-replicas 1 表示master仅有一个从节点,这里前三个为主

redis-trib.rb 命令用法(3、4版本)

Redis 3和 4版本需要使用到集群管理工具redis-trib.rb,这个工具是redis官方推出的管理redis集群的
工具,集成在redis的源码src目录下,是基于redis提供的集群命令封装成简单、便捷、实用的操作工
具,redis-trib.rb是redis作者用ruby开发完成的,centos 7 系统yum安装的ruby存在版本较低问题。

编译安装ruby环境

yum -y install gcc openssl-devel zlib-devel
wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.5.tar.gz
tar xf ruby-2.5.5.tar.gz
cd ruby-2.5.5
 ./configure
 make -j 2 && make install
ruby -v
ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-linux]
 #注意需要重新登录
 #修改redis-trib.rb连接redis的密码
vim /usr/local/lib/ruby/gems/2.5.0/gems/redis-
4.1.3/lib/redis/client.rb
 #ruby创建集群#
redis-trib.rb create --replicas 1 10.0.0.7:6379 10.0.0.17:6379 10.0.0.27:6379 10.0.0.7:6380 10.0.0.17:6380 10.0.0.27:6380

集群数据写入脚本

#!/usr/bin/env python3
from rediscluster import RedisCluster
startup_nodes = [
{"host":"10.0.0.7", "port":6379},
{"host":"10.0.0.7", "port":6380},
{"host":"10.0.0.17", "port":6379},
{"host":"10.0.0.17", "port":6380},
{"host":"10.0.0.27", "port":6379},
{"host":"10.0.0.27", "port":6380}
]
redis_conn= RedisCluster(startup_nodes=startup_nodes,password='123456',
decode_responses=True)
for i in range(0, 10000):
redis_conn.set('key'+str(i),'value'+str(i))
print('key'+str(i)+':',redis_conn.get('key'+str(i)))

你可能感兴趣的:(2020-10-25)