redis分布式以及持久化机制(主从、哨兵、分片、RDB、AOF)

单节点存在问题:

  1. 数据安全问题 :redis基于内存存储,如果主机损坏且没有进行数据备份的话,会造成数据丢失。即使进行备份,如果RDB后突然断电,那么在这期间后主机上的写数据将全部丢失
  2. 并发能力问题:虽然redis是基于内存存储,并发能力很强。但毕竟是单节点,并发能力有限
  3. 故障恢复问题:单节点一但出现故障,就会影响服务。redis负责的功能将不能自行恢复
  4. 存储能力问题:单个机器的内存是有限的

redis持久化

redis是基于内存存储的,内存的存储会导致:断电即失、数据不可迁移备份

RDB

RDB 即 Redis Database Backup file (redis数据备份文件) 也为 快照机制 默认开启
某一时刻的数据全部一起写入磁盘文件中 。redis重启后会读取磁盘文件的数据放入内存,使得恢复至那一时刻。且备份文件可以移动,使得多个redis都可以恢复至那一刻,达到备份的效果。RDB在数据恢复时较快
备份命令

  • save
    • 缺点:此命令是由主进程进行执行的,在执行时会进行阻塞,在执行完成之前,其他命令都不可以执行。但保存到磁盘是一个IO操作,又比较耗时
    • 适用场景:在redis手动关机前进行备份
  • bgsave
    • 开启子线程进行一步保存,避免主线程受到影响
    • 适用场景:在redis自动备份时

RDB文件存放目录:默认存放在 运行redis时所在的目录,可在配置文件中修改

在这里插入图片描述

RDB 触发
  1. redis在正常关机前会进行一次 save
  2. 每隔一段时间触发 ,频率可修改
  3. 在进行全量同步时会触发
    在这里插入图片描述

若要关闭 RDB 可以将其注释并添加 save “”

RDB的配置
  1. 是否开启间隔保存?默认开启,关闭需要写入save ""
  2. RDB文件名称:在这里插入图片描述
  3. RDB是否进行压缩:压缩会耗费CPU资源和时间,但节省磁盘空间 通常选择不压缩,更多时候相比来说cpu资源(性能)更重要
    在这里插入图片描述
  4. 保存RDB文件的路径
    在这里插入图片描述
RDB异步持久化原理
  1. 执行bgsave命令时,主进程会fork一个子进程(此期间阻塞)用来执行异步IO保存主进程中的数据。但子进程如何访问主进程的数据呢?
    主进程访问内存使用页表,将页表进行拷贝给子进程,从而使得子进程也能够操作同一个内存地址的数据,这时共享的内存数据将会变成只读数据,防止主进程在复制时数据发生修改。

在这里插入图片描述

  1. 如果这时主进程有写入,就会查找写入数据的地址然后进行单独复制一份进行写入(copy-on-write技术),防止直接在共享中内存写入导致数据不一致问题
    在这里插入图片描述
    但这样存在的一个极端条件下的问题:如果在子进程IO内存数据期间,所有数据都发生改动,会导致从共享数据中拷贝同样大小的那些数据用作修改,会导致内存突然翻倍,所以要留充足的内存,尽量避免内存溢出
  2. 将子进程写完的文件替换原有文件

RGB缺点
io读写需要耗费性能与内存,不能过于频繁。但如果在每次备份间隔期间发生宕机,会导致在此时与上次备份这期间的新增或修改的数据全部丢失。数据可能会丢失一部分,不能用于RDB存储对数据安全有要求的。

AOF

AOF:Append Only File 每一个写命令都会被记录在AOF文件,相当于数据操作日志。在恢复时由于记录中之前所有增删改命令,可以再次从头到尾执行这些命令,从而恢复数据 。默认不会开启,由主进程进行操作

由于数据持久化频率比RDB频率高,因此可用作对RDB数据丢失风险的一种弥补。但AOF仍有频率间隔(默认每秒),在这期间仍然有可能发生数据丢失。

AOF记录的写数据的操作过程,而RDB记录的是最终数据结果。所以AOF文件会比RDB大很多

AOF触发

