Redis 技术内幕——Redis Cluster

Redis 在 3.0 版本中提供了 Redis Cluster (集群) 来满足分布式的需求。Redis Cluster 采用无中心结构,每个节点保存数据和整个集群的状态,每个节点都和其他所有节点连接,节点之间使用流言协议 (Gossip Protocols) 去传播信息以及发现新的节点。

Redis Cluster 的主要目的是将不同的 key 分散放置到不同的 Redis 节点。

1.分片

分片:按照某种规则去划分数据库,分散存储在多个节点上。

常见的两种分片方式是顺序分区和 Hash 分区:

说明 特点 典型产品
顺序分区 按顺序进行分区 数据分散度易倾斜,键值业务相关,可顺序访问,支持批量操作 BigTable、HBase
哈希分区 key 取 Hash 进行分区 数据分散度高,键值分布业务无关,无法顺序访问,支持批量操作 一致性哈希Memcache、Redis Cluster

Hash 分区主要有三种方式:

1、节点取余分区

客户端分片,分区位置 = hash(key) % nodes,nodes 指节点数。

存在的问题:如果扩容,约 80% 的数据会做漂移,如果是翻倍扩容,约 50% 的数据会做漂移,大量的漂移会影响系统性能,建议翻倍扩容。

2、一致性哈希分区

客户端分片,分区位置 = hash(key) % (2 的 32 次方),是对节点取余分区的一个优化,为数据做一个 Hash 环,token = 0 ~ 2 的 32 次方,然后为每一个节点分配一个 token 范围,然后根据 hash(key) % (2 的 32 次方) 值顺时针去找节点名。

一致性哈希分区

存在的问题:如果在 node1 和 node2 之间加一个 node5,node1 到 node5 之间的哈希就会落在 node5 上了,数据仍然会存在漂移,但是有一个好处是,添加节点后,不会影响 node1、node3、node4 的数据,影响范围会小很多。随着节点数量的增加,漂移影响范围也会越来越小。适合节点比较多的情况。

3、虚拟槽分区

预设虚拟槽:每个槽映射一个数据子集,一般比节点数大。

Redis Cluster 使用的分区方式,服务端分片。Redis Cluster 中有一个16384 (0~16383) 长度的虚拟槽。

分区位置 = hash(key) % 16383。

虚拟槽分配:

虚拟槽分配1
虚拟槽分配2

像节点取余分区和一致性哈希分区都有一个问题,就是添加节点之后,数据会进行漂移,存在丢数据的可能性,只能作为缓存场景来使用。而虚拟槽分区是不存在这样的问题的,因为每个槽负责的范围是固定的,加了新节点,也不会把其他节点的槽抢过去。

1.基本架构

Redis Cluster基本架构

节点:Redis Cluster 中会有多个节点,节点之间是相互通信的,且每个节点都负责读写。

meet 操作(gossip 协议):节点之间相互通信的基础。假如现在有 5 个节点,node1 节点对 node2、node3、node4、node5 节点分别发送了一个 meet 操作,node2 等节点会各自返回一个 pong 命令(表示 Redis 服务运行正常),其他节点可以自动找到,最终所有节点都可以相互通信。

分配槽:需要给节点分配虚拟槽。

节点 虚拟槽(slot)
node1 0~3276
node2 3277~6553
node3 6554~9829
node4 9830~13105
node5 13106~16383

对于客户端来说,只需要计算 slot = hash(key) %16383。

复制:为了保证高可用,每一个节点都有一个 slave 节点。

2.搭建集群

配置开启 Redis,原生命令安装和官方工具安装这一步是一样的。这里 Redis 五个节点用五个端口进行区分,分别是 7000、7001、7002、7003、7004。

Redis 节点 redis/config/redis-7000.conf 配置(redis.conf 模板文件在 redis/redis.conf,这里只给出一个节点配置,其余节点只能端口号不同):

# 关闭保护模式
protected-mode no
# 配置启动端口
port 7000
# 配置后台启动
daemonize yes
# 修改pidfile指向路径 redis-${port}.pid
pidfile /var/run/redis-7000.pid
# 日志记录方式 redis-${port}.log
logfile "redis-7000.log"
# 配置dump数据存放目录
dir "/opt/soft/redis/data/"
# 配置dump数据文件名 redis-${port}.rdb
dbfilename dump-7000.rdb
# 开启集群模式
cluster-enabled yes
# cluster节点超时时间,毫秒
cluster-node-timeout 15000
# cluster配置文件
cluster-config-file "nodes-7000.conf"
# 是否需要集群内所有节点都能提供服务才认为集群是正确的,默认yes
cluster-require-full-coverage no

