redis的Cluster集群学习

1,263 阅读10分钟
Share猿,一个极客共同交流学习的社区!

关键词

  • cluster
  • 去中心化
  • 节点槽位
  • 网络抖动
  • CRC16算法(槽位定位算法)

记录

关于cluster

RedisCluster 是redis的亲儿子,他是redis作者自己提供的redis集群解决方案。

问题

1.cluster是去中心化的集群,什么是去中心化集群?

去中心化集群指的就是各个节点之间都是平等的,而且每个节点具有高度自治的特征,节点之间相互连接通讯保持数据的一致性。我们最熟知的去中心应用比特币系统,就是一个去中心化的系统。

2.cluster为什么要将所有数据划分为 16384 的 slots(槽位)?

2.1什么是solts(槽位,又称为hash槽)?

通过上一节学习codies集群,我们知道codies有1024个槽位,为什么cluster集群会有这么多,什么是槽位/hash槽哪?

槽位其实就相当于我们缓存桶,16384个槽位就相当于16384个存储数据的缓存桶,cluster集群会把这个16384个缓存桶均匀分配给集群的各个节点

节点A覆盖0-5460;

节点B覆盖5461-10922;

节点C覆盖10923-16383.

当我们在集群中放置一个key-value的时候,cluster会根据CRC16(key)mod16384得出的值,该值决定我们的key-value放到哪个缓存桶里面。

当我们新增集群节点的时候,新增的集群节点会从现有的各个节点中获取一部分缓存桶

节点A覆盖1365-5460

节点B覆盖6827-10922

节点C覆盖12288-16383

节点D覆盖0-1364,5461-6826,10923-12287

看到这里,想必大家也知道什么是redis cluster的槽位,为什么cluster集群的槽位比codies多的原因。

2.2.基于上面的回答我又提出一个问题,去中心化节点是把槽位均分到各个集群节点上,假如我们其中一个节点挂了,整个集群岂不是挂了??

经过网上查资料,发现,所谓的去中心化节点准确的说应该是去中心化主节点,上面的ABC节点在部署的时候我们还要对其部署对应的从节点,这样才能保证其中一个主节点挂了而不影响整个集群。所以cluster集群是一种:去中心化+主从的集群模式

2.3.关于槽位定位算法

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位

Cluster 还允许用户强制某个 key 挂在特定槽位上,通过在 key 字符串里面嵌入 tag 标记,这就可以强制 key 所挂在的槽位等于 tag 所在的槽位

3.什么是cluster跳转?

3.1.什么是cluster的转?

说的直白一点就是从一个节点跳到另一个集群节点。

3.2.如何跳转?

当我们对一个集群节点发送了一个指令,发现该节点不存在该指令的槽位,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。

GET x
-MOVED 3999 127.0.0.1:6381

MOVED 指令的第一个参数 3999 是 key 对应的槽位编号,后面是目标节点地址。MOVED 指令前面有一个减号,表示该指令是一个错误消息。

客户端收到 MOVED 指令后,要立即纠正本地的槽位映射表。后续所有 key 将使用新的槽位映射表。

4.cluster集群如何进行多个节点之间数据的迁移?

Redis Cluster 提供了工具 redis-trib 可以让运维人员手动调整槽位的分配情况,它使用 Ruby 语言进行开发,通过组合各种原生的 Redis Cluster 指令来实现。

redis-trib提供了UI界面方便我们的迁移,还提供了自动平衡槽位的工具,无需人工干预就能均衡集群负载。

4.1.迁移过程

从源节点获取内容 => 存到目标节点 => 从源节点删除内容。

5.redis的cluster集群是如何保证容错性的?

Redis Cluster 可以为每个主节点设置若干个从节点,单主节点故障时,集群会自动将其中某个从节点提升为主节点。如果某个主节点没有从节点,那么当它发生故障时,集群将完全处于不可用状态。不过 Redis 也提供了一个参数cluster-require-full-coverage可以允许部分节点故障,其它节点还可以继续提供对外访问。

6.什么是网络抖动?cluster集群如何防止网络抖动带来的数据不一致性?

所谓网络抖动就是网络异常情况,突然不可访问,一会儿又好了。这种情况可能导致cluster的主从节点频繁切换。

针对上述情况,cluster提供了一个选项cluster-node-timeout,他存在的意义在于防止网络抖动而引起频繁的节点切换。设置了该选项只有当节点长期失联的时候才会进行主从切换。

7.cluster是如何判断一个节点是否下线的?

只有当大多数节点都认定了某个节点失联了,集群才认为该节点需要进行主从切换来容错。

一个节点发现某个节点失联了 (PFail),它会将这条信息向整个集群广播,其它节点也就可以收到这点失联信息。

如果一个节点收到了某个节点失联的数量 (PFail Count) 已经达到了集群的大多数,就可以标记该节点为确定下线状态 (Fail),然后向整个集群广播,强迫其它节点也接收该节点已经下线的事实,并立即对该失联节点进行主从切换。

8.如何使用cluster集群?(redis-py 客户端不支持 Cluster 模式)

