8.Redis- 集群:AKF拆分(y轴和z轴),twemproxy,predixy,cluster

容量问题

单机redis在使用的时候会碰到三个问题:单点故障、容量不足、访问压力。

因此我们可以对redis进行AKF拆分,站在x轴的角度上可以对redis进行 主从复制 + 哨兵机制。

主从复制:slave做master的全量备份保证数据的可靠性。master对外提供读写,slave对外提供读操作(读写分离),解决了 部分访问压力。
哨兵机制:对master做高可用,使用 哨兵集群 监控master健康状态,哨兵之间相互通信,如果发现master挂了会进行投票选举 其中一个个slave作为新的master。解决了单点故障的问题。

但是由于slave是master的全量数据,在容量这个维度上来说,redis依然是一个单实例的。对于臃肿的redis实例来说,还需要对其进行y轴个z轴的拆分。

什么是容量问题呢?
如果一个redis,它的内存是有限的,即便服务器有128G内存,也不可能让一个redis实例把128G内存全部使用,因为做持久化等等消耗时间成本很大。所以我们尽量控制一个redis实例只使用几G内存,这样这个实例的所有环节和动作都会很轻盈。

Y轴拆分

在这里插入图片描述

在数据可以分类,较比不是很多的情况下,我们可以在Client端把要写入redis数据 根据业务(商品、购物车、订单) 在AKF的Y轴上进行分类,把不同的分类写入不同的redis实例。
换个角度讲,就是每个redis实例自己是不知道拆分的,是Client中融入一部分 业务拆分逻辑 代码,使Client根据不同的业务访问不同的redis。

但是如果根据业务进行拆分后,某一个业务的数据数据量很大(比如:订单),应该如何继续拆分?
答案:在AKF的Z轴上继续拆分。

Z轴拆分

拆分逻辑在Client

Y轴拆分后某一业务的数据量还是很大,我们可以对Z轴方向上,在Client端根据 算法 继续拆分。(sharding 分片)

1. modula(hsah + 取模):

在这里插入图片描述

这种方式是在Client增加算法逻辑,把要存入数据的进行 % 运算,后边有几个redis实例,就和几进行 % 运算,根据取模的值,把数据存入到不同的redis实例。

优点: 简单,容易操作。
缺点: 取模 的值是固定的,影响分布式下的扩展性,如果添加新的redis实例会使 模数值 发生改变,再取数据的时候根据 模数 去取就无法查找到数据了。

2. random:

在这里插入图片描述
Client把数据随机放到不同的redis实例中:
一定会有很多人会问 ,随机把数据放入不同的redis,取出成本会不会很高?或者根本找不到数据?
但是为什么还会有这random模型呢? 如果存入的是一个list类型(lpush),key为ooxx,那么就会在两个redis中都生成ooxx的key,这个时候 消费者 并不是执行lpush的Client,而是执行rpop的另一个Client,都会从ooxx中取数据,无论从哪个redis取,都会取到key为ooxx的数据。这样就形成了一个类似于消息队列的功能。

说的简单一些,就是应用list类型 左进右出 或者 右进左出 的特性模拟队列,只不过在random模型中Client把list数据分发给不同的redis可以起到一个缓冲的效果,更适合高并发的场景。

3. ketama(一致性hash):

相较于 hash + 取模 的方式 弊端,有一种更好的解决方案,就是ketama的方式,其核心就是 一致性hash 算法。

先了解 一致性hash 算法:

在这里插入图片描述
在得到一个长度随机的字符串后(redis的key),经过算法得到一个等宽的其他的值(算法:hash、crc16、crc32、fnv、md5),这个值会和字符串做一个映射。和hash取模算法不同的是,一致性hash没有取模的过程(即:不会影响分布式扩展性),并且要求key和node都要参与计算。
然后会在内存中虚拟出一个环形(哈希环)。

在这里插入图片描述
假如这个哈希环由0 — 2^32个数字组成,每一个数字都是一个点。无论后面有多少个redis实例,或新增,或减少,都会给这些redis实例一个ID号(或者IP+Port之类的)唯一标识。

如果这个时候有一个 node1 节点,把node1的ID 经过 一个统一的hash算法就会得到一个值,这个值会映射到哈希环的某一个点上。这个时候新增node2节点,同样把node2节点的ID经过 统一的hash运算 得到一个值,也映射到这个哈希环上某个点。(node在哈希环上对应的点 称之为 物理点)

