Redis核心技术与实战【学习笔记】 - 23.Redis 主从切换故障,有哪些坑

前言

Redis 的主从同步机制不仅可以让从库服务更多的读请求,分担主库的压力,而且还能在主库发生故障时,进行主从库切换,提供高可靠服务。

不过,在实际使用主从机制时会踩到一些“坑”:主从数据不一致、读到过期数据以及配置项设置得不合理而导致服务挂掉。


主从数据不一致

主从数据不一致,就是指客户端从从库中读取到的值和主库中的最新值并不一致。

假设,主从库之前保存的用户年龄是 19,但是主库收到了修改命令,已经把这个数据更新为 20 了,但是,从库中的值仍然是 19。那么,如果客户端从从库中读取用户年龄值,就会读到旧值。

因为主从库的命令复制是异步进行的

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

造成从库之后执行同步命令的原因有两个:

  • 一方面,主从库间的网络可能会有传输延迟,所以从库不能及时地收到主库发送的命令,从库上执行命令同步的时间就会被延后。
  • 另一方面,即使从库及时收到了主库的命令,但是,也可能因为正在处理的其他复杂度高的命令而阻塞。此时,从库需要处理完当前的命令,才能执行主库发送的命令,这就造成主从库数据不一致。而在主库命令被滞后执行的这一段时间内,主库本身可能又执行了新的写操作。这样一来,主从库间的数据不一致程度就会进一步加剧。

有两种解决办法:

  1. 在硬件配置方面,要尽量保证主从库间的网络连接状况良好。要避免把主从库部署在不同的机房,或者是避免把网络通信密集的应用和 Redis 主从库部署在一起。
  2. 开发一个外部程序来监控主从库间的复制进度。

因为 Redis 的 INFO replication 命令可以查看主库接收写命令的进度信息(master_repl_offset)和从库复制写命令的进度信息(slave_repl_offset),所以,我们可以开发一个监控程序,先用 INFO replication 命令查到主、从库的进度,然后,用 master_repl_offset 减去 slave_repl_offset,这样就能得到主库和从库间的复制进度差值了。

如果某个从库的进度差值大于我们预设的阈值,可以让客户端不再和这个从库就进行数据读取,这样就可以减少得到不一致数据的情况。不过,为了避免出现客户端和所有从库都不能连接的情况,我们要把复制进度差值的阈值设置得大一些。
在这里插入图片描述
当然,监控程序可以一直监控这从库的复制进度,当从库的复制进度又赶上了主库时,我们允许客户端再次跟这些从库连接。

读取过期数据

我们在使用 Redis 主从集群时,有时会读到过期数据。例如,数据 X 的过期时间是 202401010900,但是客户端在 202401010910 时,仍然可以从从库中读到数据 X。一个数据过期后,应该是被删除的,客户端不能再读取到该数据。

其实,这是有 Redis 的过期策略引起的。Redis 同时使用了两种策略来删除过期数据,分别是惰性删除策略和定期删除策略

  1. 惰性删除策略。当一个数据的过期时间到了以后,并不会立即删除数据,而是等到再由请求来读写这个数据时,对数据进行检查,如果发现数据已经过期了,再删除这个数据。

    这个策略的好处是尽量减少删除操作对 CPU 资源的使用,对于用不到的数据,就不在浪费时间进行检查和删除了。但是,这个策略会导致大量已经过期的数据留存在内存中,占用较多的内存资源。所以,Redis 在使用这个策略的同时,还使用了定期删除策略。

  2. 定期删除策略是指,Redis 每隔一段时间(默认 100ms),就会随机选出一定数量的数据,检查他们是否过期,并把其中过期的数据删除,这样就可以及时释放一些内存。

