问题是这样的,为了进一步学习redis集群相关知识,我决定在自己的centos(虚拟机)上开启多个redis-server,并将其作为redis集群来使用。暂不考虑在多个虚拟机上开启redis-server的情况,我决定在一台虚拟机上复制多个redis 的文件夹,分别在不同的端口开启。具体配置如下
按照官网给出的步骤安装好redis以后,建立cluster文件夹,然后复制7份如下
每一个redis-i文件夹中保存了redis的副本,为了自动化的进行集群部署,我写了一个脚本clustering.bash,其内容如下:
#author: cong-1995
base=7000
ip=192.168.101.16
for var in $(ls)
do
if [ -d $var ]; then
# remove persistent file
if [ -e $var/src/*.rdb ]; then
rm $var/src/*.rdb -rf
fi
if [ -e $var/src/*.aof ]; then
rm $var/src/*.aof -rf
fi
# enable cluster
sed -i "/^cluster-enabled .*/ d" $var/redis.conf
echo 'cluster-enabled yes' >> $var/redis.conf
# change port
base=$(($base + 1))
clusterPara="${clusterPara} ${ip}:$base"
touch $var/logfile.log
sed -i "/^port/ s/[[:digit:]]\{4\}/$base/g" $var/redis.conf
sed -i "s/^pidfile .*/pidfile \/var\/run\/redis_${base}.pid/g" $var/redis.conf
sed -i "s/^logfile .*/logfile \.\/logfile.log/g" $var/redis.conf
# start redis-server
$var/src/redis-server $var/redis.conf
fi
done
# start cluster
count=0
echo "clusterParam: $clusterPara"
for var in $(ls)
do
if [ -d $var ]; then
count=$(($count + 1))
if [ $count -eq 1 ]; then
echo "var: ${var}"
$var/src/redis-cli --cluster create $clusterPara --cluster-replicas 1
fi
fi
done
注释基本上说明了我的意图,首先(为了避免之前的数据残留)我删除了所有的持久化数据rdb文件和aof文件,其实这里应该用一个命令行参数来设置一下的,不过因为第一次设置,就没管那么多。
然后添加cluster-enabled yes 配置开启cluster集群设置。
最后需要将redis.conf中的port, pidfile和logfile修改(其实base port应该由命令行参数传入的,不过这里就不计较这么多了)
修改conf文件完成后使用
$var/src/redis-server $var/redis.conf
开启每一个redis-server,最后选取第一个redis-server 执行
$var/src/redis-cli --cluster create $clusterPara --cluster-replicas 1
开启整个集群(这里设置每个master一个slave节点)
到这里看起来没有任何问题,(我知道你们要喷我修改一个redis.conf文件用了好几次sed -i,先将就着看吧,主要我一开始也没想到有这么多要改,早知道就把sed命令写到一个文件里了,以后慢慢改进吧),但是,在我美滋滋的运行这段脚本的时候,却发现报错,每次都是第二个redis-server 无法连接,也没有报任何开启redis-server 出错的提示。
百思不得其解的我只得用
ps -aux | grep redis
来查看redis集群的运行情况,结果每次都是这个样子:
只有第一个redis-server开起来了
然后我非常自然的使用
redis-2/src/redis-server redis-1/redis.conf
来试图开启2号redis-server,奇怪的是,命令执行之后没有任何反应,本着UNIX 的no news is good news 的原则,我天真的以为开启无误了。然后当我再次使用
ps aux | grep redis
查看进程信息的时候,依旧是这个样子:
然后我就蒙了,一通查日志,翻资料,花了好几个小时,就差没逆向redis-server了(开个玩笑,我要有那能耐我tm早就逍遥快活了,还在这里写填坑博客?)。
最后,在当前目录下一个ls命令之后发现,我的当前文件夹下多了几个文件
咦?有点眼熟对不对?logfile.log 不就是我在脚本中配置的log文件路径吗?
sed -i "s/^logfile .*/logfile \.\/logfile.log/g" $var/redis.conf
但是讲道理,我配置在每个redis文件夹的redis.conf文件里,还使用了./logfile.log的形式,难道不是应该和每个redis.conf相同目录嘛?
而且,这个nodes.conf,应该是每个节点的配置文件啊,为什么会跑到的cluster母文件夹下?。抱着疑问,我删除了这些奇奇怪怪的文件夹,再次执行
redis-2/src/redis-server redis-2/redis.conf
命令,终于成功开启了第二台redis-server。
并且!!,在母文件夹下又创建了这些文件。
好了,到了这里,我相信聪明的你已经找到了真凶了,现在就是见证奇迹的时刻了;
问题的来源在于,当使用形如
redis-server some-config-file
的方式开启我redis-server的时候,redis-server会读取conf文件中的配置信息。但是,配置信息中读取到的相对相对路径,是依据加载redis-server的进程的当前工作目录为参照点的,而不是redis.conf配置文件的相对参照点。
最要紧的是,如果配置文件开启了cluster 也就是cluster-enabled yes,那么redis-server进程会根据当前进程的工作路径产生节点配置文件nodes.conf,而后续在采用cluster模式开启redis-server的时候,如果发现当前进程的工作目录下有了node.conf文件的时候,什么也不会发生,没有提示,也没有新的redis-server被创建,这就导致了悲剧的产生。
所以,要修正这个错误,需要将我的clustering.bash中开启服务的一行代码改为:
cd $var && src/redis-server ./redis.conf && cd ..
进入子redis文件夹并在该文件夹调用redis-server程序,这样一来,nodes.conf和logfile.log都会被放置在子redis文件夹的根目录下,非常nice