现在 在哈希环上有两个node映射的物理点,把这两个物理点放入带有排序功能的TreeMap集合里。这个时候如果Client要写入数据,可以把数据的key也参与hash运算后会到一个值,并且这个值同样映射到 哈希环 上点,然后用这个映射点和TreeMap里面的物理点进行对比,查找大过自己并且距离自己最近的点是哪个?最后把数据存入距离自己最近的物理点对应的node就可以了。

优点:
没有固定node数量的限制,不会造成全局洗牌。

缺点:
新增节点后,造成一小部分数据无法命中。
如上图,新增一个节点 node3,把node3的ID进行hash运算得到一个数值,这个数值对应 哈希环 的点 恰好在之前数据映射的点和它存入node之间(data -> node2 变为 data -> node3 -> node2), 此时如果查询data,不会从node2查询,而是会从node3里面查找data,因此查询结果为null。
所以,这种方式只适合做缓存而不适合做数据库,缓存大多为期限,即使node2里面data数据永远不会被查询到,data也会随着时间的推移而被清除掉,或者开启缓存清理策略LRU、LFU。并且node3里面无法查询到数据,可以走数据库从新缓存到node3(缓存击穿),也可以修改为从比自己大的两个node中查找数据。


扩展:虚拟节点
如果node1和node2映射在 哈希环 的点分别在最左边 和 最右边,把哈希环切分成了 上半环 和 下半环,在添加数据的时候就可能出现 数据集中在某个半环上而导致 数据量 的倾斜。
我们可以每个node ID后面依次拼10个数字,让一个ID变成10个,用这些ID做hash运算映射到 哈希环 不同的点上,如果是两个设备在 哈希环 上面就会有20个点,这样做的目的是让一个物理设备出现在 多个 点上,就可以间接的解决数据倾斜的问题。

拆分逻辑在Proxy

拆分逻辑在Client弊端

在这里插入图片描述
在Client里实现 Z轴 拆分逻辑,虽然能解决容量问题,但是在实际场景中,一台redis可能要面对多个Client,换言之 每个Client都要和每个redis实例进行连接,况且每个Client不可能只和redis开一个连接,而是应该开一个连接池缓存10个或更多的连接。即便是没有连接池,每次TCP握手和分手都是一个损耗的事情。

结论:redis的连接成本很高。

如何解决?增加proxy代理。

Proxy拆分逻辑原理

在这里插入图片描述
可以在Client和redis之间增加一个代理层(proxy),类似于Nginx这种应用层 的反向代理,基于反向代理的基础上 负载均衡服务器。

Client只需要和proxy建立握手,proxy再单独和多个redis实例建立握手,这样就可以减少对redis的socket连接的压力。这个时候我们更关注的是proxy的性能。
基于proxy的理论,可以把在Client的拆分逻辑 迁移 到 代理层,所以在代理层可以对modula、random、ketama进行逻辑实现。

注意:无论拆分逻辑在Client还是Proxy,都没有脱离modula、random、ketama三种模式,并且都只适合作为缓存,不适合做数据库。这个问题如何解决?redis自带的拆分:cluster。

常用的代理:twemproxypredixy

拓展 -> proxy是不需要记录Client状态,本身不存在数据库存储,所以proxy是无状态的 ,很容易的就可以把proxy一变多:
如果在高并发场景下,一个proxy不够用了怎么办:

在这里插入图片描述
那就使用两个proxy,让固定Client组连接固定的proxy,为了提高可用性,可以搭建LVS四层 负载均衡 服务器 对两个proxy做负载均衡。
但是LVS也是一个单点,并且不能对后端的proxy集群做健康检查,所以可以使用keepalived建立VIP对LVS做主备HA高可用。

同时建立LVS的VIP也有一个好处:无论企业后端技术多复杂,对用户都是透明的。用户只需要访问VIP就OK!

redis自带的拆分:cluster

redis作为数据库的情况下,可以使用redis自带的拆分cluster。规避了ketama新增redis实例时截断数据的情况,那么cluster是如何做到的呢?

引导:

在这里插入图片描述
假如现在有两台redis服务器,分别是redis1和redis2,以后还会出现第三台服务器redis3。
在加入新节点到集群的话,无论拆分逻辑是在Client还是在Proxy,对算法都是一个极大的挑战。

