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 的设计目标就是同时解决上述所有问题:横向扩展、高可用、高性能。 二、核心概念与架构1. 数据分片 (Sharding) - 解决容量和写性能问题Redis Cluster 将整个数据集划分为 16384 个哈希槽(Hash Slot),每个键都属于这些槽中的一个。 如何分配? 使用 CRC16(key) % 1638...
Redis集群策略
Redis 主要有三种主流的方式来构建集群,以满足不同场景下对性能、容量、高可用性的需求。我将从核心原理、优缺点和适用场景三个方面来详细介绍。 三种核心集群策略概览 策略 核心目标 数据分布 高可用实现 适用场景 主从复制 (Replication) 数据冗余、读写分离 全量复制(所有节点数据相同) 手动或外部工具切换 读多写少、数据备份、故障恢复 哨兵模式 (Sentinel) 高可用 (HA) 全量复制(所有节点数据相同) Sentinel 进程自动监控和故障转移 对可用性要求高的读写分离场景 集群模式 (Cluster) 可扩展性 & 高可用 分片 (Sharding),数据分布式存储 集成在集群中,主从切换+分片迁移 海量数据、高并发、既要读也要写的场景 1. 主从复制 (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 这几个...
Redis过期键删除策略
Redis 采用了 两种策略相结合 的方法来删除过期键,以达到在合理使用 CPU 时间和避免浪费内存空间之间取得平衡。 这两种策略是:惰性删除 和 定期删除。 此外,当内存不足时,Redis 还会采用 主动删除(逐出) 策略。 惰性删除这是默认的、在访问键时进行的删除策略。 核心思想:只有在访问一个键时,才会顺带检查它是否过期。如果过期,则立即删除。 工作原理: 当你执行 GET、HGET、LRANGE 等任何读写操作访问某个键时。 Redis 会首先检查这个键是否设置了过期时间。 如果设置了,再检查当前时间是否大于该键的过期时间。 如果已过期,则立即删除这个键,并返回 nil(或空值),就像这个键不存在一样。如果未过期,则正常返回键值。 优点: 对 CPU 友好:删除操作只会在访问键时发生,不会消耗额外的 CPU 时间去扫描大量可能永远不会被访问的过期键。 缺点: 对内存不友好:如果一个键已经过期,但之后再也没有被访问,那么它将一直占用着内存空间,成为僵尸键。这可以看作是一种内存泄漏。 为了解决惰性删除的缺点,Redis 还需要另一种策略来配合。 定期删除这...
Redis淘汰策略
Redis 为什么需要淘汰策略?Redis 是一个基于内存的数据库/缓存,当实际使用的内存量超过 maxmemory 参数设置的最大限制时,Redis 会根据配置的淘汰策略(Eviction Policy) 来移除一些键,以便为新数据腾出空间。 Redis 的淘汰策略有哪些?Redis 提供了 8 种淘汰策略,可以分为两大类: 第一类:处理过期键的策略(只针对设置了 TTL 过期的键)这组策略只在有过期时间的键中进行淘汰。 volatile-lru (Least Recently Used) 机制:从设置了过期时间的键中,淘汰最近最少使用的键。 理解:基于时间戳,认为最近没被访问的键以后也不太可能被访问。 volatile-lfu (Least Frequently Used) 机制:从设置了过期时间的键中,淘汰最不经常使用的键。 理解:基于访问频率计数器,认为访问次数最少的键是最不重要的。这是 Redis 4.0 及以上版本新增的策略。 volatile-random 机制:从设置了过期时间的键中,随机淘汰某个键。 理解:简单粗暴,没有开销,但效果不...
Redis ZSet类型解析
Redis 的 ZSet(有序集合)基础类型是一个非常有趣且高效的数据结构,它通过两种不同的内部编码(encoding)来实现其特性,在内存使用和性能之间做出了精妙的权衡。 我们主要关注以下几个方面: ZSet 的两种内部编码 数据结构定义 核心操作的源码逻辑 编码转换 总结 ZSet 的两种内部编码ZSet 并非由单一数据结构实现,而是根据一定的条件,在两种编码之间动态选择: OBJ_ENCODING_ZIPLIST (压缩列表): 在元素数量较少、元素值长度较小时使用。它是一种为节省内存而设计的紧凑型线性数据结构。所有元素(member)和分值(score)都按顺序紧密排列在同一个内存块中。 OBJ_ENCODING_SKIPLIST (跳跃表): 当元素数量或大小超过 zset-max-ziplist-entries 和 zset-max-ziplist-value 配置的阈值时,ZSet 会从 ZIPLIST 转换为 SKIPLIST。它结合了跳跃表(skiplist) 和字典(dict) 两种数据结构,以同时保证排序和高效查找。 这种设计哲学是 Redis 的...
