分布式缓存

目录

Redis集群

一、Redis持久化

1.RDB持久化

测试

RDB底层原理

RDB缺点

2.AOF持久化

RDB和AOF对比

二、Redis主从

搭建主从架构

数据同步的原理

全量同步

增量同步

优化主从集群

总结

三、Redis哨兵

哨兵的作用

服务状态监控

选择新的master

实现故障转移

RedisTemplate的哨兵模式

四、Redis分片集群

散列插槽

集群伸缩

故障转移

RedisTemplate访问分片集群

Redis集群

单点Redis的问题:

  1. Redis是内存存储,服务重启可能会丢失数据

  2. 并发能力,不能满足高并发场景

  3. 故障恢复,如果Redis宕机,则服务不可用,需要一种自动恢复故障的手段(边运行,边修复)

  4. 存储能力,Redis是基于内存,单节点存储的数据量难以满足海量数据需求

因此利用集群的方式去解决以上的问题。

 

一、Redis持久化

1.RDB持久化

Redis Database Backup file(Redis数据备份文件)

数据快照,把内存中的所有数据都记录到磁盘中。当Redis实例故障后,从磁盘读取快照文件,恢复数据。

RDB文件默认保存在当前的运行目录

[root@localhost ~]#redis-cli 127.0.0.1:6369>save   #由Redis主线程来执行RDB,会阻塞所有的命令 
127.0.0.1:6369>bgsave #由后台异步执行,开启子进程执行RDB,避免主进程收到影响
Background saving started

Reids停机时会执行一次RDB

测试
redis-server redis-6.2.4/redis.conf ​ 
127.0.0.1:6379>redis-cli 
127.0.0.1:6379>set num 123 
127.0.0.1:6379>get num

默认在退出之前保存一次RDB

Redis内部由触发RDB的机制,可以在redis.conf文件中找到:

#900秒内,如果至少有1个key被修改则执行bgsave,如果是save""则表示禁用RDB 
save 900 1 
save 300 10 
save 60 10000

异步持久化:

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB 文件。

RDB底层原理

 

RDB方式bgsave的基本流程:

  • fork主进程得到一个子进程,共享内存空间。

  • 子进程读取内存数据并写入新的RDB文件。

  • 用新RDB文件替换旧的RDB文件。

RDB缺点
  • RDB执行间隔的时间长,两次RDB之间写入数据有丢失的风险。

  • fork子进程、压缩、写出RDB文件都比较耗时

2.AOF持久化

全称为Append Only File(追加文件)

把Redis处理的每一个命令都记录到AOF文件,可以看作是日志文件

[root@localhost redis-6.2.4]redis-cli
127.0.0.1:6379>set num 123
OK

 

其中:$3表示输入字符的长度

AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF

 

AOF的记录频率

# 表示每执行一次写命令,立即记录到AOF文件
appendsync alaways
#写命令执行完先放入AOF缓冲区,然后表示每隔一秒将缓冲区的数据写到AOF文件,也是默认方案
appendfsync everysec
#写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no

 因为将所有的命令都记录下来,会使AOF文件太大,因此,通过执行bgrewriteaof命令可以让AOF文件执行重写的功能,用最少的命令达到相同的效果。

用最少的命令达到相同的效果

 

RDB和AOF对比

 

二、Redis主从

搭建主从架构

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,旧需要搭建主从集群,实现读写分离

 

开启主从关系

配置主从可以使用replicaof或者slaveof(5.0之前)命令

有临时和永久两种模式:

  • 修改配置文件(永久生效):

    • 在redis.conf中添加一行配置:slaveof <masterip><masterport>

  • 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):

slaveof <masterip> masterport

5.0之后新增命令replicaof,与salveof效果一致

注意:从节点只能读不能写,读写分离

假设有A、B两个Redis实例,如何让B作为A的slave节点? ​ 
在B上执行`slaveof <Aip> Aport`
数据同步的原理
全量同步

主从第一次同步是全量同步:

 

1.master判断slave是不是第一次连接,是第一次全量同步(Full resync),不是第一次,增量同步

2.如果是第一次建立连接,master把RDB文件(所有数据)发送给slave;但是由于(bgsave是异步执行的,在发送过程中master还会处理用户的请求,可能会有新的数据写入到redis但是又没有同步到RDB文件里面)RDB的间隔很大,可能在间隔期间执行了写操作,所以引入了repl_backlog文件来记录在生成和发送RDB文件的过程期间收到的新的命令。以此使slave完整的获取到master的数据。

3.RDB文件中的data+repl_baklog文件中的data就是master节点上的完整数据

master如何判断slave是不是第一次来同步数据?   
    Replication:数据集的标记,id一致则说明是同一数据集。每一个master都有一个唯一的id,slave会继承master节点的replid。   
    offset:偏移量,随着记录在repl_baklog中的数据增多而增大,slave完成同步时也会记录当前同步的offest,如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。

这两个值用来判断是不是一个数据集和同步的进度。

完整的主从同步过程:

 

全量同步的过程:

  1. slave节点请求同步增量

  2. master节点判断replid,发现不一致,拒绝增量同步

  3. master将完整内存数据生成RDB,发送RDB到slave

  4. slave清空本地数据,加载master的RDB

  5. master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave

  6. slave执行接收到的命令,保持与master之间的同步