要解决这个问题,可以在 拆分逻辑中 进行 预分区
现在有两个redis节点,未来就可能有10个节点。那么在两个节点的时候,就可以直接取模10个节点,取模的结果为 0 ~ 9 ,两个节点可以分别对0~9个节点做一个mapping(10个槽位),比如:
redis1映射0,1,2,3,4
redis2映射5,6,7,8,9
(各领取5个槽位)。
这个时候如果redis3加入集群,会让redis1和redis2让出几个槽位,比如从redis1中拿到了3和4,在redis2中拿到了8和9(如上图)。移动数据的时候,不需要把redis全部rehash,只需要把3,4,8,9槽位的时点数据找到直接传输给redis3,redis3接收完数据后,会根据 时点数据 跟redis1和redis2传输期间内的数据做一个追平更新,追平的一刹那,再往3,4,8,9槽位存数据就会直接存入redis3。
Client只需要知道映射关系,就可以根据槽位正确的读取数据了。

cluster:

在这里插入图片描述
有3台redis服务器,分别是redis1,redis2,redis3。

Client想要存入k1,会随机访问redis1和redis2。
和之前不同的是每一个redis中都存在hash算法,并且保存了集群内其他redis实例的槽位映射关系(知道别人有什么),满足了这两个条件后,就可以让每个redis实例都能当家做主。
这样k1随机进入一个redis实例后(假设这个实例是redis2),redis2会先拿k1进行hash取模算出槽位,用计算的槽位和自己的mapping映射的槽位做一个匹配,如果和自己匹配就直接存入redis2,如果不匹配再和redis2内保存的其他实例的槽位映射关系进行匹配,就能找到k1需要存的redis实例是哪个,把k1返回给Client 并 重定向到正确的redis实例中(假设匹配结果为redis3)。redis3拿到k1后同样要进行hash运算并且 把结果和自身映射槽位进行匹配,匹配成功直接存入自己这个实例当中。

摘要redis中文网:
“实际redis中,Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念。
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。”

这就是redis自带的cluster,是一种无主模型。

注意:只要把数据拆分,无论逻辑在Client、Proxy、还是redis自身,都会有一个问题 : 聚合操作很难实现。

  1. 一个操作需要几个key,但是这些key都不在一个节点上。
  2. 事务
  3. set集合的交集,并集,差集运算。两个set分别在不同的redis中,如果redis自身实现就会涉及数据移动过程,redis在设计的思想是 计算 向 数据移动,而不是移动数据。redis的特点就是快,所以作者做了一个取舍。

解决方案:问题的起点在于 数据被分开。换言之,数据不会被分开就能够实现 聚合操作。
操作的key都在相同的节点,可以用 hash tag 。
比如:把key设置成为{oo}k1,{oo}k2,{oo}k3这种带有{}内部有固定标识的 格式,这样在存入key的时候会使用 oo 进行取模,而不会使用k1,k2,k3进行取模。进而存入同一个redis节点。

twemproxy操作演示

GitHub地址:https://github.com/twitter/twemproxy

安装:

cd /soft/twemproxy										//新建存放twemproxy的目录
git clone  https://github.com/twitter/twemproxy.git		//从git上clone下该项目
yum install automake libtool  -y  						//安装automake和libtool
autoreconf -fvi											//执行完之后目录文件多出configure可执行文件
./configure 											//执行configure文件
make													//进行编译
cd src/													//进入src目录,会看到nutcracker可执行程序
cd ../													//会看见有scripts脚本目录
cd scripts												//进入scripts目录,会看见nutcracker.init文件

###################################  把twemproxy变为服务  ##################################

