0、安装前环境准备
① 本篇是基于Linux操作系统中的安装,故先准备一个干净的Linux操作系统,本文中所有的操作基于CentOS8进行安装演示;
② 接下来的演示文本中,红色字体为操作步骤,黑色字体为解释说明;
③ 根据Redis中文网站的官方描述,老版本需要使用Ruby的方式来启动集群,但是在新版本中已经自带Ruby环境。所以如果使用的Redis版本比较老旧的话,建议还是使用新版本的Redis。
1、仔细阅读Redis中create-cluster的README文件
在已经解压好的Redis的源码里面,有一份搭建cluster的脚本
cd /usr/local/source/redis-6.2.5/utils/create-cluster/
老规矩,第一次面对一个从来没用安装过的软件时,去读它提供的类 README 文件,在这个文件中会详细描述当前软件的安装步骤,排错过程及各参数的详细意义,一定要仔细研读后再进行软件的安装!
vim README
再来看一眼 create-cluster 文件中的内容
vim create-cluster
NODES=6 说明在这个集群中,一共有6个节点
REPLICAS=1 说明在这6个节点中有3台是主机,有3台是从机,每台主机有1台从机
2、执行 create-cluster 启动文件启动Redis实例
./create-cluster start
启动了6台Redis实例成功
3、给Redis实例划分主从节点,并分配槽位
./create-cluster create
3台master都已经成功分配了槽位,并且5是1的备份,6是2的备份,4是3的备份,3主3从已经分配好了,并向你确认是否按照它提供的方案进行分配。
输入yes,并回车确认
显示 [OK] 说明已经按照如上的方案分配完成。
4、客户端连接Redis实例进行进行操作
我们先连接30001节点,进行一个简单的操作:set k1 xiexun
但是发现这个简单的命令却被报错,错误提示这个key的数据应该设置到30003这个节点上,这个跟我之前所提到的Redis自带的集群槽位分配策略是一样的
但是这个返回它是以error报错的形式,所以普通的客户端它只能识别到这是一个报错,而无法非常精确的区分它到底是真的报错还是返回给你别的节点的地址。
所以,应该换一个可以识别这种返回方式的连接方式去连接客户端:
redis-cli -c -p 30001
此时在3001节点设置数据以后,当Redis计算完以后发现这个数据并不属于它所在的槽位,会告诉客户端应该去连30003,然后客户端就会自动去连接30003,并将数据储存到30003。所以此时客户端所连接的并不是30001这个节点,而是30003这个节点。当你使用get命令的时候会发现可以直接从当前的节点中get出k1,因为k1就是存在当前所连接的30003这个节点中。
可以多执行几次命令来看看这个算法,当我们set k2的时候,k2经过计算应该储存到30001这个节点上,所以30003会告诉客户端去连接30001。于是客户端自动连接到30001,并将数据储存到30001。所以此时你get的k2的时候可以直接从30001中取出值。但是此时你再get k1的时候,因为k1储存在30003中,所以30001告诉客户端:我这里面没有k1,你需要去30003中去取K1,所以客户端又会自动到30003中去取得k1的值。
这就是所谓梦游的请求模式,不断的跳来跳去跳来跳去。在这个算法之下,watch和multi命令都是可以支持的,但支持的并不全面。
开启事务的时候,是在30001这个节点上开启,可是经过这个不断跳来跳去的操作之后,最后一次执行的时候,此时客户端连接的是30002这个节点,但是开启事务的是在30001这个节点,所以当开启事务的节点和执行事务的节点不是同一个节点的时候就会报错。
解决的办法也很简单,只要在key的前面加上一个特定的标识符,这样每次在计算的时候,这个特定的标识符计算的结果必然是一致的。所以针对这个标志符前缀的key,它们所分配到的节点一定是一致的,只要开启事物跟执行事务是同一个节点就没有问题。
5、手动给Redis实例划分主从节点,并分配槽位
先停掉Redis cluster集群服务,并清除旧数据
./create-cluster stop
./create-cluster clean
重新启动Redis cluster集群
./create-cluster start
之前是通过Redis自带的脚本去分配主从节点和划分槽位,其实在客户端命令中也可以手动去指定主从节点并划分槽位。先看一眼客户端命令的描述:redis-cli --cluster help
根据客户端命令的描述,我们应该执行以下命令:
redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1
这个命令的效果跟刚刚脚本的效果一模一样,没有任何区别。
输入yes,并回车确认
显示 [OK] 说明已经按照如上的方案分配完成。
连接客户端,进行一些简单的命令操作。和刚刚所搭建的集群没有任何区别,通过这个命令的方式,现在也可以通过手工去搭建集群。
6、通过 reshard 命令对集群中的数据槽位进行迁移
先看客户端命令的描述:redis-cli --cluster help
根据客户端命令的描述,我们应该执行以下命令:
① redis-cli --cluster reshard 127.0.0.1:30001
这个命令里面所移动的是数据槽位,可以手动指定移动多少个槽位。
② 需要移动2000个槽位:2000,回车确认
指定的2000个槽位要移动到哪个目标节点?这个输入的是节点的ID,而不是IP地址。
③ 需要移动到30002节点:93c8fd437de56186d40c5e73d74b0ffaac7e35d3,回车确认
2000个槽位要从哪个节点移出来?[all]指的是从所有的节点中一共抽2000个槽位挪出来,要么指定特定的节点ID,从这个指定的节点中挪出2000个槽位。
④ 需要从30001节点中挪出:e3542e16e1598524419cc4d7ead92dc3675936b2,回车确认
如果还需要从别的节点中挪出槽位,就继续输入指定节点的ID。如果不需要别的节点中挪出槽位,输入[done],表示需要挪出槽位的节点已经输入完毕。
⑤ 不需要从别的节点中挪出:done,回车确认
回车确认以后就会在屏幕上打印出会被挪动的这些槽位,以上那些配置只是表明从哪一个节点中挪取多少个槽位到哪一个节点中,但是具体挪的是哪些槽位,这个无法控制,Redis有自己的算法去确认最终挪动的槽位。
⑥ 同意Redis挪动的槽位方案:yes,回车确认
查看Redis集群槽位是否挪动成功
redis-cli --cluster info 127.0.0.1:30001
其实从这个槽位的数量中就可以看出槽位挪动成功,30001节点只有3000多个槽位,30002节点已经有7000多个槽位,而没有动过槽位的30003节点有5000多个槽位。没有挪动槽位之前,3个节点的分赃都比较均匀,挪动完以后30001槽位显著变少,30002槽位显著变多。
除了info命令以外,还有一个check命令
redis-cli --cluster check 127.0.0.1:30001
通过这个命令可以看到30001节点里现在的槽位是[2000-5460],而原本的[0-1999]槽位已经被挪到30002节点中,30003节点的槽位没有受到影响,还是原来的[10923-16383]。
这个reshare的命令就是用来解决数据倾斜的问题:当某一个节点中的数据过于庞大的时候,可以将这个节点中的一些数据平摊到其余的节点,让别的节点来分担数据上的压力。甚至可以这么用,如果想删除30001节点,就可以将30001还剩下的3461个节点全部挪到其余的节点中;或者此时新增了一台节点,可以将旧的这些节点中的数据平均分配一些到这个新增的节点中,Redis本身自带的这个集群模式给予了非常灵活的节点数据分配方案。
其实这个槽位的移动确实还存在一些小瑕疵,有人说应该对于数据倾斜的节点进行一些非常精准的移动,但是Redis并没有给与精确移动槽位的设置:只能配置移动槽位的个数,而不能精确的配置移动哪个槽位。其实对于这件事情也不必那么较真,如果Redis真能实现的话那成本也太高了。要知道Redis的核心体现在【快】,任何能够对它的【快】造成影响的操作必定会被妥协。而且Redis如果你用的多的话,你就会发现Redis的作者巨懒的一个人,他连多线程都懒得给你写,能够提供这么一个数据迁移的功能已经很不错了,他没让你把集群拆了重新搭建,已经很够意思了,对吧。
7、关于本地搭建集群的一点小问题
上面介绍了两种Redis搭建cluster的集群的方法:一种是通过自带的脚本启动,另外一种是手动命令启动。如果是通过手动命令启动的话,因为我这是为了演示方便,所以4台实例都是在一台服务器上,真正在企业中每台实例都应该独自在一台服务器上,这种情况下在Redis启动之前就需要在配置文件中加一个配置选项:cluster-enabled yes。
因为它默认是非集群的,需要你手动给它指定为是集群,指定为集群以后再去进行分赃。如果是像我演示的一样,所有的实例都在一台机子上,那这个配置加不加无所谓都可以。如果每一台实例都有自己的一台服务器是独立的,那就得加这个配置。