今天学习了redis集群的使用,在此记录一下过程中遇到的问题
一、环境搭建(需要先安装好docker)
这里将使用docker部署4个redis实例(node1-3作为主节点,node4作为1的备节点)
这里把4个redis实例部署在同一台机器上,如果部署在不同机器上,下面有些命令要分开执行
下载redis镜像
docker pull redis:5.0.5
?
创建redis实例的数据目录?
mkdir -p /data/redis-data/node1 /data/redis-data/node2 /data/redis-data/node3 /data/redis-data/node4
chmod -R 777 /data
?创建4个redis容器,其中,node1、node2、node3的端口分别是6379、6380、6381
docker create --name redis-node1 --net host -v /data/redis-data/node1:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-1.conf --port 6379
docker create --name redis-node2 --net host -v /data/redis-data/node2:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-2.conf --port 6380
docker create --name redis-node3 --net host -v /data/redis-data/node3:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-3.conf --port 6381
docker create --name redis-node4 --net host -v /data/redis-data/node4:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-4.conf --port 6382
--name :容器名称
--net:网络模式,host表示和主机处于同一个网络命名空间,这样本地程序才能访问到该redis集群
-v:文件目录挂载
--cluster-enabled:是否启动集群
--cluster-config-file:配置文件
--port:服务端口
?启动容器
docker start redis-node1 redis-node2 redis-node3 redis-node4
?
关闭防火墙(不关闭防火墙,程序无法连接上集群)
systemctl stop firewalld
?二、集群搭建
配置主节点集群
docker exec -it redis-node1 bash
redis-cli --cluster create 192.168.19.138:6379 192.168.19.138:6380 192.168.19.138:6381 --cluster-replicas 0
-- 上面的192.168.19.138是该服务器的ip,实际需要换成自己部署的服务器ip
在node1中,执行redis-cli进入redis服务,查询集群节点状态cluster nodes
?复制node1的id,下面要用
?退出node1的docker,进入主服务器
配置备节点,指定node4为node1的备节点
docker exec -it redis-node4 bash
redis-cli --cluster add-node 192.168.19.138:6382 192.168.19.138:6379 --cluster-slave --cluster-master-id 2a8710ea53acaaaa4c611c880109dece6abbaff6
--上面的2a8710ea53acaaaa4c611c880109dece6abbaff6,需要换成实际的id
查看添加备节点后的集群状态
?
?三、Redis-cluster使用
使用springboot搭建一个简单的客户端,用来连接redis集群,并在过程中,停止node1节点,看看集群环境能否正常切换使用
架包引用,只需要一个jedis,springboot会自动关联jedis版本
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-log4j2")
compile("redis.clients:jedis")
compile("org.projectlombok:lombok:1.18.8")
annotationProcessor ("org.projectlombok:lombok:1.18.8")
testCompile group: 'junit', name: 'junit', version: '4.12'
}
?配置文件application.yaml,需要指定整个集群的所有redis节点,不需要密码
spring:
redis:
cluster:
nodes: 192.168.19.138:6379,192.168.19.138:6380,192.168.19.138:6381,192.168.19.138:6382
?Main入口
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
?redis配置类
@Configuration
public class RedisConfig {
@Value("${spring.redis.cluster.nodes:}")
private String clusterNodes;
@Bean
public JedisCluster getJedisCluster(){
String[] serverArray = clusterNodes.split(",");
Set<HostAndPort> nodes = new HashSet<>();
for (String ipPort : serverArray) {
if(StringUtils.isEmpty(ipPort)){
continue;
}
String[] ipPortPair = ipPort.split(":");
nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));
}
JedisCluster cluster = new JedisCluster(nodes, 1000);
return cluster;
}
}
测试类,每30秒往集群中写数据
@Log4j2
@Component
public class Task implements InitializingBean {
@Autowired
JedisCluster cluster;
@Override
public void afterPropertiesSet() throws Exception {
while(true) {
for (int i = 0; i < 10; i++) {
try {
String key = "abc" + i;
cluster.set(key, "" + i);
int slot = JedisClusterCRC16.getSlot(key);
log.info(cluster.get(key)+" 保存成功,slot:"+slot);
}catch (Exception e){
log.error(e.getMessage());
}
}
Thread.sleep(30000);
}
}
}
四、测试结果
当redis集群所有节点正常运行时,node1、node2、node3三个主节点各自保存一部分数据
?
?
node4的数据和node1的数据保持一致
我们关掉node1节点
?
经过几秒后,可以看到redis集群中,node1状态变成fail,node4状态变成master,并且node4的slot分区和之前的node1保持一致
不过30秒后,程序还是报错了
失败后,JedisCluster重新从redis-cluster更新本地状态,这次又能连上备节点。
?后语
此文章的redis环境部署部分参考了以下文章:
基于Docker搭建Redis集群(主从集群) - niceyoo - 博客园
|