Redis主节点的Key已过期,但从节点依然读到过期数据....

本文探讨了Redis主从架构在处理读写操作时如何优化吞吐量,以及如何处理数据过期和一致性问题。通过一主多从的方式分散读压力,但过期数据的删除策略可能导致从库返回过期数据。惰性删除和定期删除是两种常见的过期策略,而EXPIRE和PEXPIRE命令可能导致时间点计算误差。主从数据不一致主要是由于网络延迟和命令执行顺序,解决办法包括优化网络和监控主从同步进度。升级Redis版本和使用EXPIREAT/PEXPIREAT命令可以减少过期数据问题,确保主从节点时钟同步能有效防止数据不一致。

我们知道,大部分的业务场景都是读多写少,为了利用好这个特性,提升Redis集群系统的吞吐能力,通常会采用主从架构、读写分离
在这里插入图片描述
如上图所示:其中

Master节点:负责业务的写操作

Slave节点:实时同步Master节点的数据,提供读能力

为了提高吞吐量,采用一主多从的架构,将业务的读压力分摊到多台服务器上

一、拉取过期数据

Redis性能高主要得益于纯内存操作,但内存存储介质的成本过高,所以数据的存储有一定的约束。
通常会设置过期时间,对于一些使用不是很频繁的数据,会定期删除,提高资源的利用率。

删除过期数据,Redis提供了两种策略:

1、惰性删除。

也称被动删除,当数据过期后,并不会马上删除。而是等到有请求访问时,对数据检查,如果数据过期,则删除数据。

优点:不需要单独启动额外的扫描线程,减少了CPU资源的损耗。

缺点:大量的过期数据滞留内存中,需要主动触发、检查、删除,否则会一直占用内存资源。

2、定期删除。每隔一段时间,默认100ms,Redis会随机挑选一定数量的Key,检查是否过期,并将过期的数据删除。

你可能会为问了,既然Redis有过期数据删除策略,那为什么还会拉取到已经过期的数据呢?
这要从主从同步讲起了,我们先来看张流程图
在这里插入图片描述
当客户端往主库写入数据后,并设置了过期时间,数据会以异步方式同步给从库。

1、如果此时读主库,数据已经过期,主库的惰性删除会发挥作用,主动触发删除操作,客户端不会拿到已过期数据

2、但是如果读从库,则有可能拿到过期数据。原因有两个

原因一:

跟 Redis 的版本有关系,Redis 3.2 之前版本,读从库并不会判断数据是否过期,所以有可能返回过期数据。

解决方案:

升级Redis的版本,至少要3.2 以上版本,读从库,如果数据已经过期,则会过滤并返回空值。

特别注意:

此时同步过来的数据,虽然已经过期,但本着谁生产谁维护的原则,从库并不会主动删除同步的数据,需要依赖于主节点同步过来的key删除命令。

原因二:

跟过期时间的设置方式有关系,我们一般采用 EXPIRE 和 PEXPIRE,表示从执行命令那个时刻开始,往后延长 ttl 时间。严重依赖于 开始时间 从什么时候算起。

  • EXPIRE:单位为秒

  • PEXPIRE:单位为毫秒
    在这里插入图片描述
    如上图所示,简单描述下过程:

主库在 t1 时刻写入一个带过期时间的数据,数据的有效期一直到 t3

由于网络原因、或者缓存服务器的执行效率,从库的命令并没有立即执行。一直等到了 t2 才开始执行, 数据的有效期则会延后到 t5

如果,此时客户端访问从库,发现数据依然处于有效期内,可以正常使用

解决方案:

可以采用Redis的另外两个命令,EXPIREAT 和 PEXPIREAT,相对简单,表示过期时间为一个具体的时间点。避免了对开始时间从什么时候算起的依赖。

  • EXPIREAT:单位为秒
  • PEXPIREAT:单位为毫秒

特别注意:

EXPIREAT 和 PEXPIREAT 设置的是时间点,所以要求主从节点的时钟保持一致,需要与NTP 时间服务器保持时钟同步。

主从同步,除了读从库可能拉取到过期数据,还可能遇到数据一致性问题。

二、主从数据不一致

解释下,什么是主从数据不一致?指客户端从库中读取到的值与主库中读取的值不一致!

在这里插入图片描述
如图所示:

  • 客户端写入主库,值为100
  • 然后,主库将值100 同步给 从库
  • 接着,客户端又访问主库,将值更新为 200
  • 由于主从同步是异步进行的,有一定延迟,假如最新数据还没有同步到从库,那么从库读取的就不是最新值。
    从库同步落后的原因主要有两个:

1、主从服务器间的网络传输可能有延迟

2、从库已经收到主库的命令,由于是单线程执行,前面正在处理一些耗时的命令(如:pipeline批处理),无法及时同步执行。

解决方案:

1、主从服务器尽量部署在同一个机房,并保持服务器间的网络良好通畅

2、监控主从库间的同步进度,通过info replication命令 ,查看主库接收写命令的进度信息(master_repl_offset),从库的复制写命令的进度信息(slave_repl_offset)
在这里插入图片描述

master_repl_offset - slave_repl_offset 得到从库与主库间的复制进度差