cp nutcracker.init /etc/init.d/twemproxy					//把nutcracker.init拷贝到/etc/init.d/目录
cd /etc/init.d/												//发现cp后的twemproxy还没有变绿,所以要赋予权限
chmod 777 twemproxy 										//赋予权限,使其变绿
vi twemproxy 							//发现里面OPTIONS="-d -c /etc/nutcracker/nutcracker.yml" 需要在指定目录有nutcracker.yml文件。
mkdir  /etc/nutcracker										//创建目录
cd /soft/twemproxy/twemproxy/conf				//回到twemproxy安装目录下的conf目录,里面有nutcracker.yml文件
cp ./*  /etc/nutcracker/									//拷贝当前目录下所有文件到 /etc/nutcracker/	目录
cd  /soft/twemproxy/twemproxy/src							//进入src目录下
cp nutcracker /usr/bin/										//把之前编译的可执行程序复制到 /usr/bin/	目录
cd /etc/nutcracker/											//进入之前移动配置文件的目录
cp nutcracker.yml nutcracker.yml.bak						//把nutcracker.yml文件进行备份(好习惯)
vi nutcracker.yml												//修改配置文件,下面有详细介绍

nutcracker.yml 详解

alpha:
  listen: 127.0.0.1:22121			#代理众多redis实例对外暴露的统一访问接口
  hash: fnv1a_64					#使用的hash算法
  distribution: ketama				#分布式使用的模型
  auto_eject_hosts: true
  redis: true						#代理的是redis
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - 127.0.0.1:6379:1
   - 127.0.0.1:6380:1				#计量代理的两个redis实例

演示

先启动两个redis:

cd
mkdir data
cd data
mkdir 6379
mkdir 6380
cd 6379
redis-server --port 6379

############# 切入到新窗口

cd data/6380
redis-server --port 6380

启动twemproxy :

[root@z8524210 6379]# service twemproxy start 
Reloading systemd:                                         [  确定  ]
Starting twemproxy (via systemctl):                        [  确定  ]
[root@z8524210 6379]# 

启动后,连接twemproxy提供的统一接口,并添加元素:

[root@z8524210 6379]# redis-cli -p 22121
127.0.0.1:22121> set k1 aaa
OK
127.0.0.1:22121> set k2 asd
OK													//在统一接口里添加4个元素 k1,k2,k3和 1 
127.0.0.1:22121> set k3 asd
OK													//这些数据都存到哪些实例了呢?
127.0.0.1:22121> set 1 zhangsan
OK
127.0.0.1:22121> 

然后连接redis6379和redis6380接口,并查看各自实例的元素:

#######################################  6379  ####################################

[root@z8524210 ~]# redis-cli -p 6379
127.0.0.1:6379> KEYS *
1) "1"												//6379里面有一个 1 元素
127.0.0.1:6379> 

#######################################  6380  ####################################

[root@z8524210 ~]# redis-cli -p 6380
127.0.0.1:6380> KEYS *
1) "k1"
2) "k3"												//6380里面有 k1,k2,k3三个元素 
3) "k2"
127.0.0.1:6380> 

但是因为数据分治,所以不支持聚合操作:

127.0.0.1:22121> KEYS *
Error: Server closed the connection					//聚合操作会报错
127.0.0.1:22121> WATCH k1
Error: Server closed the connection
127.0.0.1:22121> MULTI
Error: Server closed the connection
127.0.0.1:22121> 

predixy操作演示

Github地址:https://github.com/joyieldInc/predixy

Predixy可以在所有主流平台下编译,推荐在linux下使用,需要支持C++11的编译器。所以直接下载别人编译好的程序。

[root@z8524210 ~]# mkdir predixy
[root@z8524210 ~]# cd predixy/
[root@z8524210 ~]# wget https://github.com/joyieldInc/predixy/releases/download/1.0.5/predixy-1.0.5-bin-amd64-linux.tar.gz
[root@z8524210 predixy]# cd predixy/				//下载完之后进入predixy目录

下载完之后进入predixy目录:

[root@z8524210 predixy]# ll
总用量 36
drwxr-xr-x. 2 root root   21 6月  11 17:47 bin
drwxr-xr-x. 2 root root  178 6月  11 18:03 conf
-rw-r--r--. 1 root root   26 6月  11 17:42 _config.yml
drwxr-xr-x. 3 root root  112 6月  11 17:42 doc
-rw-r--r--. 1 root root 1537 6月  11 17:42 LICENSE
-rw-r--r--. 1 root root  274 6月  11 17:42 Makefile
-rw-r--r--. 1 root root 5680 6月  11 17:42 README_CN.md
-rw-r--r--. 1 root root 4200 6月  11 17:42 README.md
drwxr-xr-x. 2 root root 4096 6月  11 17:43 src
drwxr-xr-x. 2 root root   39 6月  11 17:42 test

/**
*	可以看到有可执行程序的bin目录,里面只有一个predixy可执行程序。
*	还有conf配置文件目录,里面是很多配置文件
*/

进入到conf目录:

