Redis持久化及集群架构原理剖析

Redis持久化及哨兵架构搭建

RDB

save

所谓RDB快照文件,指的是redis会定期或者根据条件生成一个快照文件,可以凭借这个快照文件恢复redis数据;在重启redis服务端的时候会自动加载RDB文件,

redis数据库快照文件保存到dump.rdb文件中;

如何触发?-----可以通过设置 #Sava n秒 k个改动;即可让redis在n秒内根改了k个操作时触发save命令保存快照文件;

当然也可以手动执行save命令保存;每次执行都会覆盖原来的dump文件;变成一个新的快照文件;

save是同步操作,当需要保存的数据量过大时就会阻塞客户端请求,因为redis是基于单线程操作的,为了解决这个问题redis在1.1版本推出异步执行命令bgsave;

bgsave

redis不是单线程的嘛?怎么还能异步执行操作呢?这就需要借助操作系统提供的功能了:写时复制;简单来说就是主线程fork出一个子线程 ,子线程可以共享主线程的内存数据;bgsave 运行之后读取主线程内存数据,并写入dump文件;

两个线程操作互不影响;所以在读数据的时候都可以互相正常运行;但是如果主线程对数据进行写操作的话,就会将数据创建一个副本;bgsave操作这个副本将之写入文件;

两者对比

Redis持久化及集群架构原理剖析_第1张图片

缺点

  • 数据的持久化会导致一些近期数据丢失;

AOF

Rdb生成的快照文件是一个二进制文件,数据量大之后文件会变得非常庞大;

AOF则是记录所有操作的命令;将这些命令写入文件,这样在重启服务是就可以一次执行文件中的命令即可恢复数据;文件形式如下:

1 *3  # 多少个参数----set zhuge 666
2 $3
3 set  
4 $5   #KEY长度
5 zhuge  
6 $3  #value长度
7 666

星号代表参数的个数;$表示长度;

如何开启:appendonly yes ,在配置文件中;

执行时机:共有三个选项可以选择:

1 appendfsync always:每次有新命令追加到 AOF 文件时就执行一次 fsync ,非常慢,也非常安全。
2 appendfsync everysec:每秒 fsync 一次,足够快,并且在故障时只会丢失 1 秒钟的数据。
3 appendfsync no:从不 fsync ,将数据交给操作系统来处理。更快,也更不安全的选择。

默认每秒同步一次;

时间久了就会出现一个问题:命令很多,但是许多过程是重复的,我们只在乎最后的结果而已

所以AOF还搭配了一个重写功能,相当与重建二叉树那样,调整文件命令,只取最终结果;

AOF重写

如何设置?

1 # auto‐aof‐rewrite‐min‐size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就 很快,重写的意义不大 
2 # auto‐aof‐rewrite‐percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写

当然除了自动还有手动:通过bgrewirteaof即可实现;通过bg便可知道和bgsave一样通过子进程操作;

  • 如何选择AOP和RDB?

Redis持久化及集群架构原理剖析_第2张图片

可以看到各有各的优点,那么小孩子才做选择,大人当然是都要;redis在4.0后推出混合模式;

混合持久化

见名知意:RDB容易丢数据,但是体积小;那么使用RDB+ AOF不就ok了;

开启配置:前提是开启AOF;

# aof‐use‐rdb‐preamble yes //翻译:使用RDB做前缀;相当于把RDB文件数据放在前面;

实现思路:

某一刻:触发AOF,那么久将此刻之前的数据转为RDB放在AOF副本文件;在此刻新增的就使用AOF追加到文件末尾;在重写完成后覆盖原来的aof文件进行替换;

Redis主从架构

  • 什么是主从架构?

redis服务端只有一个的话如果宕机了就没办法了;所以需要搭建集群;主从;保证一个结点挂了之后也能运行

Redis持久化及集群架构原理剖析_第3张图片

搭建步骤

单机环境下复制一份新的rdis.conf文件修改端口号

将相关配置修改为如下值: 
port 6380 5 pidfile /var/run/redis_6380.pid # 把pid进程号写入pidfile配置的文件 
logfile "6380.log"
dir /usr/local/redis‐5.0.3/data/6380 # 指定数据存放目录 
# 需要注释掉bind 9 # bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通 过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可) 
配置主从复制 12 replicaof 192.168.0.60 6379 # 从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof 
replica‐read‐only yes # 配置从节点只读 
启动从节点 16 redis‐server redis.conf 
连接从节点 19 redis‐cli ‐p 6380 
测试在6379实例上写数据,6380实例是否能及时同步新修改数据

工作原理

如果一个master配置了一个slave;当这个slave连接上master之后,会发一个psync命令 给master请求复制数据;master收到命令后会在后台使用命令bgsave生成最新的rdb文件发送给slave,在持久化期间接受的客户端命令会缓存在一个buff中,持久化结束后再将其发送给slave;而slave在此期间一直在接受数据并生成rdb文件,之后加载到内存执行数据恢复;

Redis持久化及集群架构原理剖析_第4张图片

可是这样有一个问题,那就是每次从结点连接主节点是都是全量复制数据,效率肯定不是很高;所以redis在2.6后推出部分复制,向文件的断点续传一样;这样就可以实现在网络断开一段时间后还能正常接受没同步的数据;

