利用chatgpt解决单主机多实例模式Redis主从配置的报错问题:Error condition on socket for SYNC: Connection refused
今天在配置redis主从配置时,从实例报错:Error condition on socket for SYNC: Connection refused
我是在单体机上配置三个实例,实现redis的一主二从。
1.首先,创建三个文件夹,名字分别叫7001、7002、7003(我喜欢将应用安装在tmp下)
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003
2.拷贝配置文件到每个实例目录
然后将redis-6.2.4/redis.conf文件拷贝到三个目录中(在/tmp目录执行下列命令,其中redis-6.2.4是原redis的目录):
# 方式一:逐个拷贝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
# 方式二:管道组合命令,一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf
3.修改每个实例的端口、工作目录
修改每个文件夹内的配置文件,将端口分别修改为7001、7002、7003,将rdb文件保存位置都修改为自己所在目录(在/tmp目录执行下列命令):
sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf
4.修改每个实例的声明IP(其实这步只是为了好区分,不是必要的操作,不配也没关系)
虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息,格式如下:
# redis实例的声明 IP
replica-announce-ip 192.168.137.11
每个目录都要改,我们一键完成修改(在/tmp目录执行下列命令):
# 逐一执行
sed -i '1a replica-announce-ip 192.168.150.101' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7003/redis.conf
# 或者一键修改
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf
5.启动
为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:(cd到/tmp下执行)
# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf
如果要一键停止,可以运行下面命令:
printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown
6.
现在三个实例还没有任何关系,要配置主从可以使用replicaof 或者slaveof(5.0以前)命令。
有临时和永久两种模式:
-
修改配置文件(永久生效)
-
在redis.conf中添加一行配置:
slaveof <masterip> <masterport>
-
-
使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
slaveof <masterip> <masterport>
注意
这里我们为了演示方便,使用方式二。新建一个终端(为了不影响三个redis节点的运行以及更方便看演示效果)。
通过redis-cli命令连接7002,执行下面命令:
# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.137.11 7001
上面这个命令代表的就是客户端连接到7002节点,将它的主节点设置为7001,7002就是从节点。
但是执行这步,查看7002控制台,报错了:
出现了错误:Error condition on socket for SYNC: Connection refused,找了很久没发现原因,还以为是要把集群打开,cluster-enable哪个改为yes,打开后其实就不能主从复制了,redis会报错。问题还是没找到,网上搜索一大堆也没有解决,后面我就问chatgpt,它帮我解决了主从复制的问题,它是这么说的:
按照它说的,我找到主节点的redis.conf文件,将127.0.0.1改为了我主机的ip192.168.137.11(这里要严格区分前者是回环地址,后者是局域网本机ip地址)。
再按照上面设置主从配置,发现可以了:主节点7001提示 主从模式开启,从节点7002请求同步。
同时从节点7002控制台也不报错了,成功连接到了7001:
接下来我再按照同样的方法设置7003为从节点,一样没问题。这个问题就这样解决了。
我想继续执行命令,看看主节点的replication信息:
本想执行命令:info replication,我用redis客户端登录上主节点的redis控制台,直接就报错了:
连接被拒绝,说明把 bind 127.0.0.1 -::1替换为 bind 192.168.137.11 -::1 满足了主从复制连接的问题,但本地登录连接又被拒绝了。
接着我想我把两个都配上总可以了吧,发现还是一样的情况:主从复制连接可以,本地连接不行。后来我又接着问为什么两个配置还不行,chatgpt刚开始回答是可以的:
后面我说这还是不行啊,它继续帮我找答案,而且正确了。
但是它在后面还加了一句:
我按照它说的两个都配了,发现主从复制又不可以了,于是我就问它怎么回事,怎么两者不可兼得呢。于是我有点不相信它了,我开始在网上找答案:
找到这个:bind 127.0.0.1
修改为:bind 0.0.0.0,这不是chatgpt告诉我的吗,只不过它多加了一步(它要我把两个绑定都加上了),于是我按照网上找的修改:
bind 0.0.0.0替换为bind 127.0.0.1,发现可以了,满足主从复制的同时本地登录也没问题了。想了下我明白了:
1.其实0.0.0.0是放开所有的ip,本地回环可以访问,外部网络ip也可以访问(只要确保网络通就行),但是这种方式是不安全的,生产上肯定不可以这样做。
2.另外bind这个命令不是集合,而是覆盖的,你执行了两次就代表最后这次会生效,比如我按照chatgpt提供给我的方案,加上bind 0.0.0.0,又加上了bind 127.0.0.1,
这种情况实际上代表bind 127.0.0.1生效了,前面的绑定其实是被覆盖的。所以就会出现主从复制又不行了。其实仔细看下redis.conf文件是有注释说明配置方式的:
如果配置多个就是直接在后面空格再加ip就可以了。
不过直得说明的是,chatgpt并没有真正能智能到意识到这种问题,说明它只能给直接的回答,但再深度思考上面还欠缺,比如如果它能够直接想到是不是bind多个被覆盖了,直接给我这些答案那就真的太厉害了。后来我接着问题如果生产上这样配置可以吗,它的提示是:
回答的特别好。我接着问如果我非要配置呢?它回答:
回答的相当好了,直接给出了生产上比较规范的配置了。于是我联想到我是不是还可以这样配置,按照它给的,我配置成了这样:
这样就既满足了安全,又满足本地回环访问,同时还满足主从复制连接了。
对于本地回环地址和本机ip地址我也有疑惑,一般很多人会以为就是同一个地址,其实有很大区别的,我再问chatgpt,它回答:
看它的回答也是相当的好,接着我还是觉得不够具体,我再让它举个例子对比下:
这一段简直回答的太好了。利用chatgpt今天解决了redis主从复制连接的问题,也明白了回环地址和本地ip地址的区别了。chatgpt真的太厉害了。