一、背景
随着互联网的不断发展,用户体验要求越来越高,为了提高性能大家常常采用的方案是将我们的热点数据存储到缓存中,这样来减少服务与数据库的交互。怎样能搭建一个高可用的缓存集群也就成为了新的问题。
Redis3.0版本之前,可以通过Redis Sentinel(哨兵)来实现高可用 ( HA ),从3.0版本之后,官方推出了Redis Cluster,它的主要用途是实现数据分片(Data Sharding),不过同样可以实现HA,是官方当前推荐的方案。
在Redis Sentinel模式中,每个节点需要保存全量数据,冗余比较多,而在Redis Cluster模式中,每个分片只需要保存一部分的数据,对于内存数据库来说,还是要尽量的减少冗余。在数据量太大的情况下,故障恢复需要较长时间。
Redis Cluster的具体实现细节是采用了Hash槽的概念,集群会预先分配16384个槽,并将这些槽分配给具体的服务节点,通过对Key进行CRC16(key)%16384运算得到对应的槽是哪一个,从而将读写操作转发到该槽所对应的服务节点。当有新的节点加入或者移除的时候,再来迁移这些槽以及其对应的数据。在这种设计之下,我们就可以很方便的进行动态扩容或缩容。
二、搭建集群
1)创建目录/usr/local/redis
2)下载redis安装文件,官网https://redis.io/download,当前最新版本5.0.3
wget http://download.redis.io/releases/redis-5.0.3.tar.gz
3)解压、安装
tar xf redis-5.0.3.tar.gz
cd redis-5.0.3
make && make install
4)创建存放多个实例的目录
mkdir /data/cluster -p
cd /data/cluster
mkdir 7000 7001 7002 7003 7004 7005
5)复制配置文件到实例目录
cp redis.conf cluster/7000/
6)修改配置项
port 7000
daemonize yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为nodes.conf 。其他参数相信童鞋们都知道。节点配置文件无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。
修改完成后,把修改完成的redis.conf复制到7001-7005目录下,并且端口修改成和文件夹对应。
7)分别启动6个redis实例
8)检查进程是否存在
9)执行命令创建集群,首先安装依赖,否则创建集群失败。
yum install ruby rubygems -y
10)安装gem-redis,下载:https://rubygems.org/gems/redis/versions/3.0.0
gem install -l redis-3.0.0.gem ,注意支持ruby版本,gem-redis在4.0.0版本包括以及以上需要ruby版本>2.2.2
11)复制集群管理程序到/usr/local/bin
cp redis-5.0.3/src/redis-trib.rb /usr/local/bin/redis-trib
重新命名,因为一次复制没有到位。
12)创建集群
redis-cli --cluster create 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:7005 --cluster-replicas 1
命令的意义如下:
- 给定redis-cli --cluster create 程序的命令是 create , 这表示我们希望创建一个新的集群。
- 选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
- 之后跟着的其他参数则是实例的地址列表, 我们希望程序使用这些地址所指示的实例来创建新集群。
简单来说, 以上命令的意思就是让redis-cli --cluster create程序创建一个包含三个主节点和三个从节点的集群。
接着,redis-cli --cluster create会打印出一份预想中的配置给你看, 如果你觉得没问题的话, 就可以输入 yes , redis-cli --cluster createb就会将这份配置应用到集群当中:
输入 yes 并按下回车确认之后, 集群就会将配置应用到各个节点, 并连接起(join)各个节点 —— 也即是, 让各个节点开始互相通讯:
测试 Redis 集群比较简单的办法就是使用 redis-cli , 接下来我们将使用 redis-cli 为例来进行演示:
[root@centos-linux0002 bin]# redis-cli -c -p 7000
127.0.0.1:7000> set name zhangqiang
-> Redirected to slot [5798] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get name
"zhangqiang"
127.0.0.1:7001>
检查集群状态
redis-cli -p 7000 cluster nodes
可以看到7000-7002是master,7003-7005是slave。
三、新增(Node)节点
随着业务发展,数据量的不断上升。当已有的缓存系统无法满足我们的需求时,需要对已有服务器集群进行扩容。新增集群的主从节点,主节点7006,从节点7007。
redis集群的架构图可知,在整个集群新增节点的过程中涉及到一下几个步骤:建立主节点、建立从节点、槽范围移动、槽分区移动。
数据初始化
验证槽范围移动后,槽分区也同时移动,首先我们在7001实例内用set命令初始化一个Key-Value值。命令:set name zhangqiang
图中可知,name值为zhangqiang的信息被映射到5798这个槽对应的7001这个实例。
创建主节点
cluster下建立两个实例目录7006、7007。存储新增节点的实例信息。
复制实例配置文件到7006、7007下,进行实例配置,修改配置端口。
分别启动服务实例
redis-server redis.conf
ps -ef | grep redis
将7006 端口号的redis实例添加到集群之前,一定要确保这个redis实例没有存储过数据,也不能持久化的数据文件,否则在添加的时候会报错的!
执行命令“redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000”,添加节点。
我们执行在任意一个客户端下执行 redis-cli -p 7000 cluster nodes 命令,可以看到7006 已经作为主节点添加到我们的集群中了,但是可以看到他没有分配哈希槽,没有分配哈希槽的话表示就没有存储数据的能力,所以我们需要将其他节点上的哈希槽分配到这个节点上。
redis-cli -p 7000 cluster nodes
下边我们看一下如何分配哈希槽。我们随便进入一个客户端,然后我们执行 redis-cli --cluster reshard 127.0.0.1:7000, 就可以看到如下图所示提示,问我们需要移动多少个哈希槽,我们在这里移动3000个。
完以后,又会问我们需要覆盖的节点id是什么,这个id就是我们新创建的节点id。然后让我们输入源节点,如果这里我们输入all的话,他会随机的从所有的节点中抽取3000个作为新节点的哈希槽。
为了达到验证槽范围移动,槽分区也移动啦,这里我选取将端口7001的槽移动3000个到7006端口,会出下下图所示东西,表示hash槽的移动计划。
输入yes确定移动计划后,再真正执行移动。
移动完以后,我们进入客户端,执行redis-cli -p 7000 cluster nodes命令,查看集群节点的状态,我们会看到原来没有哈希槽的7006节点,分配到了3000个哈希槽,而且是连续的。
这样我们一个新的节点就添加好了, 但是我们发现总共是7个节点,其中的六个互为住备,但有一个是有主,没有备,所以我们需要在为该节点添加一个备份节点。我们在创建一个实例,端口号为7007,启动以后我们只命令redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7006 --cluster-slave,第一个实例127.0.0.1:7007为备份节点,第二个实例127.0.0.1:7006为主节点。然后我们在执行,redis-cli -p 7000 cluster nodes命令,就会发现新添加的节点已经作为7007 备份节点开始工作了!
至此,集群新增节点操作完成,那我们来验证一下,槽分区5798的数据是否已经移动到端口7006上。
由图可知,5798槽已经由实例7001移动到7006。并且对应的槽分区数据也移动到7006上了。
总结:redis cluster集群新增节点,槽范围移动的时候,槽分区(实际存放数据的地方)也会做相应的移动。
四、删除(Node)节点
删除节点也分两种,一种是主节点,一种是从节点。在从节点中,我们没有分配哈希槽,所以删除很简单,我们直接执行redis-cli --cluster del-node 127.0.0.1:7005 739228b458d6f296333bc50652f6c3ba6776be94 有两个参数ip:port 和节点的id。 我们就可以将从节点从集群中删除了。
我们现在删除7000实例下的从节点7005
而在删除主节点的时候,因为在主节点中存放着数据,所以我们在删除之前,要把这些数据迁移走,并且把该节点上的哈希槽分配到其他主节点上。
如果是主从,先删除从节点,再删除主节点。
主节点有值时,我们执行redis-cli --cluster del-node 127.0.0.1:7006 6bb5709b1dcc8d06c04a52288b8f13e2385c1059命令时,会提示以下错误,告诉我们删除的时候需要将槽给移动走。
我们执行redis-cli --cluster reshard 127.0.0.1:7006,问我们有多少个哈希槽要移走,因为我们这个节点上有3000 个所以我们这里输入3000,整个原理同新增节点一样。如下如所示:
查看当前槽的分布情况,端口7006上的槽数量为0啦。
最后删除端口7006主节点,这次删除成功。