Qouson's blog Qouson's blog
首页
  • Java 基础

    • 基础
    • String
  • Java 中级

    • 网络编程
  • Java 高级

    • JVM
    • 多线程
  • Spring
  • SpringMVC
  • SpringBoot
  • MySQL
  • Redis
  • MQ
  • ZooKeeper
  • git
  • linux
  • 设计模式
  • 数据结构与算法
  • 计算机基础
  • Java相关框架
  • 分布式
  • DDD领域驱动设计
  • 系统设计
  • 杂乱无章
Java知识图谱
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

qouson

Java界的小学生
首页
  • Java 基础

    • 基础
    • String
  • Java 中级

    • 网络编程
  • Java 高级

    • JVM
    • 多线程
  • Spring
  • SpringMVC
  • SpringBoot
  • MySQL
  • Redis
  • MQ
  • ZooKeeper
  • git
  • linux
  • 设计模式
  • 数据结构与算法
  • 计算机基础
  • Java相关框架
  • 分布式
  • DDD领域驱动设计
  • 系统设计
  • 杂乱无章
Java知识图谱
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • mysql

  • redis

    • Redis
    • 版本介绍
    • redis分布式锁
    • 缓存淘汰策略
    • Redis_xiaolingcode
      • 高可用篇
        • Redis如何实现服务高可用
        • 主从复制
        • 哨兵模式
        • 切片集群模式
        • 集群脑裂导致数据丢失怎么办
        • 解决方案
  • mq

  • zookeeper

  • 中间件
  • redis
qouson
2024-11-14
目录

Redis_xiaolingcode

# Redis

# 高可用篇

# Redis如何实现服务高可用

要想设计一个高可用的Redis服务,一定要从Redis的多服务节点来考虑,比如Redis的主从复制,哨兵模式,切片集群。

# 主从复制

主从复制是Redis高可用服务的最基础的保证,实现方案就是将从前的一台Redis服务器,同步数据到多台从Redis服务器上,即一主多从的模式,且从服务器之间采用的是读写分离的方式。

主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来的写操作命令,然后执行这条命令。

也就是说,所有的数据修改只在主服务器上进行,然后将最新的数据同步给服务器,这样就使得主从服务器的数据是一致的。

注意,主从服务器之间的命令复制时异步进行的。

具体来说,在主服务器命令传播阶段,主服务器接受到新的写命令后,会发送给从服务器。但是,主服务器并不会等从服务器实际执行完命令后,再把结果返回给客户端,而是主服务器自己在本地执行完命令后,就会向客户端返回结果了。如果从服务器还没有执行主服务器同步过来的命令,主从服务器间的数据就不一致了。

所以,无法实现强一致性保证(主从数据时时刻刻保持一致),数据不一致是难以避免的。

# 哨兵模式

在使用Redis主从服务的时候,会有一个问题,就是当Redis的主从服务出现故障宕机时候,需要手动进行恢复。

为了解决这个问题,Redis增加了哨兵模式,因为哨兵模式做到了可以监控主从服务器,并且提供主从节点故障转移的功能。

# 切片集群模式

当Redis缓存数据量大到一台服务器无法缓存时,就需要使用Redis切片集群方案,它将数据分布在不同服务器上,一次来降低系统对单主节点的依赖,从而提高Redis服务的读写性能。

Redis Cluster方案采用哈希槽(Hash Slot),来处理数据和节点之间的映射关系。在Redis Cluster方案中,一个切片集群共有16384个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的key,被映射到一个哈希槽中,具体执行过程分为两大步:

  • 根据键值对的key,按照CRC16算法计算一个16bit的值。
  • 再用16bit值对16384取模,得到0~16383范围的模数,每个模数代表一个相应编号的哈希槽。

接下来问题就是,这些哈希槽怎么被映射到具体的Redis节点上

  • 平均分配:在使用cluster create 命令创建Redis集群时,Redis会自动把所有哈希槽平均分布到集群节点上。比如集群中有9个节点,则每个节点上槽的个数为16384/9个
  • 手动分配:可以使用cluster meet命令手动建立节点间的连接,组成集群,再用cluster addslots命令,指定每个节点上的哈希槽个数。