在开启Aop的条件下:
在这里插入图片描述
在这里插入图片描述

AOF的配置
  • 开启AOF:
    在这里插入图片描述
  • 修改AOF文件名
    在这里插入图片描述
  • 修改AOF重写阀值
    在这里插入图片描述
AOF重写

由于AOF记录写过程,文件会很大。但这些过程如果其中有对一个key多次进行修改那么只需要记录最后一次即可,其他关于key的记录将变得毫无意义。所以当记录一定数量命令时,要考虑去除无意义的命令,并考虑合并命令使得用最少的命令达到相同的效果,减少文件体积

例如:
在这里插入图片描述
AOF可以使用命令 bgrewirteaof异步执行重写
也可以配置 使得符合条件时,自动触发AOF重写
在重写期间产生的数据会放入缓冲区,当重写完毕后,进行追加。

AOF重写触发

在这里插入图片描述
如何解决AOF的子进程在重写aof文件时,数据发生变化?
Redis 引入了 AOF 重写缓冲区(aof_rewrite_buf_blocks),这个缓冲区在服务器创建子进程之后开始使用,当 Redis 服务器执行完一个写命令之后,它会同时将这个写命令追加到 AOF 缓冲区AOF 重写缓冲区

二者对比

在这里插入图片描述
两者详细说明

主从集群

主从数据一致,将读写进行分离,提升读并发能力(不能提升 储存能力,因为空间并未扩容。不能提升 写能力,因为只有master能够写,而master数量没有变)
在这里插入图片描述

搭建集群

搭建三台集群步骤
规划 同一个主机通过更改端口运行三个redis

IPPORT角色
本机7001master
本机7002slave
本机7003slave
  1. 创建三个目录 拟三个不同的主机 将原始配置文件拷给三个目录(不同主机可省略)

  2. 修改各自目录下的 端口号工作目录 (不同主机可省略)

    • 使用命令批量替换
    sed -i -e 's/6379/目标端口/g'  -e 's/dir .\//dir(原内容)  (目标目录)/g'  (要替换的目录  每级目录使用 \/  相隔)   (要修改的文件路径)
    

    例 :
    在这里插入图片描述

    可一键完成当前文件对端口,以及工作目录的修改

  3. 修改每个配置文件的ip ,即使是同一个主机下也要声明出来,避免自动读取的ip不一致
    修改配置 replica-announce-ip : 本机ip

    sed -i '1a replica-announce-ip 主机ip' 配置文件路径
    

注意 :在搭建集群前,一定要将密码关闭 ,或者在从节点配置文件中 加上主节点的密码 “masterauth 密码”!!!
然后 将三个redis服务器启动
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

使用redis-cli -p 各自的端口 连接服务器

开启主从联系
此时,服务器间彼此毫无关系,独立的三个redis,要想形成主从集群,要将他们进行连接。只需slave指明是谁的从节点即可。

  • 临时配置 在命令窗口中 输入 slaveof <masterIp> <masterPort>
  • 永久配置 在redis配置文件 添加 slaveof <masterIp> <masterPort>

整体流程:先建立三个不同的redis,在通过 slaveOf masterIp masterPort 将他们进行主从连接

主从数据同步原理

第一次同步为全量同步,但怎样判断是不是第一次同步呢?
根据 replidReplication Id :每一个master都有唯一的replid,而slave会继承master的replid,使得每一个数据集都会有唯一的replid。

所以,当有节点发起数据同步请求时,master只需要判断其replid与自己的是否一致。若不一致,说明是第一次同步,因为只要进行过同步就会一致。 若一致,说明与其在同一个数据集,已经不是第一次同步,无需将自己的全部数据都给与slave节点(全量同步)。只需要判断salve与自己数据相差多少(偏移量 offset) 。主机自己的偏移量会记录在repl_baklog(将要进行同步给salve的数据缓存在这里)中数据增多而增大,每次同步slave会记录自己同步数据的offset,当有新数据自己还未更新时,repl_backlog中的偏移量会大于slave的偏移量。