[root@z8524210 predixy]# cd conf/
[root@z8524210 conf]# ll
总用量 36
-rw-r--r--. 1 root root 2395 6月  11 17:42 auth.conf
-rw-r--r--. 1 root root 1041 6月  11 17:42 cluster.conf				//cluster配置文件
-rw-r--r--. 1 root root 3426 6月  11 17:42 command.conf
-rw-r--r--. 1 root root  781 6月  11 17:42 dc.conf
-rw-r--r--. 1 root root 2121 6月  11 17:42 latency.conf
-rw-r--r--. 1 root root 2544 6月  11 17:56 predixy.conf				//主配置文件
-rw-r--r--. 1 root root 1849 6月  11 18:03 sentinel.conf			//哨兵配置文件
-rw-r--r--. 1 root root 2016 6月  11 17:42 standalone.conf		
-rw-r--r--. 1 root root   98 6月  11 17:42 try.conf
[root@z8524210 conf]# 

vi predixy.conf,需要设置的地方主要有两个:

GENERAL模块:Bind 127.0.0.1:7617    			//设置对外暴露的统一接口
SERVERS模块:Include sentinel.conf				//引入哨兵配置文件

设置好predixy.conf文件后,继续修改哨兵的配置文件vi sentinel.conf:

SentinelServerPool {
    Databases 16
    Hash crc16
    HashTag "{}"
    Distribution modula
    MasterReadPriority 60
    StaticSlaveReadPriority 50
    DynamicSlaveReadPriority 50
    RefreshInterval 1
    ServerTimeout 1
    ServerFailureLimit 10
    ServerRetryTimeout 1
    KeepAlive 120
    Sentinels {
        + 127.0.0.1:26379								//三个哨兵的 IP+端口
        + 127.0.0.1:26380
        + 127.0.0.1:26381
    }
    Group ooxx {						//一套哨兵可以监控多套主从,一个Group为一套主从。
    }									//Client写入的数据会被打散分别存入ooxx主从的master和xxoo主从的master。
    Group xxoo {
    }
}

编写三个哨兵的配置文件:

[root@z8524210 test]# vi 26379.conf 
port 26379
sentinel monitor ooxx 127.0.0.1 36379 2			//第一套主从ooxx的master ID+ Port,组为ooxx
sentinel monitor xxoo 127.0.0.1 46379 2			//第二套主从xxoo的master ID+ Port	组为xxoo

[root@z8524210 test]# vi 26379.conf 
port 26380
sentinel monitor ooxx 127.0.0.1 36379 2
sentinel monitor xxoo 127.0.0.1 46379 2

[root@z8524210 test]# vi 26379.conf 
port 26381
sentinel monitor ooxx 127.0.0.1 36379 2
sentinel monitor xxoo 127.0.0.1 46379 2

在三个窗口分别启动哨兵:

[root@z8524210 test]# redis-server 26379.conf --sentinel
[root@z8524210 test]# redis-server 26380.conf --sentinel
[root@z8524210 test]# redis-server 26381.conf --sentinel

建立四个个文件夹36379、36380、46379、46380,分别进去启动对应的redis

//开启两个主机
[root@z8524210 36379]# redis-server --port 36379
[root@z8524210 46379]# redis-server --port 46379

//开启两个从机,追随对应的主机
[root@z8524210 36380]# redis-server --port 36380 --replicaof 127.0.0.1 36379
[root@z8524210 46380]# redis-server --port 46380 --replicaof 127.0.0.1 46379

启动predixy代理:

[root@z8524210 bin]# ./predixy ../conf/predixy.conf 
2020-06-11 19:38:06.154417 N Proxy.cpp:112 predixy listen in 127.0.0.1:7617
2020-06-11 19:38:06.154595 N Proxy.cpp:143 predixy running with Name:PredixyExample Workers:1
2020-06-11 19:38:06.154953 N Handler.cpp:456 h 0 create connection pool for server 127.0.0.1:26380
2020-06-11 19:38:06.155035 N ConnectConnectionPool.cpp:42 h 0 create server connection 127.0.0.1:26380 5
2020-06-11 19:38:06.155150 N Handler.cpp:456 h 0 create connection pool for server 127.0.0.1:26381
2020-06-11 19:38:06.155172 N ConnectConnectionPool.cpp:42 h 0 create server connection 127.0.0.1:26381 6
2020-06-11 19:38:06.155212 N Handler.cpp:456 h 0 create connection pool for server 127.0.0.1:26379
2020-06-11 19:38:06.155225 N ConnectConnectionPool.cpp:42 h 0 create server connection 127.0.0.1:26379 7
2020-06-11 19:38:06.156206 N StandaloneServerPool.cpp:422 sentinel server pool group ooxx create master server 127.0.0.1:36379 
2020-06-11 19:38:06.156221 N StandaloneServerPool.cpp:472 sentinel server pool group ooxx create slave server 127.0.0.1:36380 
2020-06-11 19:38:06.156226 N StandaloneServerPool.cpp:422 sentinel server pool group xxoo create master server 127.0.0.1:46379 
2020-06-11 19:38:06.156228 N StandaloneServerPool.cpp:472 sentinel server pool group xxoo create slave server 127.0.0.1:46380 

