Redis和MySQL如何保证数据一致性
Redis 和 MySQL 保证数据一致性是一个在分布式系统设计中常见的挑战。由于 Redis 通常作为缓存(Cache)使用,而 MySQL 作为持久化数据库(Database),两者之间的数据同步需要精心设计。 没有一个银弹方案可以适用于所有场景,关键取决于你的业务对一致性级别(强一致性还是最终一致性)和性能的要求。 核心问题:为什么会出现不一致?不一致通常发生在写操作过程中。当数据在 MySQL 中被修改后,如果 Redis 中的旧缓存没有被及时处理,后续的读请求就会读到脏数据。 常用策略方案以下是几种主流的解决方案,从简单到复杂。 缓存失效模式 (Cache-Aside Pattern)这是最常用、最基础的策略。其核心原则是:程序只直接管理缓存的数据和有效期,不主动更新缓存,而是在读取时懒加载数据。 写流程 (Write): 先更新(或删除)MySQL 中的数据。 然后,删除(Invalidate) Redis 中对应的缓存。 注意:是删除缓存,而不是更新它。这是一个关键点,目的是让下次读请求时再重新加载数据,避免在写过程中并发读导致缓存与数据库不一致。 ...
缓存穿透、缓存击穿、缓存雪崩
缓存穿透缓存穿透是指查询一个根本不存在的数据。由于缓存中不存在(未命中),这个请求会直接穿透缓存层,到达数据库。如果同时有大量这样的请求(比如恶意攻击、爬虫扫描),会给数据库造成巨大压力,甚至可能压垮数据库。 核心原因: 数据在缓存和数据库中都不存在。 解决方案: 缓存空对象: 即使从数据库没查到,也把一个空值(比如 null)或特殊标记存入缓存,并设置一个较短的过期时间(例如 5分钟)。后续同样的请求就会命中缓存,拿到这个空值,从而保护数据库。 缺点: 如果恶意攻击者用大量不同的 key 来攻击,会导致缓存中存储大量无用的空值,浪费内存。 布隆过滤器: 这是解决此问题的最优方案。在访问缓存和数据库之前,先将所有可能存在的 key 哈希到一个巨大的位图(BitMap)中。 流程: 收到请求 -> 先查布隆过滤器 -> 如果过滤器说肯定不存在,则直接返回空,不再访问缓存和数据库 -> 如果过滤器说可能存在,再继续走正常的缓存流程。 优点: 内存占用极小,能高效判断一个元素是否绝对不存在于某个集合中。 缺点: 有极低的误判率(可能会把不存在的 key 判为...
Redis集群模式下大Key问题
在 Redis 集群模式下,大Key(Big Key)导致的问题会比在单机模式下更复杂、更严重。 我们可以将这些问题分为两类:集群特有问题和通用问题(在单机和集群都会出现,但在集群中后果更严重)。 集群特有问题这些问题直接由 Redis Cluster 的分片(Sharding)架构引起。 数据倾斜与节点负载不均 原因:Redis Cluster 通过哈希槽(Hash Slot)分片数据。一个巨大的 Key(例如,一个包含数百万字段的 Hash)必然属于某个特定的哈希槽,而一个哈希槽只能存在于一个主节点上。 问题:这会导致存储这个巨大 Key 的节点内存使用率远高于其他节点。同时,所有针对这个大 Key 的读写请求都会集中打到这一个节点上,而其他节点压力很小。 后果:整个集群无法实现水平的负载均衡,该节点可能因压力过大而提前达到内存上限、CPU 负载过高、响应变慢,从而成为整个系统的瓶颈。这违背了使用集群扩展性能和容量的初衷。 迁移失败与阻塞 原因:在进行集群扩缩容、数据重新分片(reshard)或者故障转移时,数据需要在节点之间迁移。迁移的基本单位是 Key。 问题...
Redis集群添加节点槽位迁移分析
第一部分:为什么要迁移槽位?首先,要理解迁移的目的。Redis Cluster 共有 16384 个槽位。数据通过 CRC16(key) mod 16384 的算法被分配到这些槽中。每个主节点负责处理其中一部分槽位。 当你向一个已经平衡的集群添加新的主节点时,这个新节点默认是不负责任何槽位的(即它的槽位计数为 0)。这意味着它无法处理任何请求。为了让新节点分担负载,必须从现有节点中拿走一部分槽位及其对应的数据,并分配给新节点,这个过程就是槽位迁移。 第二部分:槽位迁移的详细步骤整个迁移过程由集群管理员通过 redis-cli --cluster 工具触发,但背后是一系列精细的协议和命令。我们可以将其分解为几个核心阶段: 阶段一:准备新节点并加入集群 启动新节点:启动两个新的 Redis 实例(一个主节点,一个从节点),并以集群模式运行。 加入集群:使用 CLUSTER MEET <ip> <port> 命令,让新节点与集群中任意一个已知节点取得联系,并最终成为集群的一份子。此时,新节点是空的,不持有任何槽位。 阶段二:规划迁移 触发重分配:使用集群管理...
Redis集群Gossip协议
什么是 Gossip 协议?Gossip 协议,中文常译为流言协议或流行病协议,是一种去中心化的、基于感染式传播的通信协议。它的灵感来源于人类社会中的流言传播或流行病扩散。 其核心思想是: 随机选择:集群中的每个节点都会随机地选择几个其他节点。 交换信息:节点之间周期性地(例如,每秒一次)交换自己所知道的信息(即元数据)。 最终一致性:经过一段时间后,集群中的所有节点都会获得完全一致的元数据信息,从而达到最终一致性。 这个过程就像办公室里一个人知道了一个八卦,他随机找几个人说了这个八卦,这些人又随机找其他人说,很快整个办公室的人都知道了。 为什么 Redis 集群需要 Gossip 协议?Redis 集群是一个去中心化的架构。它没有像 ZooKeeper 或 etcd 那样的中心协调节点来统一管理所有节点的状态信息。那么,集群中的每个节点是如何知道其他节点的存在、状态(是在线还是下线)、以及负责的槽位(slot)信息呢? 这就是 Gossip 协议的用武之地。Redis 集群使用 Gossip 协议来实现: 节点发现:新节点加入集群后,如何让其他节点知道它。 元数据传播:...
Redis Cluster集群模式
Redis Cluster 是 Redis 官方提供的分布式数据库解决方案,它通过分片(Sharding) 来进行数据共享,并提供复制和故障转移的功能。简单来说,它解决了单机 Redis 容量有限和高可用性不足的问题。 为什么要使用 Redis Cluster?在单机 Redis 模式下,我们会遇到两个核心瓶颈: 容量瓶颈:单台机器的内存容量有限,无法存储超大规模的数据集。 性能瓶颈:单个 Redis 实例的处理能力受限于单核 CPU(Redis 是单线程模型),无法应对高并发读写需求。 可用性瓶颈:虽然主从复制+哨兵模式(Sentinel)提供了高可用性,但主从模式下所有节点存储的都是全量数据,无法解决容量和写性能的问题。 Redis Cluster 的设计目标就是同时解决上述所有问题:横向扩展、高可用、高性能。 核心概念与架构数据分片 (Sharding) - 解决容量和写性能问题Redis Cluster 将整个数据集划分为 16384 个哈希槽(Hash Slot),每个键都属于这些槽中的一个。 如何分配? 使用 CRC16(key) % 16384 这个公式来...
Redis集群策略
Redis 主要有三种主流的方式来构建集群,以满足不同场景下对性能、容量、高可用性的需求。我将从核心原理、优缺点和适用场景三个方面来详细介绍。 三种核心集群策略概览 策略 核心目标 数据分布 高可用实现 适用场景 主从复制 (Replication) 数据冗余、读写分离 全量复制(所有节点数据相同) 手动或外部工具切换 读多写少、数据备份、故障恢复 哨兵模式 (Sentinel) 高可用 (HA) 全量复制(所有节点数据相同) Sentinel 进程自动监控和故障转移 对可用性要求高的读写分离场景 集群模式 (Cluster) 可扩展性 & 高可用 分片 (Sharding),数据分布式存储 集成在集群中,主从切换+分片迁移 海量数据、高并发、既要读也要写的场景 主从复制 (Replication)这是最基础的模式,通常由一个 主节点 (Master) 和若干个 从节点 (Slave/Replica) 组成。 工作原理: 从节点启动后,向主节点发送 SYNC 命令。 主节点执行 BGSAVE 生成 RDB 快照文件,并缓存期间的写命令...
Redis分布式锁
Redis 分布式锁的底层实现经历了从简单到复杂、从不可靠到相对可靠的演进过程。其核心思想是:在分布式系统中,用一个共用的 Redis服务来充当一个公证人,所有客户端通过在这个公证人那里占坑的方式来获取锁,通过删坑来释放锁。 最基础的实现:SETNX + DEL这是最原始的想法,利用 Redis 的 SETNX(Set if Not eXists)命令。 加锁:SETNX lock_key my_random_value 如果返回 1,说明设置成功,客户端获取到锁。 如果返回 0,说明 key 已存在,锁被其他客户端持有,当前客户端获取失败。 解锁:DEL lock_key 删除这个 key,释放锁供其他客户端使用。 存在的问题: 死锁:如果获取锁的客户端宕机,无法执行 DEL 命令,那么这个锁将永远无法被释放,其他客户端再也无法获得锁。 误释放:客户端 A 获取锁后,如果业务执行时间过长,锁超时被 Redis 自动释放(假设设置了过期时间),客户端 B 获取到了锁。此时客户端 A 执行完,调用 DEL 命令,就会错误地释放了客户端 B 的锁。 改进版:SET...
Redis事务如何实现ACID
Redis 事务在隔离性 (Isolation) 上做得非常出色,在原子性 (Atomicity) 上则是部分保证,其一致性 (Consistency) 和持久性 (Durability) 的实现则更多地依赖于 Redis 的持久化机制而非事务本身。 下图清晰地对比了Redis事务在各ACID属性上的实现机制与特点: flowchart TD A[Redis ACID 属性实现] subgraph Atomicity[原子性 Atomicity - 部分保证] direction LR A1[EXEC前] --> A2["入队错误: 全体取消"] A3[EXEC后] --> A4["运行时错误: 继续执行,无回滚"] end subgraph Consistency[一致性 Consistency - 保证] direction LR C1[入队前检查] --> C2[语法错误拒绝入队] C3[执行时检查] --> C4[类型错误继续执行] C5[乐观锁] --> C6[WATCH机制保障] end subgraph ...
Redis事务实现
Redis 的事务实现与传统关系型数据库(如 MySQL)有根本性的不同。它不保证严格的原子性(Atomicity),也没有回滚(Rollback)机制。其核心思想是将多个命令打包,然后顺序地执行,并保证在执行期间不会被其他客户端的命令打断。 Redis 事务的实现主要依赖于以下几个命令和机制: 核心命令 MULTI:标记一个事务块的开始。随后的命令都不会立即执行,而是被服务器放入一个队列中。 EXEC:执行事务队列中的所有命令,并返回所有命令的返回值。 DISCARD:取消事务,清空事务队列。 WATCH:监视一个或多个 key。如果在 EXEC 命令执行前,这些被监视的 key 被其他客户端修改,那么整个事务将被取消(EXEC 返回 nil 表示事务失败)。 UNWATCH:取消所有 WATCH 命令对 key 的监视。 事务执行的三阶段一个完整的 Redis 事务过程可以分为三个阶段: 事务开始 (MULTI): 客户端执行 MULTI 命令,服务器会将此客户端的状态从非事务状态切换到事务状态。之后,除了 EXEC, DISCARD, WATCH, MULTI 这几个...