同步过程

  1. salve与master建立正常连接
  2. salve 会 发起sync同步请求,请求中携带自己的 replidoffset 给master节点。
  3. master节点接收到请求中的replid去判断与自己replid的是否一致。若不一致则是第一次同步,要进行全量同步。若一致,则要进行增量同步
    • 全量同步过程:性能较差
    1. master进行一次 bgsave(fork一个子线程去做),将自己所有的数据写入一个RDB文件,发送给salve节点,salve节点接收到全量同步会将自己的数据全部清除,迎接新的数据
    2. 在写RDB时,将有关 写数据的命令 暂时放入到 repl_baklog
    3. 将RDB发送给salve后,再将在自己的repl_backlog中的数据持续传给salve节点,salve不断接收命令,不断去执行,使得主从之间数据能够一致(但此过程不叫增量同步,仍是一次连接)不是断开后再进行同步 就不是增量同步
      增量同步(常发生在从节点宕机重连时)
      可能是salve 发生宕机,使得与master已经连接过,再失去联系,等待其正常后,会再次向master发起以上三点
    4. master判断不是第一次请求,会向其发送一个continue命令(因为salve不知道自己是不是第一次)
    5. 然后master将请求中的offset与自己的repl_backlog去做对比,判断是否相差的数据都在自己的repl_backlog中数据的范围内
    6. 若相差已经超过repl_backlog中的所有数据,导致缺失的数据被新数据覆盖,同步缓存中找不到,只能去内存中查找,此时重新进行增量同步 (从上面第4点开始)。若相差数据都在repl_backlog中,则将差的数据进行同步。

整体流程
在这里插入图片描述

数据同步优化
数据优化主要在 全量同步,因为需要进行阻塞fork、IO操作

  1. 在master中 ,同步时采用 无磁盘IO repl-diskless-sync设置为yes,将数据不再写入磁盘而是转为流通过网络进行传输,但要有足够的网络带宽(增大全量同步效率)
  2. 尽量增大repl_backlog ,避免增量同步时,主节点缓存传输数据空间不足,数据被覆盖导致采用较慢的全量同步(减少使用全量同步)
  3. 限制master节点管理slave节点的数量,避免过多的节点数据同步影响master节点的性能。若仍需要很多的从节点,可以采用master-salve-salve 使得从节点同步从节点,减轻master的压力
  4. 单个节点内存不要过高,过高会导致服务器后期数据量大,一次RDB,文件会非常大且耗时

哨兵机制

集群当前如果有master节点宕机,集群是不能自己进行恢复的 ,需要人为手动恢复。而引入哨兵,可以实现监控而自动恢复功能,可为客户端对集群的连接提供方便。
哨兵们(哨兵也要为集群) 检测到master宕机后,从salve中选举一个作为master,使得集群立即恢复正常运转,并将宕机的master置为salve

哨兵作用
在这里插入图片描述

状态监控

不断检测 master与slave的正常

  • 基于心跳机制检测,每隔哨兵 每隔一秒向集群每一个节点发送一个ping,等待收到一个pong。若某个哨兵发送给某个节点的ping 超时了仍未收到恢复,则这个哨兵认为这个节点宕机了 主观下线
  • 若其他哨兵也为收到此节点的恢复,且未收到回复的哨兵们已经超过一半(数量自己设置)了。则认为是客观下线
  • 被认为是客观下线后,就要采取行动, 从slave中 选取一个节点作为master
故障恢复

master宕机后,要从slave中选出一个承担master的作用,实现集群的恢复
先去选举一个哨兵去做master选举
看谁先发宕机选举权就交给哪个哨兵

选取master的标准

  1. 先进行排除 :排除掉与master 失去连接过长的(down-after-milliseconds*10)。即使没有slave了,也不能使用,因为失去连接时间过长,可能有大量数据丢失,过旧
  2. 判断slave的优先级(slave-priority),是否已经人为指定顺序 .为0 则不参与选举
  3. 对比各个slave的offset ,值越大 越说明当前值与master越接近,通常是选举中最有决定性的
  4. 比较运行id大小,此时slave已经没有区别,只要有一个就行

