Cache distribué
L'implémentation technique de redis est souvent utilisée dans les caches distribués.
Problèmes et solutions de redis à nœud unique
- problèmes de perte de données
- Solution : implémenter la persistance redis
- Problèmes de concurrence
- Solution : créer un cluster maître-esclave pour obtenir une séparation lecture-écriture
- Problèmes de restauration
- Solution : utilisez Redis Sentinel pour la détection de l'intégrité et la récupération automatique
- problème de capacité de stockage
- Solution : créez un cluster partitionné et utilisez le mécanisme de slot pour obtenir une expansion dynamique
Persistance Redis
Endurance RDB
Le nom complet de RDB est le fichier de sauvegarde de la base de données Redis (fichier de sauvegarde des données Redis), également appelé instantané de données Redis. En termes simples, il enregistre toutes les données en mémoire sur le disque. Lorsque l'instance Redis échoue et redémarre, le fichier d'instantané est lu à partir du disque pour restaurer les données.
Les fichiers d'instantanés sont appelés fichiers RDB et sont enregistrés par défaut dans le répertoire d'exécution actuel.
sava #由Redis主进程来执行RDB,会阻塞所有命令
复制代码
bgsava #由子进程来执行RDB
复制代码
Lorsque bgsava démarre, il bifurque le processus principal vers le processus enfant, et le processus enfant partage les données de mémoire du processus principal. Lire les données de la mémoire et écrire le fichier RDB après avoir terminé le fork
fork utilise la technologie de copie sur écriture :
-
Lorsque le processus principal effectue une opération de lecture, il accède à la mémoire partagée ;
-
Lorsque le processus principal effectue une opération d'écriture, il copie une copie des données et effectue l'opération d'écriture
Remarque : RDB est automatiquement exécuté une fois lorsque Redis est fermé
Alors, RDB ne s'exécute-t-il que lorsque Redis est fermé ? bien sûr que non!
Il existe un mécanisme de déclenchement RDB dans Redis, qui se trouve dans le fichier redis.conf au format suivant :
# sava 时间(单位秒) key修改次数
sava 900 1 #900秒内如果有一个key被修改则执行bgsava
复制代码
Remarque : si c'est sava "" alors fermez le RDB
D'autres configurations de RDB peuvent également être définies dans le fichier redis.conf
#是否压缩,建议不开启,压缩也会消耗cpu,磁盘资源相对便宜
rdbcompression yes
#RDB文件名称
dbfilename dump.rdb
#文件保存的目录
dir ./
复制代码
Recommandation : Ne modifiez pas redis dans l'environnement de production pour éviter la perte de données
Persistance AOF
Le nom complet d'AOF est Append Only File. Chaque commande d'écriture traitée par Redis sera enregistrée dans le fichier AOF, qui peut être considéré comme un fichier journal de commandes.
AOF est désactivé par défaut, vous devez modifier le fichier de configuration redis.conf pour activer AOF :
#是否开启AOF功能,默认是no
appendsync yes
#AOF文件名称
appendfilename "appendonly.aof"
复制代码
La fréquence d'enregistrement des commandes AOF peut également être configurée via le fichier redis.conf
#表示每执行一次写命令,立即记录到AOF文件
appendsync always
#写命令执行完先放入缓冲区,然后每隔1秒将缓冲区数据写入到AOF文件,是默认方案
appendsync everysec
#写命令执行完先放入缓冲区,由系统决定何时将缓冲区内容写回磁盘
appendsync no
复制代码
élément de configuration | Synchronisation de la brosse | avantage | défaut |
---|---|---|---|
Toujours | brosse synchrone | Haute fiabilité, presque aucune perte de données | gros impact sur les performances |
chaque seconde | Pas de secondes pour se brosser | Performances modérées | Perdre des données jusqu'à 1 seconde |
non | contrôle du système d'exploitation | Meilleure performance | Mauvaise fiabilité, perte possible de grandes quantités de données |
因为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