# 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();
}
}
```