Redis implementa cache distribuído

Cache distribuído

A implementação técnica do redis é frequentemente usada em caches distribuídos.

Problemas e soluções de redis de nó único

  • problemas de perda de dados
    • Solução: Implemente a persistência do redis
  • Problemas de simultaneidade
    • Solução: crie um cluster mestre-escravo para obter a separação de leitura e gravação
  • Problemas de failback
    • Solução: use o Redis Sentinel para detecção de integridade e recuperação automática
  • problema de capacidade de armazenamento
    • Solução: crie um cluster fragmentado e use o mecanismo de slot para obter expansão dinâmica

Persistência do Redis

Resistência RDB

O nome completo do RDB é arquivo Redis Database Backup (arquivo de backup de dados Redis), também conhecido como instantâneo de dados Redis. Simplificando, ele grava todos os dados na memória em disco. Quando a instância do Redis falha e é reiniciada, o arquivo de instantâneo é lido do disco para restaurar os dados.

Os arquivos de instantâneo são chamados de arquivos RDB e são salvos no diretório em execução atual por padrão.

sava #由Redis主进程来执行RDB,会阻塞所有命令
复制代码
bgsava #由子进程来执行RDB
复制代码

Quando o bgsava é iniciado, ele bifurca o processo principal para o processo filho, e o processo filho compartilha os dados de memória do processo principal. Leia os dados da memória e grave o arquivo RDB após concluir o fork

fork usa tecnologia copy-on-write:

  • Quando o processo principal realiza uma operação de leitura, ele acessa a memória compartilhada;

  • Quando o processo principal executa uma operação de gravação, ele copia uma cópia dos dados e executa a operação de gravação

Observação: o RDB é executado automaticamente uma vez quando o Redis é fechado

Então, o RDB só é executado quando o Redis está fechado? claro que não!

Existe um mecanismo RDB de acionamento dentro do Redis, que pode ser encontrado no arquivo redis.conf no seguinte formato:

# sava 时间(单位秒) key修改次数
sava 900 1 #900秒内如果有一个key被修改则执行bgsava
复制代码

Nota: se for sava "" feche o RDB

Outras configurações do RDB também podem ser definidas no arquivo redis.conf

#是否压缩,建议不开启,压缩也会消耗cpu,磁盘资源相对便宜
rdbcompression yes
	
#RDB文件名称
dbfilename dump.rdb

#文件保存的目录
dir ./
复制代码

Recomendação: Não modifique o redis no ambiente de produção para evitar perda de dados

Persistência AOF

O nome completo do AOF é Append Only File. Cada comando de gravação processado pelo Redis será registrado no arquivo AOF, que pode ser considerado um arquivo de log de comandos.

O AOF está desabilitado por padrão, você precisa modificar o arquivo de configuração redis.conf para habilitar o AOF:

#是否开启AOF功能,默认是no
appendsync yes

#AOF文件名称
appendfilename "appendonly.aof"
复制代码

A frequência de gravação do comando AOF também pode ser configurada através do arquivo redis.conf

#表示每执行一次写命令,立即记录到AOF文件
appendsync always

#写命令执行完先放入缓冲区,然后每隔1秒将缓冲区数据写入到AOF文件,是默认方案
appendsync everysec

#写命令执行完先放入缓冲区,由系统决定何时将缓冲区内容写回磁盘
appendsync no
复制代码
item de configuração Tempo da escova vantagem deficiência
Sempre escova síncrona Alta confiabilidade, quase sem perda de dados grande impacto no desempenho
cada segundo Sem segundos para escovar Desempenho moderado Perde dados por até 1 segundo
não controle do sistema operacional melhor performance Baixa confiabilidade, possível perda de grandes quantidades de dados

因为AOF是记录命令,所以AOF文件会比RDB文件大很多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。

Redis也会在出发阈值时自动去重写AOF文件,阈值也可以在Redis.conf中配置

#AOF文件比上次文件增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
#AOF文件体积超过多少就触发重写
auto-aof-rewrite-min-size 64mb
复制代码

RDB与AOF对比

RDB和AOF各有自己的优缺点,如果对数据的安全要求比较高就使用AOF反之则使用RDB,在实际的开发中往往会二者结合使用。