我们可以开发一个监控程序,定时拉取主从服务器的进度信息,计算进度差值。如果超过我们设置的阈值,则通知客户端断开从库的连接,全部访问主库,一定程度上减少数据不一致情况。

待同步进度跟上后,我们再恢复客户端与从节点的读操作。

<think>我们正在讨论Redis的主从架构。用户的问题是:Redis节点是否可以通过get命令直接获取到主节点数据? 根据Redis的主从复制机制,从节点主节点的副本,会复制主节点数据。但是,从节点默认是只读的,客户端可以连接到从节点并执行读操作(包括GET命令)来获取数据。 因此,答案是肯定的:客户端可以连接到从节点,并通过GET命令获取主节点数据(因为从节点已经复制了主节点数据)。 但是,需要注意以下几点: 1. 数据同步延迟:由于网络延迟或复制延迟,从节点数据可能不是最新的(即主节点刚写入的数据可能还未同步到从节点)。 2. 过期数据问题:在Redis中,主节点负责删除过期键,并通过AOF传播到从节点。但在某些情况下(如版本问题或配置问题),从节点可能会读到过期数据。引用[4]提到了一个案例:主节点Key已过期,但从节点依然读到过期数据。 3.节点的只读性:默认配置下,从节点不允许写操作(可以通过配置修改,但不建议)。 因此,我们可以这样回答: - 正常情况下,从节点可以通过GET命令获取主节点数据。 - 但由于复制延迟,从节点数据可能不是实时的。 - 另外,在过期键的处理上,从节点可能不会立即删除过期键,导致读到过期数据(但Redis3.2版本以后修复了这个问题,从节点在读取时会检查键是否过期,如果过期则返回空并异步删除)。 我们参考了引用[4]中提到的过期数据问题,说明在某些情况下确实可能遇到不一致。 因此,回答结构如下: 1. 直接回答问题:可以。 2. 解释原因:主从复制机制。 3. 注意事项:复制延迟和过期键问题。 另外,用户之前的问题是关于主从数据一致性的验证,现在这个问题是延伸问题,我们需要保证回答的连贯性。 注意:根据指令,我们需要在回答中引用参考文献,并在末尾自然地添加引用标识。同时,生成相关问题。 生成的相关问题可以围绕主从数据同步、过期键处理、如何避免读到过期数据等。 </think>### Redis节点是否可以通过GET命令获取主节点数据? #### ✅ 核心结论 **可以**。Redis节点默认支持通过`GET`命令直接读取主节点数据,这是Redis主从复制机制的核心特性之一[^1]。 #### 🔍 实现原理 Redis主从复制工作流程: ```mermaid graph LR A[客户端写入主节点] --> |1. 写入操作| B[主节点] B --> |2. 记录到缓冲区| C[复制缓冲区] B --> |3. 异步传播| D[从节点] D --> |4. 执行重放| E[数据持久化] F[客户端] --> |GET命令| D ``` 1. **数据同步机制** 主节点通过`replication feed`机制将写操作传播到所有从节点,从节点重放这些命令实现数据复制[^1] 2. **读命令处理** 从节点接收到`GET`命令时: - 直接访问本地数据集(主节点的副本) - 无需与主节点通信(降低主节点压力) - 返回当前存储的数据值[^3] #### ️ 注意事项 1. **数据延迟问题** $$ \text{主从延迟} = t_{\text{propagation}} + t_{\text{replay}} $$ - 网络延迟($t_{\text{propagation}}$)和命令重放时间($t_{\text{replay}}$)可能导致从节点数据短暂滞后 - 监控命令:`redis-cli --latency -h <slave_ip>` 2. **过期数据风险** 如引用[4]所述案例: - 主节点自动删除过期Key后,从节点可能仍返回过期数据 - 原因:Redis过期删除是惰性+定期机制,从节点不会主动删除过期Key - 解决方案:升级到Redis 3.2+(从节点读取时主动过滤过期Key)[^4] 3. **写操作限制** ```bash # 尝试在从节点写入会报错 redis-cli -h slave_ip set key value (error) READONLY You can't write against a read only replica ``` 需在配置中开启`replica-read-only no`才允许写入(不推荐)[^3] #### 💡 运维建议 1. **读写分离架构** ```python # Python示例:自动路由读写请求 def redis_client(key): if is_write_command(key): return master_connection # 写操作路由到主节点 else: return slave_pool.get_connection() # 读操作路由到从节点 ``` 2. **一致性保障配置** ```redis # 主节点redis.conf min-replicas-to-write 1 # 至少1个从节点同步 min-replicas-max-lag 10 # 最大延迟10秒 ``` 3. **过期数据检测** ```bash # 检查从节点是否有过期Key redis-cli -h slave_ip --scan | while read key; do ttl=$(redis-cli -h slave_ip ttl "$key") [ $ttl -lt 0 ] && echo "过期键: $key" done ``` #### 📊 主从读性能对比 | 指标 | 主节点 | 从节点 | |-------------------|------------|-------------| | GET命令延迟 | 0.1~1ms | 0.1~1ms | | 吞吐量(QPS) | 受写操作影响 | 可线性扩展 | | 数据实时性 | 100% | 取决于延迟 | | 故障影响范围 | 单点故障 | 无状态可替换 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值