【Redis】集群存储算法

本文详细探讨了Redis集群存储中采用的分布式算法,包括哈希取余、一致性哈希、哈希槽分区,以及Redis如何利用哈希槽解决数据分布问题。重点介绍了各算法的工作原理、优缺点和应用场景,以及Redis集群存储策略的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、集群存储算法

1.1、分布式存储算法

分布式存储的常见算法:

  • 哈希取余算法分区
  • 一致性哈希算法分区
  • 哈希槽算法分区

1.2、哈希取余算法分区

算法描述:hash(key) % N(其中,key是要存入Redis的键名,N是Redis集群的机器台数)。用户每次读写操作,都是根据传入的键名经过哈希运算,对机器台数取余决定该键存储在哪台服务器上。

优点:简单直接有效,只需要预估好数据规划好节点,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。

缺点:原来规划好的节点,如果进行了扩容或者缩容,导致节点有变动,映射关系需要重新进行计算。在服务器个数固定不变时没问题,如果需要弹性扩容或者故障停机的情况下,原来取模公式中的 N就会发生变化,此时经过取模运算的结果就会发生很大变化,导致根据公式获取的服务器变得不可控。

1.3、一致性哈希算法

算法背景:一致性哈希算法是为了解决哈希取余算法中的分布式缓存数据变动和映射问题。当服务器个数发生变化时,尽量减少影响到客户端与服务器的映射关系。

算法描述:

一致性哈希算法必然有个hash函数并按照算法产生Hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个Hash区间[0, 2^32 - 1],这是一个线性空间。但是在这个算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。

它也是按照使用取模的方式。前面的哈希取余算法是对节点个数进行取模,而一致性哈希算法是对 2^32取模。

简单来说,一致性Hash算法将整个哈希值空间组成一个虚拟的圆环。如假设某个哈希函数H的值空间为 0到2^32 - 1(即哈希值是一个32位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4…直到2^32 - 1,也就是说0点左侧的第一个点代表 2^32 - 1。0 和 2^32 - 1在零点钟方向重合,我们把这个由 2^32个点组成的圆环称为Hash环。
在这里插入图片描述
有了哈希环之后,还需要进行节点映射,将集群中各个IP节点映射到环上的某一个位置。

将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希。这样每台机器就能确定其在哈希环上的位置。

假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希值后在环空间的位置如下:
在这里插入图片描述
key落到服务器的落键规则。当我们需要存储一个key键值对时,首先计算key的hash值(hash(key)),将这个key使用相同的函数hash,计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储字该节点上。

假如我们有ObjectA、B、C、D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性hash算法,数据A会被定位到NodeA上,B被定位到NodeB上,C被定位到NodeC上,D被定位到NodeD上。
在这里插入图片描述
假设NodeC宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重新定位到NodeD。

一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间的数据,其他不会受到影响。

即:假设NodeC宕机,只会影响到Hash定位到NodeB到NodeC之间的数据,并且这些数据会被转移到NodeD进行存储。
在这里插入图片描述
假如需要扩容增加一台节点NodeX,NodeX的hash(ip)位于NodeB和NodeC之间,那受到影响的就是NodeB 到 NodeX 之间的数据。重新将B到X的数据录入到X节点上即可,不会导致Hash取余全部数据重新洗牌的后果。
在这里插入图片描述
但是Hash环会存在数据倾斜问题。

一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象都集中到某一台或某几台服务器)。
在这里插入图片描述
为了解决数据倾斜问题,一致性哈希算法引入了虚拟节点机制。

对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以先确定每个物理节点关联的虚拟节点数量,然后在IP或主机名后面加上编号。

例如,可以对NodeA节点虚拟出 NodeA#1、NodeA#2、NodeA#3,对NodeB虚拟出NodeB#1、NodeB#2、NodeB#3的节点,形成六个虚拟节点。
在这里插入图片描述
优点:加入和删除节点时,只会影响哈希环中顺时针方向相邻节点,对其他节点无影响。