上图中的切片集群一共有2个节点,假设有4个哈希槽(slot0~slog3)时,我们就可以通过命令手动分配哈希槽,比如节点1保存哈希槽0和1,节点2保存哈希槽2和3

redis-cli -h 192.168.1.10 –p 6379 cluster addslots 0,1
redis-cli -h 192.168.1.11 –p 6379 cluster addslots 2,3
1
2

然后在集群运行的过程中,key1和key2计算完CRC16值后,对哈希槽总个数4进行取模,再根据各自的模数结果,就可以被映射到哈希槽1(对应节点1)和哈希槽2(对应节点2)

# 集群脑裂导致数据丢失怎么办

什么是脑裂? 集群的脑裂现象,这就好比一个人有两个大脑,那么到底受谁控制呢? 那么在Redis中,集群脑裂产生数据丢失的现象是怎样的呢?

在Redis主从架构中,部署方式一般是一主多从,主节点提供写操作,从节点提供读操作,如果主节点的网络出问题,它与所有的从节点都失联了,但是此时的主节点和客户端的网络是正常的,这个客户端并不知道Redis内部已经出了问题,还在照样想找个失联的住系欸但写数据,此时这些数据被旧主节点缓存到了缓冲区里,因为主从节点之间的网络问题,这些数据都是无法同步给从节点的。

这时,哨兵发现主节点失联了,它就认为主节点挂了(但实际上主节点正常运行,只是网络出问题了),于是哨兵就会在从节点中选举出一个leader作为主节点,这时集群就有两个主节点了,脑裂出现了。

然后,网络突然好了,哨兵因为之前已经选举出一个新节点了,他就会把旧主节点降级为从节点,然后从节点会向新主节点请求数据同步,因为第一次同步时全量同步的方式,此时的从节点会清空自己本地的数据,然后再做全量同步。所以,之前客户端在A写入的数据就会丢失,也就是集群产生脑裂数据丢失的问题。

总结一句话就是:由于网络问题,集群节点之间失去联系。主从数据不同步;重新平衡选举,产生两个主服务。等网络恢复,旧主节点降为从节点,再与新主节点进行同步复制的时候,由于会从节点清空自己的缓冲区,所以导致之前客户端写入的数据丢失了。

# 解决方案

当主节点发现从节点下线或者通信超时的总数量小于阈值时候,那么禁止主节点进行写数据,直接把错误返回给客户端。

再Redis的配置文件中有两个参数我们可以设置:

  • min-slaves-to-write x,主节点必须要有至少x个从节点连接,如果小于这个数量,主节点会禁止写数据。
  • min-slaves-max-lag x,主从数据复制和同步的延迟不能超过x秒,如果超过,主节点会禁止写数据。 我们可以把min-slaves-to-write和min-slaves-max-lag这两个配置项搭配起来使用,分别给他们设置一定的阈值,假设为N和T。

这个两个配置项组合后的要求是,主库连接的从库中至少有N个从库,和主库进行数据复制时,ACK消息延迟不饿能超过T秒,否则,主库不会再接受客户端的写请求了。

即使原主库时假故障,它再故障期间也无法相应哨兵心跳,也不能和从库进行同步,自然也就无法和从库进行ACK确认了。这样一来,min-slaves-to-write和min-slaves-max-lag的组合要求就无法得到满足,原主库就会被限制接受客户端写请求,客户端也就不能在原主库中写入新数据了。

等到新主库上线时候,就只有新主库能接受和处理客户端请求,此时,新写的数据会被直接写到新主库中。而原主库会被哨兵降为从库,即使它的数据被清空了也不会有数据丢失。

编辑 (opens new window)
上次更新: 2024/11/14, 16:34:50
缓存淘汰策略
消息中间件的应用场景

← 缓存淘汰策略 消息中间件的应用场景→

最近更新
01
杂乱无章
12-25
02
基础-大彬
11-14
03
集合-大彬
11-14
更多文章>
Theme by Vdoing | Copyright © 2023-2025 qouson
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式