/**
*	可以从日志中看到,对外暴露了7617的统一访问接口。
*	以及3个哨兵的 IP + Port
*	还有两队主从集群
*/

往7617统一接口中存入key,然后验证存入的key具体存入哪个实例。

/**
*	往7617统一接口中,存入k1和k2和hash tag 的key
*/	
[root@z8524210 ~]# redis-cli -p 7617
127.0.0.1:7617> set k1 sdasd
OK
127.0.0.1:7617> get k1
"sdasd"
127.0.0.1:7617> set k2 aaaa
OK
127.0.0.1:7617> set {xx}k1 dasdas
OK
127.0.0.1:7617> set {xx}k2 dasdas
OK
127.0.0.1:7617> set {xx}k3 dasdas
OK

/**
*	连接36379 mastr ,查看数据
*/
[root@z8524210 ~]# redis-cli -p 36379
127.0.0.1:36379> KEYS *
1) "k1"
127.0.0.1:36379> 
													//能够发现k1和k2分别存入了36379和46379两个master中
/**
*	连接46379 mastr ,查看数据,发现hash tag 都存到了这个主机里
*/
[root@z8524210 ~]# redis-cli -p 46379
127.0.0.1:46379> KEYS *
1) "{xx}k2"
2) "k2"
3) "{xx}k3"
4) "{xx}k1"
127.0.0.1:46379> 

但是因为分治的原因,不能实现聚合操作,除非配置文件中只有一套主从(单group):

127.0.0.1:7617> WATCH {xx}k1
(error) ERR forbid transaction in current server pool
127.0.0.1:7617> 

当ooxx的36379 master挂了后,哨兵会发现,然后36380会成为新的master:

127.0.0.1:7617> set k5 dsd
OK
127.0.0.1:7617> 
[root@z8524210 ~]# redis-cli -p 36380
127.0.0.1:36380> KEYS *
1) "k5"
2) "k1"
127.0.0.1:36380> 

代理就是解耦 后端的复杂度,使用的时候比较舒适!

cluster操作演示

先去使用测试脚本感受一下:

[root@z8524210 ~]# cd /soft/redis-5.0.4/utils/create-cluster
[root@z8524210 create-cluster]# vi create-cluster 		//查看脚本

create-cluster脚本(部分):

#!/bin/bash

# Settings
PORT=30000
TIMEOUT=2000
NODES=6					//表示一共有6个节点
REPLICAS=1				//有三个slave节点

启动6个节点:

[root@z8524210 create-cluster]# ./create-cluster start
Starting 30001
Starting 30002
Starting 30003
Starting 30004
Starting 30005
Starting 30006
[root@z8524210 create-cluster]# 

创建cluster集群:

[root@z8524210 create-cluster]# ./create-cluster create
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460									//这里显示有三个主,第一个master有0-5460个槽位
Master[1] -> Slots 5461 - 10922								// 第二个master有5461-10922个槽位
Master[2] -> Slots 10923 - 16383							// 第三个master有10923-16383个槽位
Adding replica 127.0.0.1:30005 to 127.0.0.1:30001			//123位master,456为slave
Adding replica 127.0.0.1:30006 to 127.0.0.1:30002
Adding replica 127.0.0.1:30004 to 127.0.0.1:30003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 604529304a6ff642659ca98c0772ae97df3ca57e 127.0.0.1:30001
   slots:[0-5460] (5461 slots) master
M: daf084af642bb6369eb0adb72463eb6c2fdcd240 127.0.0.1:30002
   slots:[5461-10922] (5462 slots) master