实现思路:主节点维护一个数据下标,标明从结点复制数据的位置;master将数据放到缓冲区,slave从缓冲区获取;其中记录了master的进程id供slave识别,如果id发生变化,也就说明master变了,从而全量复制,

Redis持久化及集群架构原理剖析_第5张图片

管道及Lua脚本

客户端发送请求给服务端执行命令,只有收到回复之后才进行下一条,这样毋庸置疑耗费大量网络IO开销;那为什么不一次发送多条命令,再一次性返回呢;这就是管道出现的意义;

管道的目的是减少网络IO开销,就算命令执行失败也照常返回,并不是事务的功能;那么想要实现事务的功能该怎样实现呢?

  • lua脚本

和管道类似,也是建立连接发送批量命令;到与管道不同的是,lua能实现事务的功能;脚本将会本视为一个整体来执行;是原子操作;

使用方法:

 EVAL script numkeys key [key ...] arg [arg ...]
 - script : 最后会执行的脚本
 - numkeys : key的数量----通过KEYS[1]访问key;
 - arg : key对应的值-----通过ARGS[1]访问参数

案例:

127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1]+ARGV[2]}" 2 k1 k2 300 200
1) "k1"
2) "k2"
3) (integer) 500
解释:return key1 和 key2,对他们的值进行求和;

由此可知,可以在lua脚本中进行计算判断等操作,因此,不要再lua脚本中进行耗时的计算,不然客户端请求会被阻塞;

Redis哨兵高可用架构

Redis持久化及集群架构原理剖析_第6张图片

由图可见,客户端不再直接访问master,而是首先访问哨兵集群,通过哨兵集群获得主节点master的信息后再访问之;建立访问关系之后,哨兵会实时监控结点集群信息;当master发生变动,哨兵会通过订阅功能发布通知给客户端;

  • 哨兵的作用:

哨兵的目的就是为了监控redis-server集群的变动而存在的,当主节点挂了之后触发内部选举机制选举出一个新的主节点供客户端连接使用;那怎么样才能确定主节点挂了呢?当有一半的哨兵都认为master挂了之后才会触发选举;选举结束后通过订阅将消息通知给客户端,客户端监听消息从而动态切换访问;

了解一下即可,真正使用的还是cluster集群

  • 缺点:集群不方便水平扩展;如果master节点异 常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现 一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持 很高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的 效率

高可用集群Cluster

Redis持久化及集群架构原理剖析_第7张图片

  • 由图可见,该集群模式可用性极强,对客户端提供服务也多;同时水平扩展也很方便;配置也不复杂,总之优点多多

如何搭建不多赘述;

集群原理分析

redis Cluster将数据划分为16384个槽位;由每个结点占用其中一部分槽位,槽位信息存储在结点数据中;

这样当客户端连接集群是也会获得一份槽位信息,访问数据信息是会获得对应的槽位,根据槽位直接访问目标结点进行连接获取数据;

redis采用crc16算法进行hash得到一个整数值,然后用这个整数值对16384取模得到具体槽位;—HASH_SLOT = CRC16(key) mod 16384

如果向一个结点发送的key的槽位不属于该结点是会重定向到目标结点进行操作;

  • 那么集群结点之间是如何进行通信的呢?

redis cluster结点之间采用 gossip进行通信;对于集群的元数据的维护:通常有集中式和gossip两种;

集中式:将元数据信息集中存放在一个地方,这样每个结点都访问这个地方获得结点和集群的元数据;有更新时也会更新这个位置,其他结点也能立马得到通知响应;很多中间件借助zookeper存储数据;

gossip:结点之间互相发送消息;交换元数据信息;

Redis持久化及集群架构原理剖析_第8张图片

网络抖动:在真实网络环境中,因为网路抖动的缘故,使得某些结点会突然断开又很快重连,这样使得主从切换很频繁;可以通过配置cluster-­node­-timeout 当结点持续断连timeout之间后才开启选举

  • 选举原理

    当slave发现自己的master变为FAIL状态之后;与该结点的其他slave竞争成为master;过程如下:

    Redis持久化及集群架构原理剖析_第9张图片

  • 集群脑裂问题

    redis的集群脑裂是指因为网络问题,导致redis master节点跟redis slave节点和sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点。此时存在两个不同的master节点,就像一个大脑分裂成了两个。
    集群脑裂问题中,如果客户端还在基于原来的master节点继续写入数据,那么新的master节点将无法同步这些数据,当网络问题解决之后,sentinel集群将原先的master节点降为slave节点,此时再从新的master中同步数据,将会造成大量的数据丢失。

    规避方法可以在redis配置里加上参数(这种方法不可能百分百避免数据丢失,参考集群leader选举机制):

    min‐replicas‐to‐write 1 //写数据成功最少同步的slave数量,这个数量可以模仿大于半数机制配置,比如 集群总共三个节点可以配置1,加上leader就是2,超过了半数
    

    目的就是让整个集群架构从结点最少同步数量超过一半才开始把多之前的主节点降级;

Redis持久化及集群架构原理剖析_第10张图片

Redis持久化及集群架构原理剖析_第11张图片

你可能感兴趣的:(Redis,redis,架构,缓存)