要使用 Cluster,必须安装另外一个包,这个包是依赖 redis-py 包的。pip install redis-py-cluster

>>> from rediscluster import StrictRedisCluster
>>> # Requires at least one node for cluster discovery. Multiple nodes is recommended.
>>> startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
>>> rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)
>>> rc.set("foo", "bar")
True
>>> print(rc.get("foo"))
'bar'

Cluster 是去中心化的,它有多个节点组成,构造 StrictRedisCluster 实例时,我们可以只用一个节点地址,其它地址可以自动通过这个节点来发现。不过如果提供多个节点地址,安全性会更好。如果只提供一个节点地址,那么当这个节点挂了,客户端就必须更换地址才可以继续访问 Cluster。 第二个参数 decode_responses 表示是否要将返回结果中的 byte 数组转换成 unicode。

Cluster 使用起来非常方便,用起来和普通的 redis-py 差别不大,仅仅是构造方式不同。但是它们也有相当大的不一样之处,比如 Cluster 不支持事务,Cluster 的 mget 方法相比 Redis 要慢很多,被拆分成了多个 get指令,Cluster 的 rename 方法不再是原子的,它需要将数据从原节点转移到目标节点。

9.cluster集群是如何感知槽位迁移的?

客户端保存了槽位和节点的映射关系表,它需要即时得到更新,才可以正常地将某条指令发到正确的节点中。

10.cluster集群发生变更客户端是如何接受到通知的?

我们前面提到 Cluster 有两个特殊的 error 指令,一个是 moved,一个是 asking。

第一个 moved 是用来纠正槽位的。

第二个 asking 指令和 moved 不一样,它是用来临时纠正槽位的。

moved 和 asking 指令都是重试指令,客户端会因为这两个指令多重试一次。

11.尝试自己搭建一个cluster集群

11.1. 准备配置文件

创建cluster目录,并创建6个配置文件

11.2. 修改配置文件

port 7000 //端口7000,7002,7003..
daemonize yes //redis后台运行
pidfile ./redis_7000.pid //pidfile文件对应7000,7001,7002
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_7000.conf //集群的配置 配置文件首次启动自动生成 7000,7001,7002
cluster-node-timeout 15000 //请求超时 默认15秒,可自行设置
appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志
//若设置密码,master和slave需同时配置下面两个参数:
masterauth "12345678" //连接master的密码
requirepass "12345678" //自己的密码

11.3. 启动、测试所有redis实例

  • 创建启动文件:vi start-all.sh
  • 赋予权限:chmod u+x start-all.sh
  • 启动:./start-all.sh

11.4. 安装redis-trib所需的 ruby脚本

ruby redis-trib.rb //测试是否安装成功,若已经安装过,可跳过此步

安装

cp /usr/andy/redis/redis-3.2.0/src/redis-trib.rb .

yum install ruby

yum install rubygems

gem install redis-3.2.2.gem //需下载redis-3.2.2.gem

11.5. 使用redis-trib.rb创建集群

执行下面命令创建集群(需为真实ip,不然外网无法访问):

./redis-trib.rb create --replicas 1 192.168.0.217:7000 192.168.0.217:7001 192.168.0.217:7002 192.168.0.217:7003 192.168.0.217:7004 192.168.0.217:7005

可以看到:

  • 7003是7000主节点的从节点,管理槽0-5460
  • 7004是7001主节点的从节点,管理槽5461-10992
  • 7005是7002主节点的从节点,管理槽10992-16383

12.使用客户端操作对cluster集群进行一些常规指令的操作

集群

cluster info :打印集群的信息

cluster nodes :列出集群当前已知的所有节点( node),以及这些节点的相关信息。

节点

cluster meet ip port:将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。

cluster forget <node_id> :从集群中移除 node_id 指定的节点。

cluster replicate <node_id> :将当前节点设置为 node_id 指定的节点的从节点。

cluster saveconfig :将节点的配置文件保存到硬盘里面。

槽(slot)

cluster addslots <slot> [slot ...] :将一个或多个槽( slot)指派( assign)给当前节点。

cluster delslots <slot> [slot ...] :移除一个或多个槽对当前节点的指派。

cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。

cluster setslot <slot> node <node_id> :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。

cluster setslot <slot> migrating <node_id> :将本节点的槽 slot 迁移到 node_id 指定的节点中。

cluster setslot <slot> importing <node_id> :从 node_id 指定的节点中导入槽 slot 到本节点。

cluster setslot <slot> stable :取消对槽 slot 的导入( import)或者迁移( migrate)。

cluster keyslot <key> :计算键 key 应该被放置在哪个槽上。

cluster countkeysinslot <slot> :返回槽 slot 目前包含的键值对数量。

cluster getkeysinslot <slot> <count> :返回 count 个 slot 槽中的键

复盘

学完这一小节明白了cluster集群的基本原理,以及槽位等一些相关概念,了解了CRC16算法,学会如何搭建一个cluster集群。

扫描以下二维码关注社区公众号↓↓↓↓↓↓↓↓

更多资讯请在简书、微博、今日头条、掘金、CSDN都可以通过搜索“Share猿”加入Share猿社区!!!