缺点:数据的分布和节点的位置有关,因为这些节点不是均匀分布在哈希环上的,所以在数据进行存储时达不到均匀部分的效果。

1.4、哈希槽分区

哈希槽分区是为了解决一致性哈希算法的数据倾斜问题。

哈希槽实质上就是一个数组,数组[0, 2^14 - 1]形成的 hash slot空间。

目的是为了解决均匀分配的问题。在数据和节点之间又加入了一层,把这层称之为槽(slot),用于管理数据和节点之间的关系。就相当于节点上放的是槽,槽里面放的是数据。·
在这里插入图片描述

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。

哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。

一个集群只能有== 16394==个槽,编号 0 - 16383(2^14 - 1)。这些槽会分配给集群中所有的主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点,集群会记录节点和槽的对应关系。

解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,根据余数决定key落到哪个槽里。

1.5、Redis集群存储策略

Redis集群使用的就是哈希槽。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置在哪个槽,集群的每个节点负责一部分hash槽。

哈希槽数量16384(2^14)的决定原因:

CRC16算法产生的hash值有 16bit,该算法可以产生 2^16 = 65536个值。但是为了心跳方便和数据传输最大化,槽的数量只能有 2^14个。

  1. 如果槽位数量为65535个,那么发送心跳信息的消息头将达到 8k,发送的心跳包过于庞大。在消息头中最占空间的是 myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是 :
65536 ÷ 8 ÷ 1024 = 8Kb

每秒中redis节点需要发送一定数量的ping消息作为心跳,如果槽位为65536,那么这个ping消息头就会太大浪费带宽。

  1. redis集群的主节点数量基本不可能超过1000个。集群节点越多,心跳包的消息体内携带的数据越多。如果节点超过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点超过1000个。对于节点数在1000以内的redis cluster集群,16384个槽位足够了,没有必要扩展到65536个。
  2. 槽位越小,节点少的情况下压缩比越高,容易传输。Redis主节点的配置信息中它锁负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率 slots / N(N为节点数)很高的话,bitmap的压缩率就很低。如果节点数很少,而哈希槽数很多的话,bitmap的压缩率就很低。