M: e55845c60c3039d776ae7fb4a8c5cb73cf0117da 127.0.0.1:30003
   slots:[10923-16383] (5461 slots) master
S: c647248988b60acaddd535a57c6e6ddaa4e37728 127.0.0.1:30004
   replicates 604529304a6ff642659ca98c0772ae97df3ca57e
S: 34e7bc777d6ccf28e5133ff138217ad1282a6db7 127.0.0.1:30005
   replicates daf084af642bb6369eb0adb72463eb6c2fdcd240
S: bd8d511ce888966443720b1ad453b8c4edc1abc3 127.0.0.1:30006
   replicates e55845c60c3039d776ae7fb4a8c5cb73cf0117da
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 127.0.0.1:30001)
M: 604529304a6ff642659ca98c0772ae97df3ca57e 127.0.0.1:30001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: bd8d511ce888966443720b1ad453b8c4edc1abc3 127.0.0.1:30006
   slots: (0 slots) slave
   replicates e55845c60c3039d776ae7fb4a8c5cb73cf0117da
S: 34e7bc777d6ccf28e5133ff138217ad1282a6db7 127.0.0.1:30005
   slots: (0 slots) slave
   replicates daf084af642bb6369eb0adb72463eb6c2fdcd240
S: c647248988b60acaddd535a57c6e6ddaa4e37728 127.0.0.1:30004
   slots: (0 slots) slave
   replicates 604529304a6ff642659ca98c0772ae97df3ca57e
M: daf084af642bb6369eb0adb72463eb6c2fdcd240 127.0.0.1:30002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: e55845c60c3039d776ae7fb4a8c5cb73cf0117da 127.0.0.1:30003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@z8524210 create-cluster]# 

以普通Client存入数据会报错:

[root@z8524210 create-cluster]# redis-cli -p 30001				
127.0.0.1:30001> KEYS *
(empty list or set)
127.0.0.1:30001> set k1 dasd
(error) MOVED 12706 127.0.0.1:30003			//报错,提示要移动到30003上才能创建,应该用cluster的方式进入客户端
127.0.0.1:30001> 

用cluster的方式进入Client:

[root@z8524210 create-cluster]# redis-cli -c -p 30001
127.0.0.1:30001> set k1 aaaa
-> Redirected to slot [12706] located at 127.0.0.1:30003		//存入k1的时候会跳转到30003客户端
OK
127.0.0.1:30003> set k2 cccc							
-> Redirected to slot [449] located at 127.0.0.1:30001			//存入k2的时候会跳转到30001客户端
OK
127.0.0.1:30001> set k3 cccc									//k3计算后,就在30001客户端,所以没有跳转
OK
127.0.0.1:30001> set {xx}k1 asds
-> Redirected to slot [15983] located at 127.0.0.1:30003		//hash tag的方式可以让key存入同一个节点
OK
127.0.0.1:30003> set {xx}k2 asds
OK
127.0.0.1:30003> set {xx}k3 asds
OK
127.0.0.1:30003> set {xx}k4 asds
OK
127.0.0.1:30003> WATCH k2								//非hash tag聚合操作会报错
-> Redirected to slot [449] located at 127.0.0.1:30001
OK
127.0.0.1:30001> MULTI
OK
127.0.0.1:30001> get k1
-> Redirected to slot [12706] located at 127.0.0.1:30003
"dasd"
127.0.0.1:30003> set k5 dasd
OK
127.0.0.1:30003> EXEC
(error) ERR EXEC without MULTI						//报错了
127.0.0.1:30003> WATCH {xx}k1 						//使用hash tag就能实现聚合操作,因为数据都在一个实例里
OK
127.0.0.1:30003> MULTI
OK
127.0.0.1:30003> get {xx}k2
QUEUED
127.0.0.1:30003> get {xx}k3
QUEUED
127.0.0.1:30003> set {xx}k4 dasda
QUEUED
127.0.0.1:30003> exec
1) "asds"
2) "asds"
3) OK
127.0.0.1:30003> 

测试脚本的命令:

[root@z8524210 create-cluster]# ./create-cluster satrt				//启动节点
[root@z8524210 create-cluster]# ./create-cluster create			//创建集群
[root@z8524210 create-cluster]# ./create-cluster stop				//停止集群和节点
[root@z8524210 create-cluster]# ./create-cluster clean				//清理数据文件

