Redis高可用架构

概述

 Redis作为常用的缓存中间件,因其高性能,丰富的数据结构,使用简单等,常被用在需要一定高性能的To C业务场景中,如「秒杀场景」「用户信息中心」「帖子」「群聊」等等大家常见的业务场景中,以提高服务的响应速度,降低接口RT,同时也可以降低对DB层的压力,以提高整个服务集群的可靠性与稳定性等,提升用户体验。当然,Redis还有很多的应用场景,如分布式锁,限流等等的应用场景,后续会逐一进行讨论分析。
 To C的高流量场景往往反映着该服务所对应的业务域具有较高的重要性,对服务集群的高性能与高可靠性都具有较高的要求,Redis作为常用的缓存中间件嵌入在服务中来抗大流量,其自生就应该具备一定的高可用性。
 从Redis诞生至今,其高可用架构也在不断的演进中,以满足不同业务体量下服务的性能与可用性需求。从最初的主从架构,到基于Sentinel(哨兵模式)的高可用架构,再到目前被广泛使用的集群架构,Redis都在不断发展演进。每一种结构都存在其对应的优缺点,也对应着应用场景,本文将着重介绍Redis不同的高可用架构,对应的优缺点,以及每种架构的实现原理,应用场景等,其高性能的实现原理不在本文的讨论范围内(想必大家也都了解Redis为何性能好的原因)。
 希望本文对想了解Redis高可用架构的同学有一定的帮助,最后也欢迎大家指出其中的问题,一起讨论。

内容说明
  1. 本文将按照Redis演进的时间线,逐一的介绍不同的架构。分别为:「基本的主从架构」「改进的主从架构」「基于Sentinel(哨兵模式)的高可用架构」「集群模式」。
  2. 因整体内容较多,本文将分阶段进行完善。

阅读说明:中间涉及到一些分布式相关知识,有一定分布式基础的可更好理解相关内容。

主从架构

基本的主从架构

whiteboard_exported_image.png

  主从架构模式:部署多台redis节点,其中只有一台节点是主节点(master),其他的节点都是从节点(slave),也叫备份节点(replica)。只有master节点提供数据的事务性操作(增删改),slave节点只提供读操作。所有slave节点的数据都是从master节点同步过来的。

问题与缺点

  上图只是最简单的一种主从结构方式,所有的slave节点都挂在master节点上,这样做的好处是slave节点与master节点的数据延迟较小;缺点是如果slave节点数量很多,master同步一次数据的耗时就很长,影响master节点的性能。

改进的主从架构

主从从架构

  当slave过多时,可以将主从架构调整为主从从的拓扑结构,以减少过多的slave节点数据同步(全量同步/增加同步)带来的cpu/网络等的开销,降低master节点的压力;
whiteboard_exported_image (1).png

问题与缺点

  一主多从变为树桩结构,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟较大,数据一致性变差,所以最多不要超过三层。

主要使用场景

  • 读多写少 - 读写分离 - 有一定的并发量

主从同步机制

全量同步(快照同步)

触发场景
  1. 集群中加入新的节点
  2. 主从节点偏移量差距超过一定的阈值
    1. 潜在的原因:
      1. 网络问题
      2. 从节点离线较长后再次连上集群,导致主从数据偏移量相差过大
      3. 主节点写入数据的速度大于主从同步的数据等场景
    2. 阈值:由redis buffer 缓冲区的大小决定
同步原理
  1. 从节点启动之后会与主节点建立socket长连接,然后向主节点发送psync指令
  2. 主节点收到从节点的psync指令之后,会执行BGsave命令生成新的rbd持久化文件,在生成过程中处理的客户端写操作命令会放在repl缓冲区。
  3. 主节点将生成的rbd文件发送给从节点,从节点清空老数据,加载新的rbd文件
  4. 主节点将生成的repl缓冲区的指令发送给从节点,从节点将执行该命令,将数据写入到内存
  5. 主节点通过socket长连接把修改命令发送给从节点,保证主从一致
全量同步开销

  主节点:生成RDB文件会占用内存、硬盘资源,网络传输RDB的时候会占用一定的网络带宽资源
从节点:清空数据,若数据量大,需要消耗一定的时间,加载RDB也需要一定的时间

