Redis-cluster原理
Redis 是一个开源的 key-value 存储系统,由于出众的性能,大部分互联网企业都用来做服务器端缓存。Redis 在3.0版本前只支持单实例模式,虽然支持主从模式、哨兵模式部署来解决单点故障,但是现在互联网企业动辄大几百G的数据,可完全是没法满足业务的需求,所以,Redis 在 3.0 版本以后就推出了集群模式。
Redis 集群采用了P2P的模式,完全去中心化。Redis 把所有的 Key 分成了 16384 个 slot,每个 Redis 实例负责其中一部分 slot 。集群中的
所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新。
Redis 客户端可以在任意一个 Redis 实例发出请求,如果所需数据不在该实例中,通过重定向命令引导客户端访问所需的实例。
在这个图中,每一个蓝色的圈都代表着一个redis的服务器节点。它们任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。
那么redis是怎么做到的呢?首先,在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量这个变量的取值范围是:0-16383。还有一个就是cluster我个人把这个cluster理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
还有就是因为如果集群的话,是有好多个redis一起工作的,那么,就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务。这个备用的redis称为从节点(slave)。那么这个集群是如何判断是否有某个节点挂掉了呢?
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。
它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入faill状态。还有就是如果有一半以上的主节点宕机,那么我们集群同样进入发力了状态。这就是我们的redis的投票机制,具体原理如下图所示:
这套架构的特点:
分片算法:基于 slot hash桶;
分片实例之间相互独立,每组 一个master 实例和多个slave;
路由信息存放到第三方存储组件,如 zookeeper 或etcd
旁路组件探活
搭建集群方案
下面说一下 Redis 集群搭建规划,由于集群至少需要6个节点(3主3从模式),实力不允许,所以老规矩伪集群。
我们计划集群中 Redis 节点的端口号为 9001-9006 ,端口号即集群下各实例文件夹。数据存放在 端口号/data 文件夹中。
mkdir /usr/local/redis-cluster
cd /usr/local/redis-cluster
mkdir -p 9001/data
mkdir -p 9002/data
mkdir -p 9003/data
mkdir -p 9004/data
mkdir -p 9005/data
mkdir -p 9006/data
我们之前的文章已经编译安装了redis,安装目录在/usr/local/redis
在 /usr/local/redis-cluster 下创建 bin 文件夹,用来存放集群运行脚本,并把安装好的 Redis 的 src 路径下的运行脚本拷贝过来。
我们现在从已安装好的 Redis 中复制一个新的实例到 9001 文件夹,并修改 redis.conf 配置。(需要注意的是这里不要设置密码,已经设置的注释掉,否则创建集群的时候会报错)。
cp -r /usr/local/redis /usr/local/redis-cluster/9001
#注意,修改 redis.conf 配置和单点唯一区别是下图部分,其余还是常规的这几项:
port 9001(每个节点的端口号)
#后台启动
daemonize yes
bind 192.168.1.48(绑定当前机器 IP)
dir /usr/local/redis-cluster/9001/data/(数据文件存放位置)
pidfile /var/run/redis_9001.pid(pid 9001和port要对应)
cluster-enabled yes(启动集群模式)
cluster-config-file nodes-9001.conf(9001和port要对应)
cluster-node-timeout 15000
#AOF持久化
appendonly yes
我们已经完成了一个节点了,其实接下来就是机械化的再完成另外五个节点,其实可以这么做:把 9001 实例 复制到另外五个文件夹中,唯一要修改的就是 redis.conf 中的所有和端口的相关的信息即可,开始操作
\cp -rf /usr/local/redis-cluster/9001/* /usr/local/redis-cluster/9002
\cp -rf /usr/local/redis-cluster/9001/* /usr/local/redis-cluster/9003
\cp -rf /usr/local/redis-cluster/9001/* /usr/local/redis-cluster/9004
\cp -rf /usr/local/redis-cluster/9001/* /usr/local/redis-cluster/9005
\cp -rf /usr/local/redis-cluster/9001/* /usr/local/redis-cluster/9006
\cp -rf 命令是不使用别名来复制,因为 cp 其实是别名 cp -i,操作时会有交互式确认,比较烦人。
修改 9002-9006 的 redis.conf 文件
vi /usr/local/redis-cluster/9002/redis/etc/redis.conf
vi /usr/local/redis-cluster/9003/redis/etc/redis.conf
vi /usr/local/redis-cluster/9004/redis/etc/redis.conf
vi /usr/local/redis-cluster/9005/redis/etc/redis.conf
vi /usr/local/redis-cluster/9006/redis/etc/redis.conf
%s/9001/9002
%s/9001/9003
%s/9001/9004
%s/9001/9005
%s/9001/9006
其实我们也就是替换了下面这四行:
port 9002
dir /usr/local/redis-cluster/9002/data/
cluster-config-file nodes-9002.conf
pidfile /var/run/redis_9002.pid
这里有个小技巧替换,不懂得可以去百度谷歌。
启动9001-9006六个节点
/usr/local/redis-cluster/9001/redis/bin/redis-server /usr/local/redis-cluster/9001/redis/etc/redis.conf
/usr/local/redis-cluster/9002/redis/bin/redis-server /usr/local/redis-cluster/9002/redis/etc/redis.conf
/usr/local/redis-cluster/9003/redis/bin/redis-server /usr/local/redis-cluster/9003/redis/etc/redis.conf
/usr/local/redis-cluster/9004/redis/bin/redis-server /usr/local/redis-cluster/9004/redis/etc/redis.conf
/usr/local/redis-cluster/9005/redis/bin/redis-server /usr/local/redis-cluster/9005/redis/etc/redis.conf
/usr/local/redis-cluster/9006/redis/bin/redis-server /usr/local/redis-cluster/9006/redis/etc/redis.conf
随便找一个节点测试试
/usr/local/redis-cluster/9001/redis/bin/redis-cli -h 192.168.1.48 -p 9001
这是因为虽然我们配置并启动了 Redis 集群服务,但是他们暂时还并不在一个集群中,互相直接发现不了,而且还没有可存储的位置,就是所谓的slot(槽)。
安装集群所需软件,其中gem install redis 执行失败,在这我们为了方便不去解决这个问题了,直接采用本地上传的方式完成。
yum install ruby
yum install rubygems
#使用本地上传方式
gem install redis
本地安装
下载地址:https://rubygems.org/gems/redis/versions
gem install -l redis-3.2.1.gem
启动集群环境
/usr/local/redis-cluster/bin/redis-trib.rb create --replicas 1 192.168.1.48:9001 192.168.1.48:9002 192.168.1.48:9003 192.168.1.48:9004 192.168.1.48:9005 192.168.1.48:9006
简单解释一下这个命令:调用 ruby 命令来进行创建集群,--replicas 1 表示主从复制比例为 1:1,即一个主节点对应一个从节点;然后,默认给我们分配好了每个主节点和对应从节点服务,以及 solt 的大小,因为在 Redis 集群中有且仅有 16383 个 solt ,默认情况会给我们平均分配,当然你可以指定,后续的增减节点也可以重新分配。
目前来看,9001-9003 为主节点,9004-9006 为从节点,并向你确认是否同意这么配置。输入 yes 后,会开始集群创建。
验证集群环境
依然是通过客户端命令连接上,通过集群命令看一下状态和节点信息等。
/usr/local/redis-cluster/9001/redis/bin/redis-cli -h 192.168.1.48 -p 9001
/usr/local/redis-cluster/9002/redis/bin/redis-cli -h 192.168.1.48 -p 9002
what?发现获取不到值什么鬼?
莫慌,因为集群这是默认以单机连接的,集群要加上 -c
/usr/local/redis-cluster/9001/redis/bin/redis-cli -h 192.168.1.48 -p 9001 -c
/usr/local/redis-cluster/9002/redis/bin/redis-cli -h 192.168.1.48 -p 9002 -c
到此我们的集群环境已经可以正常使用。
测试结果,开始时默认重定向到主节点,无论读写。主节点高可用实现了。读负载均衡在jedis实现。还有比较遗憾的一点就是分布式集群的redis是不支持事务的,技术永无止境,任重道远。
总结
除了步骤繁琐外,几乎不存在技术含量。
接下来可能就是动态扩容、增加节点和减少节点,重新分配槽大小等,当然,还有最重要的就是怎么和我们程序结合起来,以及如何更好的把 Redis 缓存集群发挥出应有的效果,这些才是最重要的。