1.1redis-cluster架构图
架构细节
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
1.2 redis--cluster
(1)领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
(2):什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.
b:如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态.
ps:当集群不可用时,所有对集群的操作做都不可用,收到((error)CLUSTERDOWN Thecluster is down)错误。
2.redis集群安装
线上的统一聊天和推送项目使用的是Redis主从,redis版本3.0
redis主从和MySQL主从目的差不多,但redis主从配置很简单,主要在从节点配置文件指定主节点ip和端口:slaveof 120.77.213.193 6379,然后启动主从,主从就搭建好了redis主从中如果主节点发生故障,不会自动切换,需要借助redis的Sentinel或者keepalive来实现主的故障转移
redis集群是一个无中心的分布式redis存储架构,可以在多个节点之间进行数据共享,解决了redis高可用、可扩展等问题,redis集群提供了以下两个好处
(1)、将数据自动切分(split)到多个节点
(2)、当集群中的某一个节点故障时,redis还可以继续处理客户端的请求。
一个 Redis 集群包含 16384 个哈希槽(hash slot),数据库中的每个数据都属于这16384个哈希槽中的一个。集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽。集群中的每一个节点负责处理一部分哈希槽。
集群中的主从复制
集群中的每个节点都有1个至N个复制品,其中一个为主节点,其余的为从节点,如果主节点下线了,集群就会把这个主节点的一个从节点设置为新的主节点,继续工作。这样集群就不会因为一个主节点的下线而无法正常工作
下面开始搭建redis集群
因为redis-cluster要求最少6个节点(maseter*3 + slave*3)主 附
1.安装ruby与相关组件:
查看服务器是否安装ruby:
yum list | grep ruby
rpm -qa | grep ruby
若没有安装,则安装组件:
yum install ruby
然后输入y则安装成功
安装gem相关:
yum install rubygems
gem install redis
这里可能无法安装,因为无法连接gem服务器:
[@zw_22_90 src]# gem install redis --version 3.0.0
ERROR: Could not find a valid gem 'redis' (= 3.0.0) in any repository
ERROR: While executing gem ... (Gem::RemoteFetcher::FetchError)
需要手工下载并安装:
wget https://rubygems.global.ssl.fastly.net/gems/redis-3.2.1.gem
gem install -l ./redis-3.2.1.gem
2. 安装redis
redis 6个节点的ip和端口对应关系
120.77.213.193:7001
120.77.213.193:7002
120.77.213.193:7003
120.77.213.193:7004
120.77.213.193:7005
120.77.213.193:7006
[root@iZwz91nfqrmmcjz3ax4vqvZ ~]# cd /usr/java
[root@iZwz91nfqrmmcjz3ax4vqvZ java]# mkdir redis-cluster
[root@iZwz91nfqrmmcjz3ax4vqvZ java]# cd redis-cluster
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# wget http://download.redis.io/releases/redis-3.0.6.tar.gz
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# tar -zxvf redis-3.0.6.tar.gz
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# mkdir redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# mkdir redis7002
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# mkdir redis7003
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# mkdir redis7004
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# mkdir redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# mkdir redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cd redis-3.0.6
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-3.0.6]#make 编译
3、修改配置文件redis.conf
拷贝/redis-3.0.6/src目录下的3个文件:
redis-server redis-cli redis-benchmark到redis-3.0.6目录
复制redis-3.0.6的文件到7001个redis文件夹下,执行命令:
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis-3.0.6/* redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cd redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# vi redis.conf
修改配置文件
daemonize yes //redis后台运行
port 7001 //端口10000
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_10000.conf //集群的配置 配置文件首次启动自动生成
cluster-node-timeout 5000 //请求超时 设置5秒够了
appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis7001/* redis7002
//请求超时 设置5秒够了
appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis7001/* redis7002
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis7001/* redis7003
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis7001/* redis7004
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis7001/* redis7005
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cp -Rf redis7001/* redis7006
拷贝完成之后要分别修改7002/7003/7004/7005/7006目录下面redis.conf文件中的port参数
4 分别进入6个文件,启动6个redis实例
redis-server redis.conf
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cd redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# ./redis-server ./redis.conf
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# cd ../redis7002
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7002]# ./redis-server ./redis.conf
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7002]# cd ../redis7003
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7003]# ./redis-server ./redis.conf
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7003]# cd ../redis7004
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7004]# ./redis-server ./redis.conf
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7004]# cd ../redis7005
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7005]# ./redis-server ./redis.conf
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7005]# cd ../redis7006
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7006]# ./redis-server ./redis.conf
启动完成后:
执行ps -ef|grep redis可看到如下:
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# ps -ef|grep redis
root 5478 1 0 14:24 ? 00:00:00 ./redis-server *:7001 [cluster]
root 5485 1 0 14:24 ? 00:00:00 ./redis-server *:7002 [cluster]
root 5489 1 0 14:24 ? 00:00:00 ./redis-server *:7003 [cluster]
root 5493 1 0 14:24 ? 00:00:00 ./redis-server *:7004 [cluster]
root 5497 1 0 14:24 ? 00:00:00 ./redis-server *:7005 [cluster]
root 5502 1 0 14:24 ? 00:00:00 ./redis-server *:7006 [cluster]
root 5512 4934 0 14:26 pts/1 00:00:00 grep --color=auto redis
5.执行redis的创建集群命令创建集群(注意ip地址和端口号)
将src文件夹下的redis-trib.rb文件拷贝到redis-cluster目录下,执行命令:
./redis-trib.rb create --replicas 1 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 127.0.0.1:7006
提示是否允许修改配置文件,输入yes----即可启动redis集群
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# ./redis-trib.rb create --replicas 1 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 127.0.0.1:7006
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7001
127.0.0.1:7002
127.0.0.1:7003
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
Adding replica 127.0.0.1:7006 to 127.0.0.1:7003
M: c60d1642a36bb253364daa244b1e1e868606c4a6 127.0.0.1:7001
slots:0-5460 (5461 slots) master
M: 63eedc9839436f369be521e724d59822a7291841 127.0.0.1:7002
slots:5461-10922 (5462 slots) master
M: 312cbfb3f8f7613587b923eb091b43510942898e 127.0.0.1:7003
slots:10923-16383 (5461 slots) master
S: f7fde42093d0cd2797a55d4712667f19811c5237 127.0.0.1:7004
replicates c60d1642a36bb253364daa244b1e1e868606c4a6
S: 2e7ba20edd2012eb861ad9c6cc4402ffb1bbc68a 127.0.0.1:7005
replicates 63eedc9839436f369be521e724d59822a7291841
S: d3173bad6d9564470ea98f69d7552cd666c44d60 127.0.0.1:7006
replicates 312cbfb3f8f7613587b923eb091b43510942898e
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:7001)
M: c60d1642a36bb253364daa244b1e1e868606c4a6 127.0.0.1:7001
slots:0-5460 (5461 slots) master
M: 63eedc9839436f369be521e724d59822a7291841 127.0.0.1:7002
slots:5461-10922 (5462 slots) master
M: 312cbfb3f8f7613587b923eb091b43510942898e 127.0.0.1:7003
slots:10923-16383 (5461 slots) master
M: f7fde42093d0cd2797a55d4712667f19811c5237 127.0.0.1:7004
slots: (0 slots) master
replicates c60d1642a36bb253364daa244b1e1e868606c4a6
M: 2e7ba20edd2012eb861ad9c6cc4402ffb1bbc68a 127.0.0.1:7005
slots: (0 slots) master
replicates 63eedc9839436f369be521e724d59822a7291841
M: d3173bad6d9564470ea98f69d7552cd666c44d60 127.0.0.1:7006
slots: (0 slots) master
replicates 312cbfb3f8f7613587b923eb091b43510942898e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
这样就可以登录客户端查看集群状况:
进入redis7001
执行:
./redis-cli -c -p 7001则进入客户端.
测试
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cd redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# ./redis-cli -c -p 7001
127.0.0.1:7001> get key
-> Redirected to slot [12539] located at 127.0.0.1:7003
(nil)
127.0.0.1:7003> set name test
-> Redirected to slot [5798] located at 127.0.0.1:7002
OK
127.0.0.1:7002> set adress lye
-> Redirected to slot [1562] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get key
-> Redirected to slot [12539] located at 127.0.0.1:7003
(nil)
127.0.0.1:7003> set key val
OK
127.0.0.1:7003> get key
"val"
127.0.0.1:7003> set key2 val2
-> Redirected to slot [4998] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get key2
"val2"
查询所有的key
keys *
集群状态查看:
cluster nodes
cluster info
6.设置密码
注意事项:
1.如果是使用redis-trib.rb工具构建集群,集群构建完成前不要配置密码,集群构建完毕再通过config set + config rewrite命令逐个机器设置密码
2.如果对集群设置密码,那么requirepass和masterauth都需要设置,否则发生主从切换时,就会遇到授权问题,可以模拟并观察日志
3.各个节点的密码都必须一致,否则Redirected就会失败
方法一:
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# vi redis.conf
masterauth
requirepass abc
默认前面存在#号的,修改密码需要把#删除
修改完重启
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# ./redis-server ./redis.conf&
方法二:
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# ./redis-cli -c -p 7001
127.0.0.1:7001> config set masterauth abc
OK
127.0.0.1:7001> config set requirepass abc
OK
127.0.0.1:7001> config rewrite
测试:
[root@iZwz91nfqrmmcjz3ax4vqvZ redis-cluster]# cd redis7001
[root@iZwz91nfqrmmcjz3ax4vqvZ redis7001]# ./redis-cli -c -p 7001
127.0.0.1:7001> cluster nodes
NOAUTH Authentication required. #因为设置了密码,所以如何操作需要输入密码验证
127.0.0.1:7001> auth "abc" #这里输入设置密码
OK
127.0.0.1:7001> cluster nodes
d3173bad6d9564470ea98f69d7552cd666c44d60 127.0.0.1:7006 slave 312cbfb3f8f7613587b923eb091b43510942898e 0 1483519617809 6 connected
2e7ba20edd2012eb861ad9c6cc4402ffb1bbc68a 127.0.0.1:7005 slave 63eedc9839436f369be521e724d59822a7291841 0 1483519618809 5 connected
63eedc9839436f369be521e724d59822a7291841 127.0.0.1:7002 master - 0 1483519621815 2 connected 5461-10922
c60d1642a36bb253364daa244b1e1e868606c4a6 127.0.0.1:7001 myself,master - 0 0 1 connected 0-5460
312cbfb3f8f7613587b923eb091b43510942898e 127.0.0.1:7003 master - 0 1483519619811 3 connected 10923-16383
f7fde42093d0cd2797a55d4712667f19811c5237 127.0.0.1:7004 slave c60d1642a36bb253364daa244b1e1e868606c4a6 0 1483519620814 4 connected
127.0.0.1:7001>
今天补充一下一个异常,当你Redis Cluster 集群在集群一次,比如IP地址要变化或者什么的,你再次集群的时候你会发现一个异常:
Node 127.0.0.1:10001 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
这个时候你需要把开始生成的nodes_*.conf
、appendonly.aof
、dump.rdb
文件删除,再次集群就可以了。
这里是设置的是某一个redis开机启动,没有使用集群,这里设置的是7001
1. 根据启动脚本要求,将修改好的配置文件以端口为名复制一份到指定目录。需使用root用户
mkdir /etc/redis
cp redis.conf /etc/redis/7001.conf
修改7001.conf文件
daemonize no 改为 daemonize yes
pidfile /var/run/redis.pid 改为 pidfile /var/run/redis_7001.pid
2. 将启动脚本复制到/etc/init.d目录下,本例将启动脚本命名为redis。
cp utils/redis_init_script /etc/init.d/redis
编辑redis,插入下面2行注释
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
# chkconfig: 2345 80 90
# description: Redis is a persistent key-value database
# chkconfig: 2345 80 90
# description: Redis is a persistent key-value database
完整配置为
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
# chkconfig: 2345 80 90
# description: Redis is a persistent key-value database
REDISPORT=7001
EXEC=/usr/java/redis-cluster/redis7001/redis-server
CLIEXEC=/usr/java/redis-cluster/redis7001/redis-cli
PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"
case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF &
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
*)
echo "Please use start or stop as first argument"
;;
esac
#注册为服务
chkconfig --add redis
#设置为开机自启动服务器
chkconfig redis on
#打开服务
service redis start
#关闭服务
service redis stop