Redis 分区

参考
https://www.cnblogs.com/cjsblog/p/9553850.html
https://blog.youkuaiyun.com/tianmangshan80/article/details/51704974
https://blog.youkuaiyun.com/rosanu_blog/article/details/68066756

redis集群分为服务端集群客户端分片,redis3.0以上版本实现了集群机制,即服务端集群,3.0以下使用客户端分片(Sharding)。redis3.0服务端集群使用哈希槽,计算key的CRC16结果再模16834。3.0以下版本采用Key的一致性hash算法来区分key存储在哪个Redis实例上。

1 摘要

Redis分区,简单的说就是将数据分布到不同的redis实例中,因此对于每个redis实例所存储的内容仅仅是所有内容的一个子集。分区(Partitioning)不仅仅是Redis中的概念,几乎是所有数据存储系统都会涉及到的概念,这篇文章将会在理解分区基本概念的基础之上进一步了解Redis对分区的支持。

2 我们为什么要分区

通常来说,Redis分区的好处大致有如下两个方面:

  • 性能的提升: 将请求分散到多台机器,充分利用多台机器的计算能力网络带宽,有助于提高Redis总体的服务能力。
  • 存储的横向扩展: 随着存储数据的增加,单台机器受限于机器本身的存储容量,将数据分散到多台机器上存储,使得Redis服务可以横向扩展。

总的来说,分区使得我们本来受限于单台计算机硬件资源的问题不再是问题,存储、计算资源、带宽等问题,都可以通过增加机器来解决这些问题。

3 Redis分区策略

3.1 范围分区

所谓范围分区,就是将一个范围内的key都映射到同一个Redis实例中。

假设我们有4个Redis实例(R0, R1, R2, R3),其上有许多代表用户的key,比如user:1, user:2, … 等等,那么在存储一个key的时候我们有多种方式。

我们可以将用户ID从0到10000的用户数据映射到R0实例,而将用户ID从10001到20000的对象映射到R1实例,依次类推。

范围分区的优点: 虽然简单,但是在实际应用中是很有效的。

范围分区的缺点:

  1. 对于每种对象类型,都需要维护一张映射关系表,例如需要一张表用来存储用户ID范围到Redis实例的映射关系,比如用户ID:0-10000的是映射到R0实例……。
  2. 如果我们想要存储的数据的key并不能按照范围划分怎么办,比如我们的key是一组uuid,这个时候就不好用范围分区了。

因此,在实际应用中,范围分区并不是很好的选择,不用担心,我们还有更好的方法,接下来认识下哈希分区。

3.2 哈希分区

哈希分区跟范围分区相比一个明显的优点是哈希分区适合任何形式的key,而不像范围分区一样需要key的形式为object_name:,而且哈希分区方法也很简单,一个公式就可以表达:id=hash(key)%N

其中id代表Redis实例的编号,公式描述的是首先根据key和一个hash函数(如crc32函数)计算出一个数值型的值。接着上面的例子,我们的第一个要处理的key是user:1,hash(user:1)的结果是93024922。

然后哈希结果进行取模,取模的目的是计算出一个介于0到3之间的值,因此这个值才可以被映射到我们的一台Redis实例上面。比如93024922%4结果是2,我们就会知道foobar将要被存储在R2上面。

当然除了上面提到的两种分区方法,还有很多其他的方法。比如一种从哈希分区演进而来的consistent hashing分区,相关信息可以参考我的另一篇文章《memcached分布式实现原理》,其已经被redis client客户端和proxies代理实现了。

根据余数计算分散的缺点

余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。 添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器, 从而影响缓存的命中率,负载会集中到数据库服务器上。

4 不同的分区实现

  • 客户端分区 : 对即key在redis客户端就决定了要被存储在那台Redis实例中。
  • 代理分区 : 客户端发送请求到一个代理服务器,代理服务器实现了Redis协议,因此代理服务器可以代理客户端和Redis服务器通信。代理服务器代理客户端,把请求转发到正确的Redis实例中,同时将反馈消息返回给客户端。
  • 查询路由 : Redis Cluster集群实现的一种Redis分区方式。你可以将你的查询发送到任何一个Redis实例,实例会将你的查询重定向到正确的服务器。
    (PS:对于一个给定的key,分区的工作就是选择一个正确的Redis实例,那么这个选择的过程可以由客户端、代理 或者 Redis实例来做)