清楚了删除策略,看看他们为什么会导致读取到过期数据。

  • 首先,虽然定期删除可以释放一些内存,但是 Redis 为了避免过多删除操作对性能产生影响,每次随机检查数据的数量并不多。如果过期数据很多,并且一直没有再被访问,这些数据就会留存在 Redis 实例中。业务应用之所以会读到过期数据,这些留存数据就是一个重要因素。

  • 其次,惰性删除策略实现后,数据只有被再次访问时,才会被实际删除。如果客户端从主库上读取留存的过期数据,主库会触发删除,此时,客户端并不会读到过期数据。但是,从库本身不会执行删除操作,如果客户端在从库中访问的过期数据,从库并不会触发数据删除。

    那么,从库会给客户端返回过期数据吗?

    如果是 Redis 3.2 之前的版本,那么,从库在服务读取请求时,并不会判断是否过期,而是会返回过期数据。在,Redis 3.2 版本后,Reids 做了改进,如果读取的数据已经过期,从库虽然不删除数据,但是会返回空值,所以就避免了客户端读到过期数据。所以,在应用主从集群时,尽量使用 Redis 3.2 以上版本

另外,Redis 的过期命令也可能导致读取到过期数据。有些命令给数据设置的过期时间在从库上可能会被延后,导致应该该过期的数据又在从库上被读取到了。

设置数据过期时间的命令一个有 4 个,我们可以把他们分成两类:

  • EXPIREPEXPIRE :它们给数据设置的是从命令执行时开始计算的存活时间
  • EXPIREATPEXPIREAT它们会直接把数据的过期时间设置为具体的一个时间点
过期时间
设置命令
参数含义
EXPIRE[key] [ttl]将 key 的存活时间设置为 ttl 秒
PEXPIRE[key] [ttl]将 key 的存活时间设置为 ttl 毫秒
EXPIREAT[key] [timestamp]将key的过期时间设置为timestamp指定的秒数时间点
PEXPIREAT[key] [timestamp]将key的过期时间设置为timestamp指定的毫秒数时间点

再举两个例子。

第一个例子是使用 EXPIRE 命令,当执行下面的命令时,我们就把 testkey 的过期时间设置为 60s 后。

EXPIRE testkey 60

第二例子是使用 EXPIREAT 命令,例如,我们执行下面的命令,就可以让 testkey 在 2024年1月1日上午9点过期,命令中的 1673079000 就是以秒数时间戳表示的 2024年1月1日上午9点。

EXPIREAT testkey 1673079000

下面来看看这些命令是如何导致读到过期数据的。

当主从全量同步时,如果主库收到了 EXPIRE 命令,那么,主库会直接执行这条命令。这条命令会在全量同步完成后,发给从库执行。而从库在执行时,就会在当前时间的基础上加上数据的存活时间,这样一来,从库上的数据的过期时间就会比主库延后了。

假设当前时间是 2024年1月1日上午9点,主从库正在同步,主库收到了一条命令 EXPIRE testkey 60,这就表示,testkey 的过期时间就是 1日上午9 点 1 分,主库直接执行了这条命令。

  • 但是,主从库全量同步花了 2 分支才完成。等从库开始执行这条命令时,时间已经是 9 点 2 分了。而 EXPIRE 命令就是把过期时间设置为当前时间的 60s 后,也就是 9 点 3 分。
  • 如果客户端在 9 点 2 分 30 秒时在从库上读取 testkey,仍可以读取到 testkey 值。但是 testkey 实际已经过期了。

为了避免这种情况,在业务应用中使用 PEXPIREAT、PPEXPIREAT 命令,把数据过期时间设置为具体的时间点,避免读到过期数据。

简单总结下刚刚学到过的这两个坑:

  • 主从数据不一致。Redis 采用的是异步复制,所以无法实现强一致性保证,数据不一致是难免的。应对方法:保证良好网络环境,以及使用程序监控主从复制进度,一旦从库复制进度超过阈值,不让客户端连接从库。
  • 对于读到过期数据,有两个提前规避的方法:一个方法是,使用 Redis 3.2 及以上版本;另外,你可以可以使用 PEXPIREAT、PPEXPIREAT 命令设置过期时间,避免从库上的数据过期时间滞后。不过,这里有个地方注意下,因为 PEXPIREAT、PPEXPIREAT 设置的是时间点,所以 主从节点上的时钟要保持一致,具体做法是,让主从节点和相同的 NTP 服务器(时间服务器)进行时钟同步

不合理配置项导致的服务挂掉

这里涉及到两个配置项: protected-mode 和 cluster-node-timeout。

1、protected-mode

这个配置项的作用是限定哨兵机制能够被其他服务器访问。当这个配置项是 yes 时,哨兵实例只能在部署的服务器本地进行访问。当设置为 no 时,其他服务器也可以访问这个哨兵实例。