RDB AOF
持久化方式 定时对整个内存做快照 记录每一次写命令
数据完整性 不完整,两次备份之间会丢失 相对完整,取决于刷盘策略
文件大小 会有压缩,文件体积较小 记录命令,文件体积很大
宕机恢复速度 很快
数据恢复优先级 低,因为数据完整性不如AOF 高,因为数据完整性更高
系统资源占用 高,大量cpu和内存消耗 低,主要是磁盘IO资源,但AOF重写时会占用大量CPU和内存资源
使用场景 可以容忍数分钟的数据丢失,追求更快的启动速度 对数据安全性要求高

Redis主从

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

数据同步

master如何判断slave是不是第一次来同步数据?这里会用到两个概念:

  • Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
  • offset:偏移量,随着记录在rep_baklog中的数据增多而逐渐增大。slave完成同时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新,因此slave做数据同步,必须向master声明自己的replication id和offset

全量同步步骤

  • slave节点请求增量同步
  • master节点判断replid,发现不一致拒绝增量同步
  • master将完整内存数据生成RDB,发送RDB到slave
  • slave清空本地数据,加载master的RDB
  • master将RDB期间的命令记录到rep_baklog,并持续将log中的命令发送给slave
  • slave执行接收到命令,保持与master之间的同步

增量同步步骤

  • slave节点携带replid和offset请求增量同步
  • master节点判断replid和offset,replid一致,offset落后于maset回复continue
  • maset去repl_baklog中获取offset后的数据发送给slave
  • slave执行命令

注意:repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步

Redis主从数据同步优化

  • 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘io(会比较吃网络性能,带宽高的情况下使用)
  • Redis单节点上的内存占用不要太大,减少RDB导致的过多内存损耗
  • 适当提高repl-baklog的大小,发现slave宕机尽快实现故障恢复,尽可能避免全量同步
  • 限制一个master上的slave节点数量,如果slave节点实在太多可以采用主-从-主链式结构,减少master压力

Redis哨兵

在主从结构中slave宕机之后可以从master节点恢复数据,那么master节点宕机之后呢?

这里就需要使用redis的哨兵来进行故障恢复,节点选举,服务监控

  • 监控:Sentinel会不断检查你的master和slave是否按预期在工作
  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis客户端

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

  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。

quorun的值最好超过sentinel实例数量的一半

选举原则

一单发现master故障,sentinel需要在salve中选择一个新的master:

  • 首先判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds*10)则会排除该slave节点
  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永远不参与选举
  • 如果slave-proity值一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
  • 最后判断slave节点的运行id,越小优先级越高

故障迁移

当选中了其中一个slave为新的master后(例如slave1),故障迁移的步骤如下:

  • sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
  • sentinel给所有其它slave发送slaveof 新master IP 命令,让这些slave成为新master的从节点,开始从新的master上同步数据
  • 最后,sentinel将故障节点标记为slave,当故障节点恢复后自动成为新的slave节点

RedisTemplate集成哨兵模式

依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
复制代码

配置

spring:
  redis:
    sentinel:
      master: mymaster
      nodes:
        - 127.0.0.1:27001
        - 127.0.0.1:27002
        - 127.0.0.1:27003

复制代码

配置主从读写分离

@Bean
    public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
        return configBuilder -> configBuilder.readFrom (ReadFrom.REPLICA_PREFERRED);
    }
复制代码

ReadFrom读取策略

•MASTER:从主节点读取

•MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica

•REPLICA:从slave(replica)节点读取

•REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

分片集群

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

  • 海量数据存储问题
  • 高并发写问题

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

  • 集群中有多个master,每个master保存不同数据
  • 每个master都可以有多个slave节点
  • master之间通过ping监测彼此健康状态
  • 客户端请求可以访问集群任意节点,最终都会被转发到正确节点

散列插槽

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

数据key与插槽绑定。redis会根据kety有效部分计算插槽值,分两种情况:

key中包含“{}”,且"{}"中至少包含一个字符,"{}"中的部分是有效部分

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

例如:{typeId}typeName typeId是计算插槽值有效部分,key为typeIdtypeNema

Acho que você gosta

Origin juejin.im/post/7079790577805443109
Recomendado
Clasificación