哨兵们选取出哪一个slave作为master后,向其slave发送一个命令 slaveof no one 告诉其永不为奴,
然后发布通知告诉所有slave ,master是谁,使得再次以恢复主从集群。
为了使得老master恢复后,不影响当前状态,在其配置文件中打上 slave印记,使其醒来后做slave

通知

集群主从关系发生了变化,负责写的master地址已经发生变化,有的节点甚至不可用。但客户端怎么知道呢?因此需要用到sentinel的一个通知功能(路由)。相当于一个网关,客户端只连接哨兵,而不关心集群的具体主机,在访问主机资源时,只需要先去访问哨兵,又哨兵再找到具体对应的主机。这样即使master地址发生变化,也无需客户端关心。
但如果哨兵宕机了怎么办?哨兵采用的是集群,在客户端配置的也是集群中各个哨兵的地址。如果其中有一个宕机,还可以去问下一个

搭建哨兵集群

哨兵与节点不是一个共同体,是一个redis包下一个单独的应用
由于模拟搭建都在一个主机,通过更改其端口号,使其各自能够独立运行
整体规划

节点IPPORT
s1本机27001
s2本机27002
s3本机27003

为每个哨兵单独创建一个目录,然后在目录中创建各自的配置文件 sentinel.conf

在这里插入图片描述
哨兵虽然监控集群每一个节点,但只要配置master节点,就可以知道其slave的信息 ,每一个哨兵只有端口、工作目录 不同,将配置文件这两处进行修改,然后放各自的目录

启动哨兵集群
在这里插入图片描述

测试 :当master宕机,观察sentinel的变化

在这里插入图片描述

当老的master重新启动时,发现自己已经变成了slave

客户端连接主从集群
  1. 客户端不再去连接主节点的地址,而是去连接哨兵集群

在这里插入图片描述

  1. 指明集群环境下采用的读写策略 ,因为配置主从集群的目的就是实现读写分离
    在这里插入图片描述
    配置好哨兵集群后,哨兵会自动找到主节点与从节点,客户端无需关系集群内部信息

分片集群

解决单节点不能内存过大(RDB过大),且数据量很大时的存储问题。解决高并发环境下 并发写的问题,同时具有哨兵功能,实现高可用
主从集群数据是相同的,并未提升数据存储能力,且从节点都是用来读的,只有一个master节点负责写,未提升写的能力
分片集群集合主从集群可以解决并发写、并发读、高存储容量、高可用性
在这里插入图片描述
常用命令

  • 添加节点 redis-cli --cluster add-node 【主机Ip】【端口】【集群中某一个主机Ip】【其端口】 将一个独立运行的节点添加到集群
  • 查看集群信息cluster nodes
  • 分配插槽redis-cli --cluster reshard 【集群中任意一个主机ip】:【其端口】确保知道要分配哪个集群的插槽
  • 删除一个节点 redis-cli --cluster del-node 【集群中任意一个主机ip】:【其端口】【要删除的节点id 】 在删除前,要注意其插槽
  • 连接集群的主机 :要在普通连接命令中加上 -c

搭建分片集群

三个master之构成分片集群,同时每一个master有自己的主从集群
整体安排

IPPORT角色
本机7001master
本机7002master
本机7003master
本机8001slave
本机8002slave
本机8003slave
  1. 修改配置文件
    cluster-enabled 设为 yes,同时指定自动生成集群文件存放路径 cluster-config-file /xxx/xxx/nodes.conf(每个节点集群的一些信息会放在这里,要保证每一个节点都有自己的一分 nodes.conf)
    例 :简化版的redis.conf
port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.150.101
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log
  1. 修改各自的端口、文件存放路径 启动所有redis
  2. 此时他们是具有集群功能的各个独立的主机,需要将他们组建成一个集群
    使用命令 redis-cli --cluster create --cluster-replicas 副本数量 master1地址及端口 master2地址及端口 ... slave1地址及端口 slave22地址及端口..一键创建关系
    由于指定了每个master从节点数量,先写master们地址,再写slave们地址 就会自动分辨出谁是谁的从节点
    在这里插入图片描述
  3. 连接集群某一个节点是,不光要指定集群中某个主机的ip(-p),还要加上 集群模式 (-c)