这是因为这样,如果 protected-mode 设为 yes ,而其余哨兵实例部署在其他服务器,那么这些哨兵视力健就无法通信,当主库故障时,哨兵无法判断主库下线,也无法进行主从切换,最终 Redis 不可用。

所以,我们在应用主从集群时,要注意将 protected-mode 配置项设置为 no,并且将 bind 配置项设置为 其他哨兵实例的 IP 地址。这样一来,只有在 bind 中配置了 IP 地址的哨兵,才可以向才可以访问,既保证了实例间能够通信进行主从切换,也保证了哨兵的安全。

如果设置了下面的配置项,那么,部署在 192.168.10.3/4/5 这三台服务器上的哨兵实例就可以相互通信,执行主从切换。

protected-mode no
bind 192.168.10.3 192.168.10.4 192.168.10.5

2、cluster-node-timeout

我们在 Redis Cluster 集群中为每个实例配置了 “一主一从” 模式时,如果实例发送故障,从实例会切为主实例,受网络延迟和切换操作执行的影响,切换时间可能更长,就会导致实例的心跳超时(超出 cluster-node-timeout)。实例超时后,就会被 Redis Cluster 判断为异常。而 Redis Cluster 能正常运行的条件是,有半数以上的实例都能正常运行。

如果,执行主从切换的实例超过半数,而且主从库切换时间又过长的话,就可能有半数以上的实例心跳超时,从而可能导致整个集群挂掉。所以,建议你将 cluster-node-timeout 调大些。(例如 10 到 20 秒)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

保育员怎么搜题答案?用这5款神器就够了!!! #媒体#笔记#知识分享

专供大学生使用的搜题神器,支持拍照搜题、文字搜题、语音搜题等多种搜题方式,能快速找到课本习题的题目答案,而且还会附带详细的答案解析,加深我们对题目的理解。 1.大鱼搜题 这是一个公众号 适合大学生,基本上网课…

动漫风博客介绍页面源码

动漫风博客介绍页面源码,HTML源码,图片背景有淡入切换特效 蓝奏云:https://wfr.lanzout.com/iIDZu1nrmjve

清理神器CleanMyMac X 空间透镜——可视化您的磁盘空间 空间透镜有什么用

不久前,CleanMyMac X 发布了一个新功能: 空间透镜 相信有非常多的小伙伴和小编一样, 对这个功能一脸问号 这啥玩意儿??? 今天就让我们深入了解一下, CleanMyMac X 的空间透镜功能。 - 更好…

【汇编】简单的linux汇编语言程序

一、Linux系统汇编语言 Linux系统上的汇编语言可以使用不同的语法风格,主要包括Intel语法和AT&T语法。这两种语法有各自的特点和风格区别,尽管它们表示的底层机器指令相同。下面分别对两种语法进行简要说明: Intel语法 Intel语法是由I…

《MySQL 简易速速上手小册》第10章:未来趋势和进阶资源(2024 最新版)

文章目录 10.1 MySQL 在云计算和容器化中的应用10.1.1 基础知识10.1.2 重点案例:使用 Python 部署 MySQL 到 Kubernetes10.1.3 拓展案例 1:在 AWS RDS 上部署 MySQL 实例10.1.4 拓展案例 2:使用 Docker 部署 MySQL 10.2 MySQL 和 NoSQL 的整合…

Web课程学习笔记--JavaScript操作DOM常用的API

JavaScript操作DOM常用的API 1 什么是DOM 文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。 文档对象模型 (DOM) 是对HTML文…

基于BiLSTM-CRF模型的分词、词性标注、信息抽取任务的详解,侧重模型推导细化以及LAC分词实践

基于BiLSTM-CRF模型的分词、词性标注、信息抽取任务的详解,侧重模型推导细化以及LAC分词实践 1.GRU简介 GRU(Gate Recurrent Unit)门控循环单元,是[循环神经网络](RNN)的变种种,与 LSTM 类似通过门控单元解决 RNN 中不能长期记忆和反向传播中的梯度等问题。与 LSTM 相…

一文带你读懂JSON模块