增量同步

 

repl_baklog可以看作是一个循环数组

 

repl_backlog大小有上限,写满后会覆盖最早的数据,如果slave断开时间过久,导致数据被覆盖则无法实现增量同步,只能再次全量同步

优化主从集群

 

总结

全量同步和增量同步

  • 全量同步: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哨兵

为了解决master宕机的问题:因为如果slave宕机可以从master恢复数据,但是master宕机怎么同步?

解决方案:

实时监测,只要master宕机就立刻选择slave作为新master。挂掉的master恢复之后就当slave。

 

哨兵的作用

主从切换

监控:Sentinel会不断检查您的master和slave是否按照预期工作

自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主

通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis客户端

服务状态监控

哨兵是如何监测节点下线的?

Sentinel是基于心跳机制检测服务状态,每隔1秒就向集群发送ping命令:

主观下线:如果(单个)sentivle节点发现某实例未在规定实例内响应,则认为是主观下线

客观下线:如果超过指定数量的(多个)sentinel都认为该实例主管下线,则该实例客观下线

选择新的master

首先判断slave与master节点断开时间长短,超过指定值(down-after-milliseconds)就排除

然后判断slave节点的slave-pripority值,越小优先级越高,如果是0永远不参加选举

如果slave-pripority一样,再看slave节点的offset(数据同步的进度),越大说明数据越新,优先级越高

最后看slave节点的运行id大小,越小优先级越高

实现故障转移
  1. sentinel通知备选的slave节点(发送slaveof no one命令),让其成为新的master

  2. sentinel再通知给所有的slave(发送slave of ip port命令),让他们成为新master的从节点

  3. 最后将故障节点标记为slave,当故障节点恢复后自动成为新的master的slave节点

RedisTemplate的哨兵模式

四、Redis分片集群

主从和哨兵可以解决高可用、高并发的问题,但是依然有两个问题没有解决:

  1. 海量数据存储问题

  2. 高并发写的问题

使用分片集群可以解决以上的问题

  • 集群中有多个master,每个master保存不同的数据

  • 每个master都可以由多个slave节点

  • master之间通过ping检测彼此的健康状态

  • 客户端请求可以访问集群任意节点,最终都会被转发到正确的节点

 

散列插槽

Redis会把每一个master节点映射到0~16383共16384插槽(hash slot)上

 

数据key不是和节点绑定,而是与插槽绑定。redis会根据key有效部分计算插槽值

1.key中包含{},且{}中至少包含一个字符,{}中部分是有效部分

2.key中不包含{},整个key都是有效部分

为什么要将数据与插槽绑定 因为redis的主节点是可能出现宕机的,或者增加删除主节点。如果数据绑定到节点,节点宕机或者被删除那数据也会跟着丢了,但是如果数据跟插槽绑定,当节点宕机时将这个节点对应的插槽转移到活着的节点,集群扩容时也可以将插槽进行转移,数据跟着插槽走永远都能找到数据的位置

步骤:

  • 将16384个插槽分配到不同的实例

  • 根据key的有效部分计算哈希值,对16382取余

  • 余数作为插槽,寻找插槽所在实例

如何将同一类的数据固定到同一个Redis实例中?

这一类数据都使用相同的有效部分,例如key都以{typeId}为前缀

集群伸缩

添加一个节点到集群

查找命令
redis-cli --cluster help
添加节点的命令
add-node  new_host:new_port existing_host:existing_port
          --cluster-slave
          --cluster-id<arg>

难点:插槽分配

redis-cli --cluster reshard ip:port
How many slots do you want to move (from 1 to 16384)?   #想移动插槽的数量
What id the receiving node ID?                          #要接收的id
Source node #1:                                         #插槽从哪里作为数据源
Source node #1: done                                    #结束
Do you want to proceed with the proposed reshard plan(yes/no)?   #是否继续执行重新分片的计划?   
故障转移

分片集群没有哨兵但是也具备故障转移的功能

查看集群节点实时状态:

[root@localhost redis]# watch redis-cli -p 7001 cluster nodes

当集群中有一个master宕机会发生什么呢?

1.首先是该实例与其他实例失去连接

2.然后是疑似宕机:

3.最后是确定下线,自动提升一个slave为新的master:

数据迁移

利用cluster failover命令可以手动让集群中某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:

 

手动的Failover支持三种不同模式:

  • 缺省:默认的流程,如图1~6步

  • force:省略了对offset的一致性校验

  • takeover:直接执行第5步,忽略数据一致性、忽略master状态和其他master的意见

[root@localhost redis]# bin/redis-cli -p 7002
127.0.0.1:7002> cluster failover
RedisTemplate访问分片集群

1.引入redis的starter依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

2.配置分片集群地址

spring:
  redis:
    cluster:
      nodes:
        - 192.168.31.181:7001
        - 192.168.31.181:7002
        - 192.168.31.181:7003
        - 192.168.31.181:8001
        - 192.168.31.181:8002
        - 192.168.31.181:8003

3.配置读写分离

    @Bean
    public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
        return new LettuceClientConfigurationBuilderCustomizer(){
            public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {
                clientConfigurationBuilder.readFrom(ReadFrom.REPLICA);
            }
        };
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值