5 分区的不足之处

  1. 多键操作是不被支持的,比如我们将要批量操作的键被映射到了不同的Redis实例中(当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作)。
  2. 多键的Redis事务是不被支持的。
  3. 分区的最小粒度是键,因此不能将关联到一个键的很大的数据集映射到不同的实例,例如不可能将一个非常巨大的key(比如,一个非常大的sorted set)去切分数据。
  4. 当使用分区的时候,数据处理会很复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。
  5. 增加和删除redis节点变得更复杂。Redis Cluster集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于Redis 客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做presharding的技术对此是有帮助的。
  6. 单点故障:当集群中的某一台服务挂掉之后,客户端在根据一致性hash无法从这台服务器取数据。解决单点故障的方法:用到Redis主从复制的功能,两台物理主机上分别都运行有Redis-Server,其中一个Redis-Server是另一个的从库,采用双机热备技术,客户端通过虚拟IP访问主库的物理IP,当主库宕机时,切换到从库的物理IP。只是事后修复主库时,应该将之前的从库改为主库(使用命令slaveof no one),主库变为其从库(使命令slaveof IP PORT),这样才能保证修复期间新增数据的一致性。

6 数据存储还是缓存?

  • 如果使用Redis作为缓存,使用一致哈希很容易进行伸缩。如果给定key的首选节点不可用,一致哈希实现通常能够切换到其他节点。
  • 当Redis用作数据存储时,一个固定的key到实例的映射是需要的。给定的key必须总是映射到相同的Redis实例,因此节点的数量必须是固定的,且不能改变。否则,就需要一个能够在节点之间重新平衡key的系统,当前Redis集群是可以做到这一点的。

7 Pre-Sharding解决动态扩容和数据分区问题

通过上面的介绍,我们知道Redis分区应用起来是有问题的,除非我们只是使用Redis当做缓存,否则对于增加机器或删除机器是非常麻烦的。

然而,通常我们Redis容量变动在实际应用中是非常常见的,比如今天我需要10台Redis机器,明天可能就需要50台机器了。

Redis的作者提出了一种叫做presharding的方案来解决动态扩容和数据分区的问题,实际就是在同一台机器上部署多个Redis实例的方式,当容量不够时将多个实例拆分到不同的机器上,这样实际就达到了扩容的效果。Pre-Sharding方法是在每台物理机上,运行多个不同端口的Redis实例,假如有三个物理机,每个物理机运行三个Redis实例,那么我们的分片列表中实际有9个Redis实例,当我们需要扩容时,增加一台物理机来代替9个中的一个redis,有人说,这样不还是9个么,是的,但是以前服务器上面有三个redis,压力很大的,这样做,相当于单独分离出来并且将数据一起copy给新的服务器。值得注意的是,还需要修改客户端被代替的redis的IP和端口为现在新的服务器,只要顺序不变,不会影响一致性哈希分片

怎么移动Redis实例呢? 当需要将Redis实例移动到独立的机器上的时候,我们可以通过下面步骤实现:

  1. 在新机器上启动好对应端口的Redis实例。
  2. 配置新端口为待迁移端口的从库。
  3. 待复制完成,与主库完成同步后,切换所有客户端配置到新的从库的端口。
  4. 配置从库为新的主库。
  5. 移除老的端口实例。
  6. 重复上述过程迁移好所有的端口到指定服务器上。

如果主库快照数据文件过大,这个复制的过程也会很久,同时会给主库带来压力。所以做这个拆分的过程最好选择为业务访问低峰时段进行

8