命令传播(增量同步)

  在master节点和slave节点同步完成后,主服务器的每次更新都会发送相应的命令到从服务器。从服务器执行对应操作,将数据库状态更新到主服务器一致的状态。

1.支持断点续传 - 通过 master的redis buffer缓冲区 / master节点offset / slave节点的offset实现

无盘复制

  通常,全量复制需要在磁盘上创建RDB文件,然后加载到内存中,Redis支持无盘复制,生成的RDB文件不保存到磁盘而是直接通过网络发送给从节点。无盘复制适用于主节点所在机器磁盘性能较差但网络宽带较充裕的场景。需要注意的是,无盘复制目前依然处于实验阶段。(类似零拷贝)

问题与缺点

  • 主从架构的问题在于所有的写入操作都在master节点上,实际上是一个具有单点问题的架构;若master节点出现异常(节点下线等导致的不可用等),则整个集群将不可用
  • 主从切换需要人工干预(无选举机制),同时需要变更客户端连接地址

基于Sentinel(哨兵模式)的高可用架构

出现背景

Sentinel架构解决redis主从架构人工干预的问题。

Redis官方文档
https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/

简介

  Redis Sentinel 是 Redis 的高可用实现方案。Sentinel不是一个单独的进程,而是有多个哨兵服务组成的分布式系统。Sentinel集群独立于 Redis 集群,哨兵之间彼此建立连接,共同监控、管理所有的 Redis 节点。哨兵间使用流言协议(gossip protocols)进行消息传播,使用投票协议(agreement protocols)决定是否执行自动故障迁移和选择新的主节点。

作用

  1. 监  控:监控所有 Redis 节点的状态。
  2. 故障转移:当哨兵发现主节点下线时,会在所有从节点中选择一个作为新的主节点,并将所有其他节点的 Master 指向新的主节点。同时已下线的原主节点也会被降级为从节点,并修改配置将 原Master 指向新的主节点,等到它重新上线时就会自动以从节点进行工作。
  3. 通  知:当哨兵选举了新的主节点之后,可以通过 API 向客户端进行通知。

基本原理

  Sentinel服务负责持续监控主从节点的健康状况,当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来连接集群时,会首先连接 sentinel,通过 sentinel 来查询主节点的地址,然后再去连接主节点进行数据交互。当主节点发生故障时,客户端会重新向 sentinel 要地址,sentinel 会将最新的主节点地址告诉客户端。如此应用程序将无需重启即可自动完成节点切换。

从库发现

  对于哨兵的配置,我们只需要配置主库的信息,哨兵在连接主库之后,会调用 INFO 命令获取主库的信息,再从中解析出连接主库的从库信息,再以此和其他从库建立连接进行监控。

  哨兵对所有节点都会每隔 10s 发送一次 INFO 命令,从各节点获取 Redis 集群实时的拓扑图信息。如果新节点加入,哨兵就会去监控新的节点。

**INFO**命令信息

# Replication
role:master
connected_slaves:2
slave0:ip=172.25.0.102,port=6379,state=online,offset=258369,lag=1
slave1:ip=172.25.0.103,port=6379,state=online,offset=258508,lag=0
master_failover_state:no-failover
master_replid:a4a6a7f3b2e15d9a43c01d4ba6c842539e582d6a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:258508
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:258508

发布/订阅机制

  哨兵们在连接同一个主库之后,是通过发布/订阅(pub/sub)模式来发现彼此的存在的。

发布/订阅(pub/sub)是一种消息通信模式,主要的目的是解耦消息发布者和消息订阅者之间的耦合。Redis 作为一个 pub/sub server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过 subscribe 和 psubscribe 命令从 Redis 订阅自己感兴趣的消息类型,Redis 将消息类型称为频道(channel)。当发布者通过 publish 命令向 Redis 发送特定类型的消息时,该频道的全部订阅者都会收到此消息。这里消息的传递是多对多的。一个 client 可以订阅多个 channel,也可以向多个 channel 发送消息

  在哨兵模式下,哨兵们会在每个 Redis 服务上创建并订阅一个名为 sentinel:hello 的频道,哨兵们就是通过它来相互发现,实现相互通信的。
  订阅后,每个哨兵每隔 2 秒都会向 hello 频道发布一条携带自身信息的 hello 信息,这样哨兵就能知道其他哨兵的状态、监控的主节点和是否有新的哨兵加入:

//Hello频道消息
127.0.0.1:6371> subscribe __sentinel__:hello
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "__sentinel__:hello"
3) (integer) 1
1) "message"
2) "__sentinel__:hello"
3) "172.25.0.202,26379,5134e342cc62ac76494c140b66b7fda80340e3a8,0,mymaster,172.25.0.101,6379,0"
1) "message"
2) "__sentinel__:hello"
3) "172.25.0.203,26379,5f5ce54a6f22f71c7d273cfb9eb14377b103d4ad,0,mymaster,172.25.0.101,6379,0"
1) "message"
2) "__sentinel__:hello"
3) "172.25.0.201,26379,4fa3486dfbaca9abc62b2976e821d18e697ab2db,0,mymaster,172.25.0.101,6379,0"

whiteboard_exported_image (2).png

监控

  哨兵在对 Redis 节点建立 TCP 连接之后,会周期性地发送 PING 命令给节点(默认是 1s),以此判断节点是否正常。如果在 down-after-millisenconds 时间内没有收到节点的响应,它就认为这个节点掉线了。

主观下线

  当哨兵发现与自己连接的其他节点断开连接,它就会将该节点标记为主观下线+sdown),包括主节点、从节点或者其他哨兵都可以标记为 sdown 状态。

//从节点主观下线
1:X 19 Mar 2024 13:26:29.837 # +sdown slave 172.25.0.103:6379 172.25.0.103 6379 @ mymaster 172.25.0.101 6379# 
//哨兵主观下线
1:X 19 Mar 2024 13:19:19.799 # +sdown sentinel 5134e342cc62ac76494c140b66b7fda80340e3a8 172.25.0.202 26379 @ mymaster 172.25.0.101 6379# 
//主节点主观下线
1:X 19 Mar 2024 13:24:06.612 # +sdown master mymaster 172.25.0.101 6379

  当该节点重新连接之后,哨兵会取消对它的主观下线标记,操作是 -sdown

1:X 19 Mar 2024 13:20:04.811 # -sdown sentinel 5134e342cc62ac76494c140b66b7fda80340e3a8 172.25.0.202 26379 @ mymaster 172.25.0.101 6379

  如果哨兵判断从节点或者其他哨兵节点主观下线,哨兵并不会执行其他操作。如果是主节点主观下线,哨兵就要采取措施,确定主节点是否真的宕机,并执行故障转移。

客观下线

  哨兵确认主节点是否真的宕机这一步成为客观下线确认,如果主节点真的宕机了,哨兵就会将主节点标记为客观下线+odown)状态。

1:X 19 Mar 2024 13:24:06.612 # +sdown master mymaster 172.25.0.101 6379
1:X 19 Mar 2024 13:24:06.685 # +odown master mymaster 172.25.0.101 6379 #quorum 2/2

  要判断主节点是否客观下线,需要与其他哨兵达成共识,如果大多数哨兵认为主节点主观下线了,哨兵才能确认主节点客观下线。达成共识的方式就是发起一轮投票,如果票数超过哨兵节点数的一半,并且大于等于 quorum 设置的数量,就是投票成功。否则哨兵就不能说主节点客观下线了。
quorum 是法定人数的意思,该信息在哨兵配置信息中进行配置:

# sentinel.conf
sentinel monitor <master-name> <ip> <redis-port> <quorum>

客观下线投票过程

  1. 当哨兵发现主节点下线,标记主节点为 sdown 状态。
  2. 哨兵向其他哨兵发送 SENTINEL is-master-down-by-addr 命令,询问其他哨兵该主节点是否已下线。
  3. 其他哨兵在收到投票请求之后,会检查本地主缓存中主节点的状态并进行回复(1 表示下线,0 表示正常)。
  4. 发起的询问的哨兵在接收到回复之后,会累加“下线”的得票数。
  5. 当下线的票数大于一半哨兵数量并且不小于 quorum 时,就会将主节点标记为 odown 状态。并开始准备故障转移。
  6. 发起投票的哨兵有一个投票倒计时,倒计时结束如果票数仍然不够的话,则放弃本次客观线下投票。并尝试继续与主节点建立连接。
