# redis-cluster-study **Repository Path**: linestyle007/redis-cluster-study ## Basic Information - **Project Name**: redis-cluster-study - **Description**: redis-cluster-study - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-15 - **Last Updated**: 2021-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # redis-cluster-study redis主从集群 ## 部署环境 [参考网址]: https://www.cnblogs.com/javasl/p/14704755.html * 三台服务器搭载主从集群 | IP地址 | 端口 | 角色 | | :-----------: | :--: | :----------: | | 172.16.65.139 | 7000 | redis-master | | 172.16.65.139 | 7001 | redis-slave | | 172.16.65.137 | 7000 | redis-master | | 172.16.65.137 | 7001 | redis-slave | | 172.16.65.141 | 7000 | redis-master | | 172.16.65.141 | 7001 | redis-slave | | 172.16.65.142 | 7000 | redis-master | | 172.16.65.142 | 7001 | redis-slave | ## 安装redis ```scala 1.下载redis5.0.8安装包 mkdir opt cd opt wget http://download.redis.io/releases/redis-5.0.8.tar.gz 2.安装依赖 yum install -y gcc gcc-c++ make 3.解压、编译 tar -zxvf redis-5.0.8.tar.gz cd redis-5.0.8 make 4.创建Redis相关工作目录 cd ~/opt mkdir redis-cluster/{data/{redis_7000,redis_7001},conf,log} -p 5.复制redis配置文件 cd ~/opt/redis-5.0.8 cp redis.conf ~/opt/redis-cluster/conf/redis_7000.conf cp redis.conf ~/opt/redis-cluster/conf/redis_7001.conf ``` ## **修改Redis配置文件** ### redis_7000.conf * vi ~/opt/redis-cluster/conf/redis_7000.conf ```scala port 7000 #修改redis监听端口(可以自定义) bind 0.0.0.0 #表示redis允许所有地址连接。默认127.0.0.1,仅允许本地连接。 daemonize yes #允许redis后台运行 pidfile /var/run/redis_7000.pid #pid存放目录 logfile "/var/log/redis-sentinel.log" #设置Sentinel日志存放路径 dir ~/opt/redis-cluster/data/redis_7000 #工作目录 cluster-enabled yes #是否开启集群 cluster-config-file ~/opt/redis-cluster/conf/nodes_7000.conf #集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息 #这个文件并不需要手动配置,这个配置文件有Redis生成并更新, cluster-node-timeout 15000 #节点互连超时的阀值。集群节点超时毫秒数,默认15秒 appendonly yes #Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件, #每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。 requirepass 123456 #设置redis密码 masterauth 123456 #主从同步master的密码(如果没有设置redis密码,则无需配置) ``` ### redis_7001.conf * vi ~/opt/redis-cluster/conf/redis_7001.conf ```scala port 7001 bind 0.0.0.0 daemonize yes pidfile /var/run/redis-cluster/redis_7001.pid logfile "/opt/redis-cluster/log/redis_7001.log" dir /opt/redis-cluster/data/redis_7001 cluster-enabled yes cluster-config-file /opt/redis-cluster/conf/nodes_7001.conf cluster-node-timeout 15000 appendonly yes #requirepass 123456 #masterauth 123456 ``` ## **分发到集群其他服务器** ```scala # 172.16.65.137 mkdir -p opt # 172.16.65.141 mkdir -p opt # 172.16.65.139 cd opt scp -r redis-5.0.8 redis-cluster root@172.16.65.137:~/opt scp -r redis-5.0.8 redis-cluster root@172.16.65.141:~/opt scp -r redis-5.0.8 redis-cluster root@172.16.65.140:~/opt # 设置软链接 # 172.16.65.139 ln -s ~/opt/redis-5.0.8/src/redis-server /usr/bin/redis-server ln -s ~/opt/redis-5.0.8/src/redis-cli /usr/bin/redis-cli # 172.16.65.137 ln -s ~/opt/redis-5.0.8/src/redis-server /usr/bin/redis-server ln -s ~/opt/redis-5.0.8/src/redis-cli /usr/bin/redis-cli # 172.16.65.141 ln -s ~/opt/redis-5.0.8/src/redis-server /usr/bin/redis-server ln -s ~/opt/redis-5.0.8/src/redis-cli /usr/bin/redis-cli ``` ## **启动Redis** ```scala 1.启动redis-master、redis-slave # 172.16.65.139 redis-server ~/opt/redis-cluster/conf/redis_7000.conf redis-server ~/opt/redis-cluster/conf/redis_7001.conf # 172.16.65.137 redis-server ~/opt/redis-cluster/conf/redis_7000.conf redis-server ~/opt/redis-cluster/conf/redis_7001.conf # 172.16.65.141 redis-server ~/opt/redis-cluster/conf/redis_7000.conf redis-server ~/opt/redis-cluster/conf/redis_7001.conf 2.验证是否成功 ps -ef | grep redis # 查看版本 redis-cli --version redis-server --version tail -f /var/log/redis-sentinel.log ``` ## **创建Redis Cluster** * 创建顺序三主-三从 * 主-主-主-从-从-从 ```scala redis-cli -a 123456 --cluster create 172.16.65.139:7000 172.16.65.137:7000 172.16.65.141:7000 172.16.65.137:7001 172.16.65.137:7001 172.16.65.141:7001 --cluster-replicas 1 # 确认 yes ``` ## **验证集群Redis-Cluster** ### 登录redis集群 * *-a Redis密码,-c表示集群模式 ,指定IP和端口* * 注意:可能会redirected进入到其它server ```scala redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c ``` ### 验证集群信息 ```scala #查看集群信息 cluster info #查看集群节点列表 cluster nodes # 查看集群内主从关系 redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c cluster slots | xargs -n8 | awk '{print $3":"$4"->"$6":"$7}' | sort -nk2 -t ':' | uniq ``` ### 数据验证 ```scala # 插入数据 redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c 172.16.65.139:7000> set mykey "Hello Redis" 172.16.65.137:7000> get mykey # 登录其他节点查看数据 redis-cli -a 123456 -h 172.16.65.137 -p 7000 -c 172.16.65.137:7000> get mykey redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c 172.16.65.137:7000> get mykey redis-cli -a 123456 -h 172.16.65.141 -p 7000 -c 172.16.65.137:7000> get mykey redis-cli -a 123456 -h 172.16.65.142 -p 7000 -c 172.16.65.137:7000> get mykey ``` ### 验证集群故障转移 * 将其中一个redis-master停止掉后 * 其对应的slave节点会被选举为master节点 * 旧master节点重新恢复时,其角色会成为slave。 * 查看日志变化 ```scala # 172.16.65.141 1.杀reids-master进程 kill -9 pid 2.查看日志 redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c #查看集群信息 cluster info #查看集群节点列表 cluster nodes # 查看集群内主从关系 redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c cluster slots | xargs -n8 | awk '{print $3":"$4"->"$6":"$7}' | sort -nk2 -t ':' | uniq 3.重新启动 # 172.16.65.141 redis-server ~/opt/redis-cluster/conf/redis_7000.conf ``` ## 加m4(master-slave) ### copy redis环境 ```scala # 172.16.65.142 mkdir -p opt # 172.16.65.139 => 172.16.65.142 cd opt scp -r redis-5.0.8 redis-cluster root@172.16.65.142:~/opt # 设置软链接 # 172.16.65.142 ln -s ~/opt/redis-5.0.8/src/redis-server /usr/bin/redis-server ln -s ~/opt/redis-5.0.8/src/redis-cli /usr/bin/redis-cli ``` ### 启动redis ```scala 1.启动redis-master、redis-slave # 172.16.65.142 redis-server ~/opt/redis-cluster/conf/redis_7000.conf redis-server ~/opt/redis-cluster/conf/redis_7001.conf 2.验证是否成功 ps -ef | grep redis # 查看版本 redis-cli --version redis-server --version tail -f /var/log/redis-sentinel.log ``` ### 加入集群节点 * Redis cluster 扩容缩容重新分片 #### 添加master ```scala 1.启动 # 172.16.65.142 redis-server ~/opt/redis-cluster/conf/redis_7000.conf redis-server ~/opt/redis-cluster/conf/redis_7001.conf 2.添加主节点142:7000到集群(挂当前集群任意节点,这里以139节点为例) # 172.16.65.142:7000 => 172.16.65.139:7000 # 1c3d458143d2461bd5e60e4e52dc83fac7fe4b10 => 139节点id redis-cli -a 123456 --cluster add-node 172.16.65.142:7000 172.16.65.139:7000 --cluster-master-id 1c3d458143d2461bd5e60e4e52dc83fac7fe4b10 3.分配slots # 1c3d458143d2461bd5e60e4e52dc83fac7fe4b10 => 172.16.65.139:7000节点id # 5a3dd2b91371796f49f0c510b5777a4ee80f0b71 => 172.16.65.142:7000节点id redis-cli -a 123456 --cluster reshard 172.16.65.139:7000 --cluster-from 1c3d458143d2461bd5e60e4e52dc83fac7fe4b10 --cluster-to 5a3dd2b91371796f49f0c510b5777a4ee80f0b71 --cluster-slots 50 --cluster-yes ``` #### 添加slave ```scala # 6b829b858ce93507198e5fe6560d61bc7e74bf2f => 172.16.65.142:7000节点id redis-cli -a 123456 --cluster add-node 172.16.65.142:7001 172.16.65.142:7000 --cluster-slave --cluster-master-id 6b829b858ce93507198e5fe6560d61bc7e74bf2f ``` ### 验证 ```scala # 插入数据 redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c 172.16.65.139:7000> set testkey "test Redis" 172.16.65.137:7000> get testkey # 登录其他节点查看数据 redis-cli -a 123456 -h 172.16.65.137 -p 7000 -c 172.16.65.137:7000> get testkey redis-cli -a 123456 -h 172.16.65.139 -p 7000 -c 172.16.65.137:7000> get testkey redis-cli -a 123456 -h 172.16.65.141 -p 7000 -c 172.16.65.141:7000> get testkey redis-cli -a 123456 -h 172.16.65.142 -p 7000 -c 172.16.65.142:7000> get testkey ``` ### 异常处理 1.[ERR] Node 192.168.43.121:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0. * 登录每一个redis节点,清空数据库,即执行flushall命令 2.[ERR] Not all 16384 slots are covered by nodes. * 进入主节点分配slots(参考上面的‘添加主节点“-3.分配slots) 3.其它 ```scala -- 删除节点 redis-cli -a 123456 --cluster del-node 172.16.65.144:7000 23b62ff15f9711569c7bf0c85489480b09971850 -- 查看slots cluster slots -- 删除无效节点 cluster forget 23b62ff15f9711569c7bf0c85489480b09971850 cluster forget d11e07dbb927c3982ac78ba84b9ae3399878f865 cluster forget 49052e35f5ba6c9e5bd736f295580ab0d1be64a2 cluster forget 00b8cc9d6e536b44aa563d641b14be71f3f598ac -- 添加主节点: 4a3de59fa306b2d6e0922df7a744b34af8b31c3d redis-cli -a 123456 --cluster add-node 172.16.65.139:7000 172.16.65.141:7000 --cluster-master-id "4a3de59fa306b2d6e0922df7a744b34af8b31c3d" -- 删除从节点141 slave redis-cli -a 123456 --cluster del-node 172.16.65.141:7001 f68074f322c2946fab88d8d92759f23559c824f5 -- 删除主节点141 master * 移动139上 targetID: 1c3d458143d2461bd5e60e4e52dc83fac7fe4b10 sourceID: 4c325495e5866ccd494660fcb8d471817ca01ff4 node#2:done -- 删除文件 rm -f ~/opt/redis-cluster/conf/nodes_7000.conf rm -f ~/opt/redis-cluster/conf/nodes_7001.conf rm -f ~/opt/redis-cluster/data/redis_7000/dump.rdb rm -f ~/opt/redis-cluster/data/redis_7001/dump.rdb ``` ## Jedis访问RedisCluster ### 导入依赖包 ```scala redis.clients jedis 2.9.3 ``` ### 代码demo ```java import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; import java.util.HashSet; public class JedisClusterDemo { public static void main(String[] args) throws IOException { JedisPoolConfig config = new JedisPoolConfig(); HashSet jedisClusterNodes = new HashSet<>(); //添加集群节点 //| 172.16.65.139 | 7000 | redis-master | //| :-----------: | :--: | :----------: | //| 172.16.65.139 | 7001 | redis-slave | //| 172.16.65.137 | 7000 | redis-master | //| 172.16.65.137 | 7001 | redis-slave | //| 172.16.65.141 | 7000 | redis-master | //| 172.16.65.141 | 7001 | redis-slave | //| 172.16.65.142 | 7000 | redis-master | //| 172.16.65.142 | 7001 | redis-slave | jedisClusterNodes.add(new HostAndPort("172.16.65.139",7000)); jedisClusterNodes.add(new HostAndPort("172.16.65.139",7001)); jedisClusterNodes.add(new HostAndPort("172.16.65.137",7000)); jedisClusterNodes.add(new HostAndPort("172.16.65.137",7001)); jedisClusterNodes.add(new HostAndPort("172.16.65.141",7000)); jedisClusterNodes.add(new HostAndPort("172.16.65.141",7001)); jedisClusterNodes.add(new HostAndPort("172.16.65.142",7000)); jedisClusterNodes.add(new HostAndPort("172.16.65.142",7001)); //获取集群连接 JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes, config); //设置值 jedisCluster.set("name:001","zhangfei"); //获取值 String value = jedisCluster.get("name:001"); System.out.println(value); //关闭连接 jedisCluster.close(); } } ```