Redis implements distributed caching

Distributed cache

The technical implementation of redis is often used in distributed caches.

Problems and solutions of single-node redis

  • data loss issues
    • Solution: Implement redis persistence
  • Concurrency issues
    • Solution: Build a master-slave cluster to achieve read-write separation
  • Failback Issues
    • Solution: Use Redis Sentinel for health detection and automatic recovery
  • storage capacity issue
    • Solution: Build a sharded cluster and use the slot mechanism to achieve dynamic expansion

Redis persistence

RDB endurance

The full name of RDB is Redis Database Backup file (Redis data backup file), also known as Redis data snapshot. Simply put, it records all the data in memory to disk. When the Redis instance fails and restarts, the snapshot file is read from the disk to restore the data.

Snapshot files are called RDB files and are saved in the current running directory by default.

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

When bgsava starts, it will fork the main process to the child process, and the child process shares the memory data of the main process. Read memory data and write RDB file after completing fork

fork uses copy-on-write technology:

  • When the main process performs a read operation, it accesses shared memory;

  • When the main process performs a write operation, it will copy a copy of the data and perform the write operation

Note: RDB is automatically executed once when Redis is closed

So does RDB only execute when Redis is closed? of course not!

There is a triggering RDB mechanism inside Redis, which can be found in the redis.conf file in the following format:

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

Note: if it is sava "" then close the RDB

Other configurations of RDB can also be set in the redis.conf file

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

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

Recommendation: Do not modify redis in production environment to avoid data loss

AOF persistence

The full name of AOF is Append Only File. Each write command processed by Redis will be recorded in the AOF file, which can be regarded as a command log file.

AOF is disabled by default, you need to modify the redis.conf configuration file to enable AOF:

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

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

The frequency of AOF command recording can also be configured through the redis.conf file

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

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

#写命令执行完先放入缓冲区,由系统决定何时将缓冲区内容写回磁盘
appendsync no
复制代码
configuration item Brush timing advantage shortcoming
Always synchronous brush High reliability, almost no data loss big performance impact
everysec No seconds to brush Moderate performance Lose data for up to 1 second
no operating system control best performance Poor reliability, possible loss of large amounts of data

因为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

Guess you like

Origin juejin.im/post/7079790577805443109