是否使用过 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集群的目的是实现数据的横向伸缩,把一块数据分片保存到多个机器,可以横向扩展数据库大小,扩展带宽,计算能力等。
实现数据分片(集群)方式大致有三种:
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方案,是个不错的组合。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Elasticsearch 集群搭建和集群原理
- RabbitMQ集群原理介绍
- Redis集群实现原理探讨
- 一致性原理与zookeeper集群
- 集群管理系统 Mesos 的设计原理
- 进阶的Redis之哈希分片原理与集群实战
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。