1、概述
Redis Cluster是Redis 的分布式解决方案,在3.0版本正式推出,有效地解决了Redis分布式方面的需求。
Redis在3.0版本之前分布式方案一般有两种:
现在官方为我们提供了专有的集群方案: Redis Cluster,它非常优雅地解决了Redis集群方面的问题。
2、数据分布理论
分区方式 | 特点 | 代表产品 |
---|---|---|
哈希分区 | - 离散度好 - 数据分布业务无关 - 无法顺序访问 |
Redis Cluster Cassandra Dynamo |
顺序访问 | - 离散度易倾斜 - 数据分布业务相关 - 可顺序访问 |
Bigtable HBase Hypertable |
常见的哈希分区规则有几种:
1)节点取余分区
2)一致性哈希分区
3)虚拟槽分区
3、Redis数据分区
数据分区是分布式存储的核心。
Redis Cluser采用虚拟槽分区,所有的键根据哈希函数映射到0~16383整数槽内,计算公式:slot=CRC16(key)&16383。每一个节点负责维护一部分槽以及槽所映射的键值数据。
Redis虚拟槽分区的特点:
4、集群功能限制
Redis集群相对单机在功能上存在一些限制,限制如下:
5、搭建集群
搭建集群工作需要以下三个步骤:
6、搭建集群步骤一:准备节点
集群相关配置如下,其他配置和单机模式一致即可,配置文件命名规则redis-{port}.conf
#节点端口
port 6379
# 开启集群模式
cluster enabled yes
# 节点超时时间,单位毫秒
cluster-node-timeout 15000
# 集群内部配置文件
cluster config file "nodes 6379.conf"
#cat data/nodes-6379.conf
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 co vars currentEpoch 0 lastVoteEpoch 0
127.0.0.1:6380> cluster nodes // 每个节点目前只能识别出自己的节点信息(要通过节点握手才能建立联系)。
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 myself,master - 0 0 0 co
7、搭建集群步骤二:节点握手
127.0.0.1:6379> set hello redis
(error) CLUSTERDOWN The cluster is down
127.0.0.1:6379> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
8、搭建集群步骤三:分配槽
// 利用bash特性批量设置槽(slots),命令如下:
redis-cli -h 127.0.0.1 p 6379 cluster addslots {0 . . .5461}
redis-cli -h 127.0.0.1 -p 6380 cluster addslots {5462 . . .10922}
redis-cli -h 127.0.0.1 -p 6381 cluster addslots {10923 . . .16383}
// 执行cluster info查看集群状态
127.0.0.1 :6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:4874
cluster_stats_messages_received:4726
9、用redis-trib.rb搭建集群
redis-trib.rb是采用Ruby实现的Redis集群管理工具。内部通过Cluster相关命令帮我们简化集群创建、检查、槽迁移和均衡等常见运维操作,使用之前需要安装Ruby依赖环境。
1)Ruby环境准备
1、安装Ruby:
-- 下载ruby
wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
-- 安装ruby
tar xvf ruby-2.3.1.tar.gz
./configure -prefix=/usr/local/ruby
make
make install
cd /usr/local/ruby
sudo cp bin/ruby /usr/local/bin
sudo cp bin/gem /usr/local/bin
2、安装rubygem redis依赖:
wget http://rubygems.org/downloads/redis-3.3.0.gem
gem install -l redis-3.3.0.gem
gem list --check redis gem
3、安装redis-trib.rb:
sudo cp /{redis_home}/src/redis-trib.rb /usr/local/bin
4、执行redis-trib.rb命令确认环境是否正确:
# redis-trib.rb
Usage: redis-trib
create host1:port1 . . . hostN:portN
--replicas
check host:port
info host:port
fix host:port
--timeout
reshard host:port
--from
--to
--slots
--yes
--timeout
--pipeline
. . .忽略 . . .
2)准备节点
// 准备好节点配置并启动:
redis-server conf/redis-6481.conf
redis-server conf/redis-6482.conf
redis-server conf/redis-6483.conf
redis-server conf/redis-6484.conf
redis-server conf/redis-6485.conf
redis-server conf/redis-6486.conf
3)创建集群
// 使用redis-trib.rb create命令完成节点握手和槽分配过程,命令如下:
redis-trib.rb create --replicas 1 127.0.0.1:6481 127.0.0.1:6482 127.0.0.1:6483 127.0.0.1:6484 127.0.0.1:6485 127.0.0.1:6486
4)集群完整性检查
redis-trib.rb check 127.0.0.1:6481
10、节点通信流程
11、Gossip消息
12、节点选择
1)选择发送消息的节点数量
2)消息数据量
13、集群伸缩原理
14、扩容集群
1)准备新节点
redis-server conf/redis-6385.conf
redis-server conf/redis-6386.conf
2)加入集群
127.0.0.1:6379> cluster meet 127.0.0.1 6385
127.0.0.1:6379> cluster meet 127.0.0.1 6386
redis-trib.rb add-node new_host:new_port existing_host:existing_port --slave --master-id
redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379
redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6379
3)迁移槽和数据
根据以上迁移数据流程,手动使用命令把源节点6379负责的槽4096迁移到目标节点6385中,流程如下:
1、目标节点准备导入槽4096数据:
127.0.0.1:6385> cluster setslot 4096 importing cfb28ef1deee4e0fa78da86abe5d24566
OK
确认槽4096导入状态开启:
127.0.0.1:6385> cluster nodes
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756 127.0.0.1:6385 myself,master - 0 0 7 co [4096 < cfb28ef1deee4e0fa78da86abe5d24566744411e]
2、源节点准备导出槽4096数据:
127.0.0.1:6379>cluster setslot 4096 migrating 1a205dd8b2819a00dd1e8b6be40a8e2abe
OK
确认槽4096导出状态开启:
127.0.0.1:6379> cluster nodes
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 co 0-5461 [4096->-1a205dd8b2819a00dd1e8b6be40a8e2abe77b756]
3、批量获取槽4096对应的键,这里我们获取到3个处于该槽的键:
127.0.0.1:6379> cluster getkeysinslot 4096 100
1) "key:test:5028"
2) "key:test:68253"
3) "key:test:79212"
确认这三个键是否存在于源节点:
127.0.0.1:6379>mget key:test:5028 key:test:68253 key:test:79212
1) "value:5028"
2) "value:68253"
3) "value:79212"
批量迁移这3个键,migrate命令保证了每个键迁移过程的原子性:
127.0.0.1:6379> migrate 127.0.0.1 6385 "" 0 5000 keys key:test:5028 key:test:682 key:test:79212
继续查询这三个键,发现已经不在源节点中,Redis返回ASK转向错误,ASK转向负责引导客户端找到数据所在的节点:
127.0.0.1:6379> mget key:test:5028 key:test:68253 key:test:79212
(error) ASK 4096 127.0 .0.1:6385
通知所有主节点槽4096指派给目标节点6385:
127.0.0.1:6379> cluster setslot 4096 1a205dd8b2819a00dd1e8b6be40a8e2abe77b7
127.0.0.1:6380> cluster setslot 4096 1a205dd8b2819a00dd1e8b6be40a8e2abe77b7
127.0.0.1:6381> cluster setslot 4096 1a205dd8b2819a00dd1e8b6be40a8e2abe77b7
127.0.0.1:6385> cluster setslot 4096 1a205dd8b2819a00dd1e8b6be40a8e2abe77b7
确认源节点6379不再负责槽4096改为目标节点6385负责:
127.0.0.1:6379> cluster nodes
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 co
0-4095 4097-5461
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756 127.0.0.1:6385 master - 0 146971801107
connected 4096
实际操作槽迁移过程时肯定涉及大量槽并且每个槽对应非常多的键。因此redis-trib提供了槽重分片功能,命令如下:
redis-trib.rb reshard host:port --from
参数说明:
reshard命令简化了数据迁移的工作量,其内部针对每个槽的数据迁移同样使用之前的流程。
由于槽用于hash运算本身顺序没有意义,因此无须强制要求节点负责槽的顺序性。迁移之后建议使用redis-trib.rb rebalance命令检查节点之间槽的均衡性。
15、收缩集群
安全下线节点的流程说明:
1)下线迁移槽
2)忘记节点
16、请求路由——请求重定向
127.0.0.1:6379> cluster keyslot key:test:1
(integer) 5191
127.0.0.1:6379> cluster nodes
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master
1366-4095 4097-5461 12288-13652
127.0.0.1:6379> set key:test:2 value-2
(error) MOVED 9252 127.0.0.1:6380
127.0.0.1:6379> cluster keyslot key:test:2
(integer) 9252
1)计算槽
2)槽节点查找
17、请求路由——Smart客户端
1)Smart客户端原理
2)Smart客户端——JedisCluster
18、请求路由——ASK重定向
1)客户端ASK重定向流程
2)节点内部处理
19、故障转移之故障发现
20、故障转移之故障恢复
21、故障转移之故障转移时间
failover-time (毫秒) ≤ cluster-node-timeout + cluster-node-timeout/2 + 1000
22、集群运维——集群完整性
23、集群运维——带宽消耗
24、集群运维——Pub/Sub广播问题
25、集群运维——集群倾斜
1)数据倾斜
2)请求倾斜
26、集群运维——集群读写分离
1)只读连接
2)读写分离
27、集群运维——手动故障转移
28、集群运维——数据迁移
redis-trib .rb import host :port --from --copy --replace