【注意】
1.当哨兵把主节点标记为 odown 时,并不会通知其他哨兵,因为这样自己才更有机会进行故障转移。2.如果多个哨兵在同一段时间内发现主节点下线,那么每个发现的哨兵都会发起投票,投票的结果只是让发起投票的哨兵能够确认主节点是否下线,并不会与其他哨兵共享。因此这个下线确认的动作是多个节点同时发起进行的。

故障转移

  哨兵在将主节点标记为 odown 状态之后,就会马上开始尝试故障转移了。

  故障转移主要由 sentinelFailoverStateMachineZ(sentinelRedisInstance) 函数负责。该函数由一个状态机组成,共有五个状态,标志着故障转移共分为五个大步骤:

| SENTINEL_FAILOVER_STATE | desc           | invoke                                                  
|:------------------------|:---------------|:-------------------------------------------------------|
| `WAIT_START`            | Leader 选举    | sentinelFailoverWaitStart(sentinelRedisInstance)        |
| `SELECT_SLAVE`          | Master 选取    | sentinelFailoverSelectSlave(sentinelRedisInstance)      |
| `SEND_SLAVEOF_NOONE`    | Slave 身份去除 | sentinelFailoverSendSlaveOfNoOne(sentinelRedisInstance)  |
| `WAIT_PROMOTION`        | 提升 Master    | sentinelFailoverWaitPromotion(sentinelRedisInstance)    |
| `RECONF_SLAVES`         | 配置从节点     | sentinelFailoverReconfNextSlave(sentinelRedisInstance)   |

详见:https://www.jianshu.com/p/178d0b10809c

整体架构

whiteboard_exported_image (3).png

集群模式(Redis Cluster)

节点负载均衡

一致性哈希

数据分布算法

虚拟节点机制

集群请求重定向

MOVED 错误

ASK 错误

Goosip协议

说明:集群节点通信机制

集群可以设置多大?

动态缩扩容

故障转移

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用WPF的Microsoft.Xaml.Behaviors.Wpf中通用 UI 元素事件

Nuget下载之后记得要先引用下面的 xmlns:i"http://schemas.microsoft.com/xaml/behaviors" <!-- 鼠标事件 --> <i:EventTrigger EventName"MouseEnter"/> <!-- 鼠标进入 --> <i:EventTrigger EventName"MouseLeave"/&g…

敏捷开发中如何避免过度加班

在敏捷开发过程中避免过度加班&#xff0c;需要明确敏捷原则、合理规划迭代任务、加强团队沟通、优化流程效率、设定合理的工作负荷、注重团队士气和成员健康。明确敏捷原则&#xff0c;即保证可持续发展的步调&#xff0c;避免频繁地变更需求、过度承诺任务量。合理规划迭代任…

JSON解析崩溃原因及解决方案

问题记录&#xff1a; /************************************************| * 描述: 将ID124执行NFC操作-JSON解析为结构体* 函数名: cJSON_ID124_to_struct* 参数[ I]: *json_string 待解析的指针* 参数[II]: *wireless_rxd 结构体指针* 返回: 成功返回0 失…

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…

Edge(Bing)自动领积分脚本部署——基于python和Selenium(附源码)

微软的 Microsoft Rewards 计划可以通过 Bing 搜索赚取积分&#xff0c;积分可以兑换礼品卡、游戏等。每天的搜索任务不多&#xff0c;我们可以用脚本自动完成&#xff0c;提高效率&#xff0c;解放双手。 本文将手把手教你如何部署一个自动刷积分脚本&#xff0c;并解释其背…

前端基础之《Vue(19)—状态管理》

一、什么是状态管理 1、Vue版本问题 Vue2 Vuex3 Vue3 Vuex4 / Pinia2 在使用任何技术的时候&#xff0c;都先要去搜索一下版本&#xff0c;你的版本和脚手架环境是否兼容。 2、安装Vuex yarn add vuex3.6.2 3、状态管理 状态&#xff0c;在应用程序中表示数据&#xff0c…

【图像处理基石】如何进行图像畸变校正?

图像畸变校正常用于计算机视觉、摄影测量学和机器人导航等领域&#xff0c;能够修正因镜头光学特性或传感器排列问题导致的图像失真。下面我将介绍几种常用的图像畸变校正算法&#xff0c;并提供Python实现和测试用例。 常用算法及Python实现 1. 径向畸变校正 径向畸变是最常…

蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析