<think>好的,我现在需要帮助用户了解Redis分区以及区间分区的实现方式。首先,我需要回顾一下用户提供的引用内容,看看里面提到了哪些关键点。 根据引用[1],区间分区(Range Sharding)是将一定范围的数据存储到同一个节点上,类似于数据库的分表操作,这样可以避免哈希分区的范围查询问题。引用[2]中提到Redis分区的常见规则有哈希分区和顺序分区,其中顺序分区的代表包括Bigtable和HBase,而哈希分区的代表有Redis Cluster。引用[3]则详细讨论了Redis Cluster的分区实现原理,包括数据分布、客户端寻址和键空间迁移。引用[4]是关于Redis源码分析的,可能对具体实现有帮助。 用户的问题集中在Redis分区实现,特别是区间分区方案。我需要明确区间分区的定义、实现方式,以及与哈希分区的区别。根据引用[1]和[2],区间分区属于顺序分区的一种,而Redis主要使用的是哈希分区(如Redis Cluster)。但用户可能认为Redis有区间分区的实现,需要澄清这一点。 接下来,我需要组织回答结构。首先解释Redis分区的概念,然后介绍常见的分区类型,包括哈希分区和顺序分区。在顺序分区中,详细说明区间分区的实现方式,可能结合引用中的例子。然后指出Redis自身是否支持区间分区,根据引用[2],Redis Cluster使用的是哈希槽,属于哈希分区,而区间分区可能更多是理论上的或在其他系统中的应用。但引用[1]提到区间分区Redis分区的另一种方案,可能存在混淆,需要进一步确认。 可能需要指出,虽然Redis Cluster主要用哈希分区,但用户可以通过手动分片实现类似区间分区的效果,比如根据键的范围分配。例如,将键0-1000分配给节点A,1001-2000给节点B等。这种情况下,客户端需要维护映射规则,或者使用代理中间件处理路由。 此外,需要比较哈希分区和区间分区的优缺点,例如哈希分区数据分布均匀,但范围查询效率低;区间分区便于范围操作,但数据分布可能不均匀,容易倾斜。同时,引用[2]中提到顺序分区的离散度容易倾斜,而哈希分区离散度好。 最后,生成相关问题,帮助用户进一步探索,比如Redis Cluster的数据分布机制、区间分区的适用场景、如何实现手动分片等。 需要确保回答结构清晰,分点说明,使用正确的LaTeX格式,并引用正确的来源。同时检查是否有误解或错误,比如Redis原生是否支持区间分区,根据引用资料,可能不直接支持,但可以手动实现。</think>### Redis分区与区间分区的实现方式 #### 1. **Redis分区的核心概念** Redis分区是将数据分布到多个节点的技术,每个节点仅存储整体数据的子集[^2]。其核心目标是解决单节点性能瓶颈,支持水平扩展。主要分为两类分区规则: - **哈希分区**:通过哈希函数将键映射到节点,例如$hash(key) \% N$,典型代表是Redis Cluster的哈希槽(Hash Slot)[^3]。 - **顺序分区**(区间分区):按键的自然顺序划分范围,例如将键$A0000$到$Z9999$分配给不同节点,常用于支持范围查询的场景[^1]。 #### 2. **区间分区的实现方式** 区间分区的核心是**按键范围划分数据**,具体实现需满足: - **键需有序**:例如时间戳、字母序等。 - **定义区间规则**:例如: - 节点1:$key \in [0, 1000)$ - 节点2:$key \in [1000, 2000)$ - ... - **路由逻辑**:客户端或代理需根据键的范围将请求转发到对应节点。 例如,若键为订单ID(如`order:2023-001`),可按年份或序号分段存储。 #### 3. **Redis原生支持的方案** Redis**默认采用哈希分区**(如Redis Cluster的16384个哈希槽[^3]),而**区间分区需手动实现**。具体方法包括: - **客户端分片**:在客户端代码中定义键范围与节点的映射。 - **代理中间件**:通过代理(如Twemproxy)配置区间规则,自动路由请求。 - **结合数据库**:如引用[1]所述,可模仿数据库分表,按范围分配数据到不同Redis实例。 #### 4. **哈希分区 vs 区间分区** | **特性** | **哈希分区** | **区间分区** | |----------------|---------------------------|---------------------------| | 数据分布 | 均匀(离散度好) | 可能倾斜(如热点范围) | | 范围查询效率 | 低(需跨节点) | 高(单节点完成)[^1] | | 适用场景 | 随机读写(如缓存) | 范围扫描(如日志、时序数据) | #### 5. **区间分区的应用示例** 假设存储用户年龄数据,键格式为`age:value`,可划分: - 节点A:$key \in [0, 30)$ - 节点B:$key \in [30, 60)$ - 节点C:$key \in [60, 100]$ 此时查询`age:[20, 40]`只需访问节点A和B,避免全集群扫描。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值