散列插槽

采用分片集群提升了redis整体的存储能力,但redis是怎样将一个数据存入带有三个master集群的呢?数据是从一个存满再存下一个显然是不可能的,要将数据尽量均匀的分布在三个集群。但怎样进行分配呢?如何记录数据在哪个节点上呢?
使用散列插槽机制。将集群中master的存储容量划分为 16384个插槽,将数据进行哈希散列后对16384取余即可获取数据存放的插槽。有了插槽机制,使得集群中内存利用的更加充分,能够将数据进行较为均匀的分布,也能查找时,通过哈希计算得出数据存放位置,免得去保存每一个key所在位置。同时,也可以使得数据与插槽绑定,模块化 方便迁移
数据不是与节点进行绑定,而是与插槽进行绑定。数据可以随着插槽移动进行移动,方便查找数据的同时也方便集群的扩充和缩减

redis会将key的有效部分进行计算(通过crc16算法 获取哈希值 并处以16384),获取插槽位置
有效部分分为两种情况:

  • 不带{},将整个key都作为有效部分
  • {},只将{}中的内容作为有效部分,因此要想使得 不同的key能够放在同一个插槽(如果可能会连续记性访问,尽量放入一个插槽。如果不在一个主机,还需要进行重定向到另一个主机,耗费时间),所以尽量使得可能连续的key {}中的内容相同

例:
在这里插入图片描述
在这里插入图片描述

get key 过程
在这里插入图片描述
总结
在这里插入图片描述
如果有一个插槽无法正常使用 ,整个集群将不可用。例:只有一个插槽的master宕机,且没有从节点,无法自主恢复,整体集群将不可用

集群伸缩
  • 添加节点 redis-cli --cluster add-node 【主机Ip】【端口】【集群中某一个主机Ip】【其端口】
    在添加节点时需要指定要添加的节点信息以及要入集群的介绍人。不指定参数默认为master。要添加从节点需要添加 --cluster-slave ,若要指定添加到哪个master,需要指定其master的id --cluster-master-id 【masterId】

在添加前,确保配置中已经打开集群模式,能够独立运行。然后使用 redis-cli --cluster 命令将其添加到集群

但后加入的节点没有插槽,要将原有插槽进行分配

  • 分配插槽 redis-cli --cluster reshard 【集群中任意一个主机ip】:【其端口】确保知道要分配哪个集群的插槽
    在这里插入图片描述

例:
在这里插入图片描述

  1. 先修改配置文件,开启集群模式,然后启动
  2. 将此节点添加到集群
    在这里插入图片描述
  3. 为新加入的节点分配插槽,由于 key为num的值放在了 2765号插槽中,因此需要将此插槽移动到新master
    在这里插入图片描述
  4. 分配插槽
    将7001的 2800个插槽移动到 7004 中 。因为num在第2765个插槽,所以也会移动到新节点中。

例:删除7004节点
5. 将7004节点的所有插槽进行转移到其他节点
6. 将 7004 节点关机
7. 使用命令 redis-cli --cluster del-node 集群联系人 要删除的节点id 彻底删除一个节点

如果直接关机,如果7004没有slave且自己又有插槽数据,将会直接导致整个集群不可用

故障转移

与哨兵机制相同,可以看做在分片集群中,master之间集成了哨兵集群,具有相同的功能
有任何一台master宕机会立即被监测出来,使用它的slave来替代它
也可以在master完好的情况下手动完成 masterslave的互换 常用于 升级master主机,向让新设备成为master的slave,在手动让二者身份互换。这样 老的master 就可以作为slave或停机。在其从节点使用cluster failover 完成手动切换身份
failover 中文翻译:故障切换

在这里插入图片描述
具体细节:

在这里插入图片描述
可选参数

  • 在其cluster failover 后面添加上 force不会在移交期前 对offset进行校验,可能导致从节点数据不全
  • 在其cluster failover 后面添加上 takeove,将只有第6步,直接通知所有节点。忽略所有准备,类似于master宕机后,继位的从节点的行为。可能导致数据丢失,数据不一致。
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值