<think>我们有两个主要问题:Redis集群算法详解和Redis事务与数据库事务的差异对比。首先,根据引用[5]我们可以知道Redis集群使用的是哈希槽分区算法(hashslot)。另外,引用[3]提到Redis5之后集群搭建更加方便,将redis-trib.rb集成到了redis-cli中。其次,关于Redis事务与数据库事务的差异,引用[1]和[2]都提到了Redis事务与关系型数据库事务存在差异,特别是Redis不支持回滚(除了在命令入队时的错误)以及使用WATCH实现乐观锁。因此,回答将分为两部分:第一部分:Redis集群算法详解(重点在哈希槽分区算法)第二部分:Redis事务与数据库事务的差异对比注意:引用[4]提到了Redis的性能优势(内存存储)以及与其他数据库的对比,可以在事务对比部分提到持久化相关的差异。由于用户要求参考之前的回答,我们之前已经详细对比过Redis事务和数据库事务,这里可以简要总结,重点放在集群算法上。系统指令要求:数学公式用$...$,独立公式用$$...$$,使用中文,生成相关问题,引用标识自然添加。结构:1.Redis集群算法详解1.1集群概念(引用[5]中的目录)1.2数据分片方式与规则(三种算法:哈希求余、一致性哈希、哈希槽,重点讲哈希槽)1.3哈希槽分区算法的具体实现(槽的数量、分配、重分配等)1.4集群的搭建(基于docker,引用[5]和[3])1.5集群的容错(主节点宕机处理,引用[5])1.6集群扩容(引用[5])2.Redis事务与数据库事务的差异对比2.1回顾Redis事务机制(MULTI/EXEC/WATCH,原子性、隔离性等)2.2与数据库事务(ACID)的对比2.3重点差异(原子性、隔离性、持久性、错误处理)注意:由于引用内容有限,我们主要基于已有的引用和之前的知识进行回答。下面开始组织回答。</think>### Redis集群算法详解与事务差异对比 #### 一、Redis集群算法详解 Redis集群采用**哈希槽分区算法**(Hash Slot Partitioning),这是其分布式架构的核心设计[^5]。与传统分片算法相比,其工作原理如下: 1. **哈希槽基础机制** - 整个集群划分为**16384个固定槽位**(slots),编号0-16383 - 每个键通过CRC16校验算法计算哈希值: $$slot = CRC16(key) \mod 16384$$ - 槽位均匀分配到集群节点,例如3节点集群可能分配: ``` Node1: 0-5460 槽 Node2: 5461-10922 槽 Node3: 10923-16383 槽 ``` 2. **关键优势对比** | 算法类型 | 数据分布 | 扩容影响 | 热点问题 | Redis采用 | |------------------|------------|----------------|----------------|-----------| | 哈希求余 | 不均匀 | 需全部重哈希 | 严重 | ❌ | | 一致性哈希 | 较均匀 | 局部数据迁移 | 可能发生 | ❌ | | **哈希槽分区** | **均匀** | **仅迁移槽数据** | **自动均衡** | ✅ | 3. **集群运维特性** - **自动故障转移**:主节点宕机时,从节点通过Gossip协议选举新主节点[^3] - **无缝扩容**:添加新节点时,只需迁移部分槽位数据(如`redis-cli --cluster reshard`) - **请求重定向**:客户端访问错误槽位时,返回`MOVED`指令引导正确节点[^5] > **案例**:集群从3节点扩容到4节点时,每个节点交出约4096个槽位(16384/4),仅迁移约25%的数据量[^5]。 #### 二、Redis事务 vs 数据库事务差异 基于Redis内存型架构与关系数据库的持久化设计差异,事务实现存在本质区别: | 特性 | Redis事务 | 数据库事务 (如MySQL) | 关键差异原因 | |--------------------|--------------------------------------|-----------------------------------|--------------------------| | **原子性** | 仅EXEC执行时原子;运行时错误不中断[^1] | 完全原子性(错误自动ROLLBACK) | Redis无undo log机制 | | **隔离性** | 无隔离级别,依赖`WATCH`乐观锁[^2] | 支持4种隔离级别(如Read Committed)| Redis单线程处理命令 | | **持久性** | 依赖AOF/RDB配置[^4] | 默认保证(WAL日志) | 内存存储 vs 磁盘存储 | | **一致性** | 弱一致性(网络分区可能丢失数据) | 强一致性(ACID约束) | 集群模式下CAP取舍[^3] | | **错误处理** | 语法错误入队时拒绝;运行时错误继续 | 任何错误触发全回滚 | Redis无事务日志 | | **执行模式** | 命令队列批量执行 | 真正的原子操作序列 | 设计目标不同[^1] | **典型场景对比**: 1. **转账操作** - MySQL: ```sql START TRANSACTION; UPDATE accounts SET balance=balance-100 WHERE user=1; UPDATE accounts SET balance=balance+100 WHERE user=2; COMMIT; -- 任一失败则自动回滚 ``` - Redis: ```lua WATCH balance:1 balance:2 MULTI DECRBY balance:1 100 INCRBY balance:2 100 EXEC -- 若其他客户端修改余额,则EXEC失败 ``` 2. **容错差异** - 当对字符串执行`INCR`时: - MySQL:事务回滚,数据不变 - Redis:错误命令跳过,其他命令继续执行[^1] #### 三、设计哲学差异 - **Redis**:优先保证**高性能**(单线程10万+ QPS[^4])和**简单性**,牺牲强一致性 - **数据库**:优先保证**数据安全**,通过锁/日志实现ACID,性能较低 > 实践建议:金融系统用数据库事务,缓存/计数器用Redis事务;集群中启用`AOF+fsync everysec`提升持久性[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值