`
uule
  • 浏览: 6303593 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

Redis 集群分片原理

 
阅读更多

Redis的分片机制

Redis集群分片原理

Redis集群方案总结

 

Redis Cluster搭建高可用Redis服务器集群

Redis Cluster 搭建高可用Redis服务器集群2

 

为什么Redis集群有16384个槽 

CRC16算法产生的hash值有16bit,该算法可以产生2^16-=65536个值。换句话说,值是分布在0~65535之间。那作者在做mod运算的时候,为什么不mod65536,而选择mod16384?

 

redis集群内节点,每秒都在发ping消息。规律如下

(1)每秒会随机选取5个节点,找出最久没有通信的节点发送ping消息

(2)每100毫秒(1秒10次)都会扫描本地节点列表,如果发现节点最近一次接受pong消息的时间大于cluster-node-timeout/2 则立刻发送ping消息

因此,每秒单节点发出ping消息数量为数量=1+10*num(node.pong_received>cluster_node_timeout/2)

 

(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。如上所述,在消息头中,最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:65536÷8÷1024=8kb

因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽

 

(2)redis的集群主节点数量基本不可能超过1000个。如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

 

(3)槽位越小,节点少的情况下,压缩比高Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

ps:文件压缩率指的是,文件压缩前后的大小比。

 

综上所述,作者决定取16384个槽,不多不少,刚刚好!

 

 ===========================================================================

是否使用过Redis集群,集群的原理是什么?

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。

Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储

 

集群要实现的目的是要将不同的 key 分散放置到不同的 redis 节点,这里我们需要一个规则或者算法,

通常的做法是获取 key 的哈希值,然后根据节点数来求模但这种做法有其明显的弊端,当我们需要增加或减少一个节点时,会造成大量的 key 无法命中,这种比例是相当高的,所以就有人提出了一致性哈希的概念。

 

一致性哈希有四个重要特征:

 

均衡性:也有人把它定义为平衡性,是指哈希的结果能够尽可能分布到所有的节点中去,这样可以有效的利用每个节点上的资源。

单调性:当节点数量变化时哈希的结果应尽可能的保护已分配的内容不会被重新分派到新的节点。

分散性和负载:这两个其实是差不多的意思,就是要求一致性哈希算法对 key 哈希应尽可能的避免重复

 

 

但是:

Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。

 

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

这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。

 

使用哈希槽的好处就在于可以方便的添加或移除节点。

 

当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;

当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;

 

在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。

 

举个例子,比如当前集群有3个节点,那么:

节点 A 包含 0 到 5500号哈希槽.

节点 B 包含5501 到 11000 号哈希槽.

节点 C 包含11001 到 16384号哈希槽.

 

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上。如果我想移除节点A,需要将A中得槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可.

由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

 

 

Redis集群中内置了16384个哈希槽,当需要在Redis集群中放置一个key-value时,redis先对key使用crc16算法算出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同的节点

 

这个是redis集群模式示意图,将16384个槽slot分到不同的服务器上去



 

Key:a

计算a的hash值,例如值为100,100这个槽在server1上,所以a应该放到server1.

Key:hello

Hash值:10032,此槽在server2上。Hell可以应该存在server2.

===============================================================

Redis-Cluster

 

redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在【这种模式下每台redis服务器都存储相同的数据】,很浪费内存,所以在【redis3.0上加入了cluster模式,实现的redis的分布式存储】,【也就是说每台redis节点上存储不同的内容】。

 

Redis-Cluster采用无中心结构,它的特点如下:

 

1. 【所有的redis节点彼此互联(PING-PONG机制)】,内部使用二进制协议优化传输速度和带宽。

2. 节点的fail是通过集群中【超过半数的节点检测失效】时才生效。

3. 客户端与redis节点直连,不需要中间代理层。客户端不需要连接集群所有节点,【客户端连接集群中任何一个可用节点即可】。

 

redis-cluster把所有的物理节点映射到[0-16383]slot上(不一定是平均分配),cluster负责维护node<->slot<->value。

Redis集群预分好16384个桶,当需要在Redis集群中放置一个key-value 时,【根据CRC16(key) mod 16384的值,决定将一个key放到哪个桶中】。

 

要让集群正常工作至少需要3个主节点,一共就需要6个节点,其中3个为主节点,3个为从节点

 

 

工作方式:

 

在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。

当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,【通过这个值,去找到对应的插槽所对应的节点】【然后直接自动跳转到这个对应的节点上进行存取操作】。

 

Cluster集群采用了P2P的模式,完全去中心化,Redis把所有的Key分成了16384个slot,【每个Redis实例负责其中一部分slot】,集群中的所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新,Redis客户端可以在任意一个Redis实例发出请求,如果所需数据不在该实例中,通过重定向命令引导客户端访问所需的实例。

 

【为了保证高可用,redis-cluster集群引入了主从模式】,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。

 

 

选举容错

 

(1) 领导选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作.

 

(2) 什么时候整个集群不可用(cluster_state:fail)

 

a:【如果集群任意master挂掉,且当前master没有slave.集群进入fail状态】,也可以理解成集群的slot映射[0-16383]不完成时进入fail态.

redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.

 

b:如果集群【超过半数以上master挂掉,无论是否有slave集群进入fail状态】.

 

ps:当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误 

 

===============================================================

Redis集群的目的是实现数据的横向伸缩,把一块数据分片保存到多个机器,可以横向扩展数据库大小,扩展带宽,计算能力等。 

 

实现数据分片(集群)方式大致有三种: 

 

1)客户端实现数据分片

 

客户端自己计算数据的key应该在哪个机器上存储和查找。

此方法的好处是降低了服务器集群的复杂度,客户端实现数据分片时,服务器是独立的,服务器之前没有任何关联。多数redis客户端库实现了此功能,也叫sharding。

这种方式的缺点是客户端需要实时知道当前集群节点的联系信息,同时,当添加一个新的节点时,客户端要支持动态sharding.,多数客户端实现不支持此功能,需要重启redis。另一个弊端是redis的HA需要额外考虑。

 

2)服务器实现数据分片

 

其理论是,客户端随意与集群中的任何节点通信,服务器端负责计算某个key在哪个机器上,当客户端访问某台机器时,服务器计算对应的key应该存储在哪个机器,然后把结果返回给客户端,客户端再去对应的节点操作key,是一个重定向的过程,此方式是redis3.0正在实现,目前处于beta版本, Redis 3.0的集群同时支持HA功能,某个master节点挂了后,其slave会自动接管。

 

服务器端实现集群需要客户端语言实现服务器集群的协议,目前java,php,ruby语言多数有redis-cluster客户端实现版本。 

 

Redis Cluster原理http://www.cnblogs.com/foxmailed/p/3630875.html

 

Redis Cluster 是Redis的集群实现,内置数据自动分片机制,集群内部将所有的key映射到16384个Slot中,集群中的每个Redis Instance负责其中的一部分的Slot的读写。集群客户端连接集群中任一Redis Instance即可发送命令,当Redis Instance收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis Instance地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key到底属于哪个Slot由crc16(key) % 16384 决定。

 

关于负载均衡,集群的Redis Instance之间可以迁移数据,以Slot为单位,但不是自动的,需要外部命令触发。 

 

关于集群成员管理,集群的节点(Redis Instance)和节点之间两两定期交换集群内节点信息并且更新,从发送节点的角度看,这些信息包括:集群内有哪些节点,IP和PORT是什么,节点名字是什么,节点的状态(比如OK,PFAIL,FAIL,后面详述)是什么,包括节点角色(master 或者 slave)等。 

 

关于可用性,集群由N组主从Redis Instance组成。主可以没有从,但是没有从 意味着主宕机后主负责的Slot读写服务不可用。 

 

一个主可以有多个从,主宕机时,某个从会被提升为主,具体哪个从被提升为主,协议类似于Raft,参见这里。如何检测主宕机?Redis Cluster采用quorum+心跳的机制。从节点的角度看,节点会定期给其他所有的节点发送Ping,cluster-node-timeout(可配置,秒级)时间内没有收到对方的回复,则单方面认为对端节点宕机,将该节点标为PFAIL状态。通过节点之间交换信息收集到quorum个节点都认为这个节点为PFAIL,则将该节点标记为FAIL,并且将其发送给其他所有节点,其他所有节点收到后立即认为该节点宕机。从这里可以看出,主宕机后,至少cluster-node-timeout时间内该主所负责的Slot的读写服务不可用。 

 

Redis Cluster Slots是什么?http://www.zhizhihu.com/html/y2014/4590.html

 

 

 

 

3)通过代理服务器实现数据分片

 

此方式是借助一个代理服务器实现数据分片,客户端直接与proxy联系,proxy计算集群节点信息,并把请求发送到对应的集群节点。降低了客户端的复杂度,需要proxy收集集群节点信息。Twemproxy是twitter开源的,实现这一功能的proxy。这个实现方式在客户端和服务器之间加了一个proxy,但这是在redis 3.0稳定版本出来之前官方推荐的方式。结合redis-sentinel的HA方案,是个不错的组合。

 

 

  • 大小: 65.3 KB
分享到:
评论

相关推荐

    Redis Cluster集群数据分片机制原理

    主要介绍了Redis Cluster集群数据分片机制原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    Redis分片池 代码

    此代码更好的解决Redis集群的开发,里面写有Redis工具类,简单易懂的理解Redis分片池原理

    Redis分布式集群实战(4)——redis集群之Codis讲解和搭建

    文章目录一、认识Codis1、什么是codisCodis 基本框架由以下组件组成2、Codis重要性3、Codis 代理4、Codis 分片原理5、不同的 Codis 实例之间槽位关系如何同步?zookeeper6、扩容7、自动均衡8、Codis 的代价9、Codis ...

    redisStudy.zip

    基本回答:Rediscluster是一个高可用集群,它基于分片(对key进行crc16,然后对16384取余)的原理,可以把他理解为是由多组哨兵集群组成,但是它不依赖哨兵 6.缓存穿透 缓存穿透指的是使用不存在的key进行大量的...

    rcc:一个简单的asyncio redis客户端,具有集群支持和重新分片的cli工具

    一般的 具有redi-trib精神的cli line工具的Redis Cluster Client。安装UNIX一线curl -sL https://raw.githubusercontent.com/machinezone/rcc/master/tools/install.sh | sh您可以先查看安装脚本的功能。对于熟悉...

    Java思维导图xmind文件+导出图片

    MongoDB数据分片、转存及恢复策略 MyCat MySQL主从复制及读写分离实战 MySQL+keepalived实现双主高可用方案实践 MySQL高性能解决方案之分库分表 数据库中间件初始Mycat 基于Mycat实习MySQL数据库读写分离 ...

    04_Redi核心使用.pdf

    全面介绍了Reids的前世今生,核心理念; 包含基础数据、高级数据、消息队列、关键的持久化、事务、主从+哨兵+集群;数据分片原理

    新版 MySQL DBA 高级视频 基于MySQL 5.7 MySQL 8.0版本.rar

    │ 03集群分片副本操作.mp4 │ 04es集群运维.mp4 │ 04redis数据类型操作.mp4 │ 04安装search-guard.docx │ 05redis主从和哨兵操作.mp4 │ 06reids集群创建收缩扩容.mp4 │ 07redis运维工具.mp4 │ Elasticsearch...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    分片 Key-hash 异步 一致性hash 消峰 分库分表 锁 悲观锁 乐观锁 行级锁 分布式锁 分区排队 一致性 一致性算法 paxos zab nwr raft gossip 柔性事务(TCC) 一致性原理 CAP BASE 中间件 ...

    JAVA上百实例源码以及开源项目

     Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构,  当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket...

    JAVA上百实例源码以及开源项目源代码

     Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构,  当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket...

Global site tag (gtag.js) - Google Analytics