启动命令:

# redis-server redis-7000.conf

继续操作,分别启动剩余 7001、7002、7003、7004 端口的节点。此时各个节点没有进行任何通信,各自都是孤立的。

1.原生命令安装(理解架构)

首先进行 meet 操作(gossip 协议):

# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 -p 7001   //在 7000 上执行命令,7000 端口的 redis 节点 meet 7001端口的 redis 节点
# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 -p 7002
# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 -p 7003
# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 -p 7004

然后分配槽:

# redis-cli -h 127.0.0.1 -p 7000 cluster addslots {0...3276}   //在 7000 上执行命令
# redis-cli -h 127.0.0.1 -p 7001 cluster addslots {3277...6553}
# redis-cli -h 127.0.0.1 -p 7002 cluster addslots {6554...9829}
# redis-cli -h 127.0.0.1 -p 7003 cluster addslots {9830...13105}
# redis-cli -h 127.0.0.1 -p 7004 cluster addslots {13106...16383}

这样所有槽分配之后,集群就算基本建立完成了。

最后需要设置主从(只有有了主从关系后,才可以实现故障自动转移):

# redis-cli -h 127.0.0.1 -p 8000 cluster replicate ${node-id-7000}   //在 8000 上执行命令

node-id 是指集群的一个节点 id,在集群启动的时候就会进行分配,需要注意的是,这里的 node-id 非单机节点的 runid,runid 重启会重置,node-id 重启不会重置。

2.官方工具安装(生产推荐)

Redis Cluster 官方提供了 Ruby 的安装脚本,相比于原生命令安装要容易很多。

Linux 上安装 Ruby 环境:

# wget -P /usr/local http://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.gz
# cd /usr/local
# tar -zxvf ruby-2.6.3.tar.gz                   //解压缩
# cd ruby-2.6.3
# ./configure -prefix=/usr/local/ruby                       //配置
# make
# make install                                 //安装
# cd /usr/local/ruby
# cp bin/ruby /usr/local/bin
# cp bin/gem /usr/local/bin

安装 Ruby Redis 客户端:

# wget -P /usr/local http://rubygems.org/downloads/redis-4.1.2.gem
# cd /usr/local
# gem install -l redis-4.1.2.gem   //安装rubygem redis
# gem list --check redis gem
# cp /usr/local/redis/src/redis-trib.rb /usr/local/bin   //安装redis-trib.rb

redis-trib 安装 Redis Cluster:

一键开启:

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:8000 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004

这个命令表示创建集群,–replicas 1 表示每个主节点配备一个从节点,前五个 7000 到 7004 的端口表示主节点,后五个 8000 到 8004 的端口表示从节点,7000 对应 8000,7001 对应 8001,以此类推。

相比原生命令安装,官方工具安装更高效、准确,生成环境可使用。

4.集群伸缩

1.伸缩原理

一个 node1、node2、node3 组成的集群,加入 node4 的过程,其实就是槽和数据在节点之间的移动。

Redis Cluster伸缩原理

2.扩容集群

127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 组成的集群,加入 127.0.0.1:7003。

1.原生命令安装(理解架构)

1、准备新节点

需要新节点是集群模式(cluster-enabled yes),配置需要和其他节点统一,然后启动改节点。

2、加入集群

通过 meet 操作(gossip 协议)来完成的:

# redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 -p 7003   //在 7000 上执行命令,7000 端口的 redis 节点 meet 7003端口的 redis 节点
# redis-cli -h 127.0.0.1 -p 7000 cluster nodes   //加入集群,观察集群配置

3、迁移槽和数据

首先进行槽迁移计划,平均槽数据,计算每个节点应该迁移到新节点的槽的数量。

然后迁移数据,迁移数据的过程是比较复杂的:

1)对目标节点发送 cluster setslot {slot} importing {sourceNodeId} 命令,让目标节点准备导入槽数据;
2)对源节点发送 cluster setslot {slot} migrating {targetNodeId} 命令,让源节点准备迁出槽的数据;
3)源节点循环执行 cluster getkeysinslot {slot} {count} 命令,每次获取 count 个属于槽的键;
4)在源节点上执行 migrate {targetIp} {targetPort} key 0 {timeout} 命令把指定 key 迁移;
5)重复执行 3~4 直到槽下所有的键数据迁移到模板节点;
6)向集群内所有 master 节点发送 cluster setslot {slot} node {targetNodeId} 命令,通知槽分配给目标节点。

迁移数据的完整流程图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值