目录 一、引言 DS18B20的原理图 单总线简介&#xff1a; ​编辑暂存器简介&#xff1a; DS18B20的温度转换与读取流程 二、代码配置 maic文件 疑问 关于不同格式化输出符号的使用 为什么要rd_temperature()/16.0&#xff1f; onewire.h文件 这个配置为什么要先读lo…

MySQL的并发事务问题及事务隔离级别

一、并发事务问题 1). 赃读&#xff1a;一个事务读到另外一个事务还没有提交的数据。 比如 B 读取到了 A 未提交的数据。 2). 不可重复读&#xff1a;一个事务先后读取同一条记录&#xff0c;但两次读取的数据不同&#xff0c;称之为不可重复读。 事务 A 两次读取同一条记录&…

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…

练习:对象数组 4

定义数组存储 4 个女朋友的对象。女朋友的属性&#xff1a;姓名、年龄、性别、爱好&#xff1b;要求1&#xff1a;计算出四个女朋友的平均年龄&#xff1b;要求2&#xff1a;统计年龄比平均值低的女朋友有几个&#xff1f;并把他们的所有信息打印出来。 代码&#xff1a; //对…

React Hooks 基础指南

React Hooks 是 React 16.8 引入的重要特性&#xff0c;它允许开发者在函数组件中使用状态和其他 React 特性。本文将详细介绍 6 个最常用的 React Hooks。 1. useState useState 是最常用的 Hook&#xff0c;用于在函数组件中添加 state。 import React, { useState } from…

【Python 算法零基础 4.排序 ⑥ 快速排序】

既有锦绣前程可奔赴&#xff0c;亦有往日岁月可回首 —— 25.5.25 选择排序回顾 ① 遍历数组&#xff1a;从索引 0 到 n-1&#xff08;n 为数组长度&#xff09;。 ② 每轮确定最小值&#xff1a;假设当前索引 i 为最小值索引 min_index。从 i1 到 n-1 遍历&#xff0c;若找到…

处理git没做修改,但是文件显示变更的情况

使用 TortoiseGit&#xff08;小乌龟 Git&#xff09; 时遇到 “文件内容没改&#xff0c;但显示为变更&#xff0c;提示有 n 行删除、n 行添加”&#xff0c;你可以按照以下步骤操作来排查并解决问题&#xff1a; ✅ 一、定位问题根源&#xff08;是否为行尾差异&#xff09;…

智慧货运飞船多维度可视化管控系统

图扑搭建智慧货运飞船可视化系统&#xff0c;借数字孪生技术&#xff0c;高精度复刻货运飞船外观、结构与运行场景。整合多维度数据&#xff0c;实时呈现飞行状态、设备参数等信息&#xff0c;助力直观洞察货运飞船运行逻辑&#xff0c;为航天运维、任务推演及决策提供数字化支…

maven微服务${revision}依赖打包无法识别

1、场景描述 我现在又一个微服务项目&#xff0c;父pom的版本&#xff0c;使用<properties>定义好&#xff0c;如下所示&#xff1a; <name>ypsx-finance-center</name> <artifactId>ypsx-finance</artifactId> <packaging>pom</pack…

详解代理型RAG与MCP服务器集成

检索增强型生成(RAG)将语言模型与外部知识检索相结合,让模型的回答基于最新的事实,而不仅仅是其训练数据呢。 RAG(高级别) 在 RAG 流程中,用户查询用于搜索知识库(通常通过向量数据库中的嵌入来实现),并将检索到的最相关文档“增强”到模型的提示中,以帮助生成事实…

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…

如何防止服务器被用于僵尸网络(Botnet)攻击 ?

防止服务器被用于僵尸网络&#xff08;Botnet&#xff09;攻击是关键的网络安全措施之一。僵尸网络是黑客利用大量被感染的计算机、服务器或物联网设备来发起攻击的网络。以下是关于如何防止服务器被用于僵尸网络攻击的技术文章&#xff1a; 防止服务器被用于僵尸网络&#xff…

贪心算法应用:硬币找零问题详解

贪心算法与硬币找零问题详解 贪心算法&#xff08;Greedy Algorithm&#xff09;在解决优化问题时表现出简洁高效的特点&#xff0c;尤其适用于特定结构的组合优化问题。本文将用2万字篇幅&#xff0c;深入探讨贪心算法在硬币找零问题中的应用&#xff0c;覆盖算法原理、正确性…