/**
*	在真实环境中,可以把satrt的步骤 换成 依次启动我们自己的集群节点。
*	create启动集群的步骤,可以使用客户端命令启动
*/

真实使用:

先查看帮助命令

[root@z8524210 create-cluster]# redis-cli --cluster help
Cluster Manager Commands:
  create         host1:port1 ... hostN:portN
                 --cluster-replicas <arg>
  check          host:port
                 --cluster-search-multiple-owners
  info           host:port
  fix            host:port
                 --cluster-search-multiple-owners
  reshard        host:port
                 --cluster-from <arg>
                 --cluster-to <arg>
                 --cluster-slots <arg>
                 --cluster-yes
                 --cluster-timeout <arg>
                 --cluster-pipeline <arg>
                 --cluster-replace
  rebalance      host:port
                 --cluster-weight <node1=w1...nodeN=wN>
                 --cluster-use-empty-masters
                 --cluster-timeout <arg>
                 --cluster-simulate
                 --cluster-pipeline <arg>
                 --cluster-threshold <arg>
                 --cluster-replace
  add-node       new_host:new_port existing_host:existing_port
                 --cluster-slave
                 --cluster-master-id <arg>
  del-node       host:port node_id
  call           host:port command arg arg .. arg
  set-timeout    host:port milliseconds
  import         host:port
                 --cluster-from <arg>
                 --cluster-copy
                 --cluster-replace
  help           

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

[root@z8524210 create-cluster]# 

模拟启动6个节点:

[root@z8524210 create-cluster]# ./create-cluster start
Starting 30001
Starting 30002
Starting 30003
Starting 30004
Starting 30005
Starting 30006

/**
*	手工启动的redis实例需要在配置文件中开启 cluster-enabled yes 
*/

使用客户端手工创建集群:

[root@z8524210 create-cluster]# 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

移动槽位:

[root@z8524210 create-cluster]# redis-cli --cluster reshard 127.0.0.1:30001
>>> Performing Cluster Check (using node 127.0.0.1:30001)
M: 07a92516271c6c748d89f2b8adaace50f3385d46 127.0.0.1:30001					//30001的ID
   slots:[2000-5460] (3461 slots) master
   1 additional replica(s)
S: b1c430bce3b79b4d8959b9b4f575a723f2fce84c 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 2089c5c063fda989cfbbc83171654bcde79a98d9
S: 774dd32475129b76c06c512cd2d1316e507970a3 127.0.0.1:30005
   slots: (0 slots) slave
   replicates 76be6e16cbdd1e489672a3d63de0e4914347ec9d
S: 20c688e9a5151d149c1c052ad801a8fff971ef34 127.0.0.1:30004
   slots: (0 slots) slave
   replicates 07a92516271c6c748d89f2b8adaace50f3385d46
M: 76be6e16cbdd1e489672a3d63de0e4914347ec9d 127.0.0.1:30002					//30002的ID
   slots:[0-1999],[5461-10922] (7462 slots) master
   1 additional replica(s)
M: 2089c5c063fda989cfbbc83171654bcde79a98d9 127.0.0.1:30003					//30003的ID
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 2000
What is the receiving node ID? 07a92516271c6c748d89f2b8adaace50f3385d46		//这里添加新节点的ID
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.		// all表示从所有节点中抽取
  Type 'done' once you entered all the source nodes IDs.					//done 表示结束
Source node #1: 76be6e16cbdd1e489672a3d63de0e4914347ec9d					// 输入30002的ID,表示从30002中移动槽位
Source node #2: done												//结束,按回车,开始移动槽位

....

Do you want to proceed with the proposed reshard plan (yes/no)? yes 	//输入yes表示赞同,回车,等待移动完成

查看槽位:

[root@z8524210 create-cluster]# redis-cli --cluster info 127.0.0.1:30001		//随便选一个节点的ip端口
127.0.0.1:30001 (07a92516...) -> 0 keys | 5461 slots | 1 slaves.		//之前30001有7000多槽位,现在变为5000了
127.0.0.1:30002 (76be6e16...) -> 0 keys | 5462 slots | 1 slaves.		//之前30002有3000多槽位,现在变为5000了
127.0.0.1:30003 (2089c5c0...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
[root@z8524210 create-cluster]# 

查看节点的详情:

[root@z8524210 create-cluster]# redis-cli --cluster check 127.0.0.1:30001			//随便选一个集群中节点的ip和端口


戏入人生
整理完毕!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值