json模块 JSON (JavaScript Object Notation):是一个轻量级的数据交换格式模块,受javascript对象文本语法启发,但不属于JavaScript的子集。 常用方法: dump(obj,fp):将对象以字符串的形式写入文件中。 load(fp)&am…

解密输入输出迷局:蓝桥杯与ACM中C++/C语言常见问题揭秘

关于C中的常见输入输出汇总 带空格的字符串: ​ 对于这种输入方式我们选择使用gets() 函数来进行输入,gets用于从标准输入(通常是键盘)读取一行文本并将其存储为字符串,直到遇到换行符(‘\n’&#xff09…

Mac电脑到手后的配置

一、Homebrew 1、Homebrew安装 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 桌面的Old_Homebrew文件夹,没有你需要的可以删除。 2、Homebrew卸载 /bin/zsh -c "$(curl -fsSL https://gitee.com/c…

生物——文献笔记

生物——文献笔记 文章目录 前言藻类群体遗传学研究和进展(综述)海洋动物群体遗传学的研究进展1. 影响群体基因频率的因素2. 根据自然群体的繁殖体系,海洋动物群体遗传类型可分为以下几类3. 海洋动物群体遗传研究中常用的遗传标记4. 研究展望…

QXlsx Qt操作excel

QXlsx 是一个用于处理Excel文件的开源C库。它允许你在你的C应用程序中读取和写入Microsoft Excel文件(.xlsx格式)。该库支持多种操作,包括创建新的工作簿、读取和写入单元格数据、格式化单元格、以及其他与Excel文件相关的功能。 支持跨平台…

python爬虫入门(一)

使用requests 库获取网站html信息 import requests response requests.get("https://jingyan.baidu.com/article/17bd8e52c76b2bc5ab2bb8a2.html#:~:text1.%E6%89%93%E5%BC%80%E6%B5%8F%E8%A7%88%E5%99%A8F12%202.%E6%89%BE%E5%88%B0headers%E9%87%8C%E9%9D%A2%E7%9A%84…

STM32F1 - 标准外设库_规范

STM32F10x_StdPeriph_Lib_V3.6.0 1> 头文件包含关系2> .c文件内部结构3> 宏定义位置4> 位掩码bit mask5> .c文件中定义私有变量 1> 头文件包含关系 1个头文件stm32f10x.h 就把整个MCU以及标准外设库,就管理了; 2> .c文件内部结构 …

小白都能看懂的力扣算法详解——链表(二)

LC 24.两两交换链表中的节点 题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 24. 两两交换链表中的节点 -…

ARP欺骗攻击利用之内网截取图片

Arp欺骗:目标ip的流量经过我的网卡,从网关出去。 Arp断网:目标ip的流量经过我的网卡 1. echo 1 >/proc/sys/net/ipv4/ip_forward 设置ip流量转发,不会出现断网现象 有时不能这样直接修改,还有另外一种方法 修…

时刻陪伴,爱意无限

情人节即将到来,你是否在寻找一份特别的礼物,既能表达你的心意,又能带来实用的陪伴?那么,华为WATCH GT 4或许是你的不二之选。 华为 WATCH GT 4有两种不同的外观,颜值都超能打。一款是简洁大气的圆形表盘&…

2024年10 个好用的AI简历工具盘点推荐

在职场竞争激烈的今天,一份出色的简历就像是你的秘密武器,能帮你在众多候选人中脱颖而出,赢得面试宝座。随着 ChatGPT 引领的 AI 浪潮席卷而来,各式各样的 AI 简历工具如雨后春笋般涌现。面对这样的背景,神器集今天为大…

C++,stl,栈stack和队列queue详解

1.栈stack 1.stack基本概念 2.stack常用接口 代码示例&#xff1a; #include<bits/stdc.h> using namespace std;int main() {stack<int> stk;stk.push(7);stk.push(9);stk.push(5);cout << "栈的size为&#xff1a;" << stk.size() <…

如何写一个其他人可以使用的GitHub Action

前言 在GitHub中&#xff0c;你肯定会使用GitHub Actions自动部署一个项目到GitHub Page上&#xff0c;在这个过程中总要使用workflows工作流&#xff0c;并在其中使用action&#xff0c;在这个使用的过程中&#xff0c;总会好奇怎么去写一个action呢&#xff0c;所以&#xff…
最新文章