Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 基础篇
  • 数据类型篇
  • 持久化篇
  • 网络模型篇
  • 缓存篇
  • 高可用篇
    • 主从
      • 全量同步
      • 增量同步
      • repl_backlog原理
      • 主从同步优化(优化Redis主从集群)
      • 过期key如何处理?
      • 同步复制还是异步复制?
      • 主从数据不一致
    • 哨兵
    • 集群
      • 散列插槽
      • 一致性哈希
  • 实战篇
  • 拾遗篇
  • Redisson
  • Redis
Nreal
2023-11-15
目录

高可用篇

# 主从

# 全量同步

主从第一次建立连接时,会执行全量同步,将master节点的所有数据都拷贝给slave节点

如何知道是第一次连接:

Replication Id:数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid

offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新

replid不一致,就是第一次连接,直接全量同步

  • slave节点请求增量同步

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

  • master将完整内存数据生成RDB(bgsave),发送RDB到slave

    主服务器生成这个RDB不会阻塞主线程,bgsave命令会产生一个子进程来生成RDB文件,异步工作;

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

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

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

master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave;

简单来说三阶段:

  1. 建立链接,协商同步;
  2. 主服务器同步数据给从服务器;
  3. 主服务器发送新写操作命令给从服务器;

# 增量同步

全量同步需要先做RDB,然后将RDB文件通过网络传输个slave,成本太高了。因此除了第一次做全量同步,其它大多数时候slave与master都是做增量同步

slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave

# repl_backlog原理

这个文件是个固定大小的环形数组,repl_baklog中会记录Redis处理过的命令日志及offset,包括master当前的offset,和slave已经拷贝到的offset,差异不超过环大小增量同步,超过全量同步

# 主从同步优化(优化Redis主从集群)

  • 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。写入网络IO流
  • Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
  • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
  • 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力

# 过期key如何处理?

主节点处理了一个key或者通过淘汰算法淘汰了一个key,这个时间主节点模拟一条del命令发送给从节点,从节点收到该命令后,就进行删除key的操作。

# 同步复制还是异步复制?

Redis 主节点每次收到写命令之后,先写到内部的缓冲区,然后异步发送给从节点。

# 主从数据不一致

主从节点间的命令复制是异步的,无法实现强一致性;

主节点执行完命令后,直接把结果返回给客户端了,并没有等从节点页执行完。

如果从节点还没有执行主节点同步过来的命令,主从节点间的数据就不一致了;

如何解决?

  • 保证主从节点在同一个机房,网络良好;
  • 外部程序来监控主从节点间的复制进度;

# 哨兵

作用:主从节点故障转移;

如何工作?

  • 监控

    基于心跳检测机制;

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

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

    • sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master

    • sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。

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

# 集群

解决问题:

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

主节点之间互为哨兵,自动实现故障转移

# 散列插槽

为什么不用哈希?

通过key计算hash值,根据节点数量求模,增加节点影响缓存命中率(重新分配代价太高);

Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:

  • key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
  • key中不包含“{}”,整个key都是有效部分

key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值

Redis如何判断某个key应该在哪个实例?

  • 将16384个插槽分配到不同的实例
  • 根据key的有效部分计算哈希值,对16384取余
  • 余数作为插槽,寻找插槽所在实例即可

如何将同一类数据固定的保存在同一个Redis实例?

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

    set num 123

    set {a}num 111

# 一致性哈希

  1. 将哈希值映射到环上0-2^32-1,将节点配置到环上(根据ip或机器名求哈希值),所有的数据顺时针找到其对应节点;

    如果节点不均衡?

    新增节点?

    影响的数据为:节点B到节点E之间数据,只会分担节点C的压力;

    解决方案:虚拟节点,分担的压力1/n

  2. 存在什么问题?

    需要找到比它值大的节点,查找数据所需时间增加(相比简单hash);

    集群节点调整时可用性降低(数据迁移);

缓存篇
实战篇

← 缓存篇 实战篇→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式