环境准备
- 架构:3主3从(Redis集群最少3主3从)
- 服务器:CentOS7
- Redis版本:Redis5.0.5
- 网络环境:
- 192.168.188.99(主机名:master)
- 192.168.188.100(主机名:master2)
- 192.168.188.101(主机名:master3)
- 192.168.188.102(主机名:slave)
- 192.168.188.103(主机名:slave2)
- 192.168.188.104(主机名:slave3)
- 各个主机防火墙均已关闭
- 注意:2018年十月Redis发布了稳定版本的5.0版本,放弃Ruby的集群方式,改为使用C语言编写的redis-cli的方式,是集群的构建方式复杂度大降低。
redis配置
修改主机的redis.conf开启集群
删除文件
删除之前Redis的rdb文件,如果有aof文件的话需要把aof文件也删除了,以及以前集群遗留下来的node.conf文件.
下面是我每台主机redis安装目录详情.配置了三台master和三台slave
密码认证
如果主机配置的有密码的话,需要在每台主机的redis.conf文件中修改配置密码访问
开机
创建集群
- -a:当前主机密码
- create:创建集群 参数是集群中各个节点的IP地址或者主机名加上端口号
- cluster-replicas 1:意思是每个Master带着1个Slave
集群创建成功
[root@master bin]# ./redis-cli -a xiaochen0. --cluster create 192.168.188.99:6379 master2:6379 master3:6379 slave:6379 slave:6379 slave2:6379 slave3:6379 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 7 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica slave2:6379 to 192.168.188.99:6379
Adding replica slave3:6379 to master2:6379
Adding replica slave:6379 to master3:6379
Adding extra replicas...
Adding replica slave:6379 to 192.168.188.99:6379
M: 38893e64753481f053663756330f7654914113a0 192.168.188.99:6379
slots:[0-5460] (5461 slots) master
M: 4b353d3b6ef42813fdd4b48c0c14cba7535c71a6 master2:6379
slots:[5461-10922] (5462 slots) master
M: 2f4808694e7d4c9cf798ec5fbe33bbf0bc999927 master3:6379
slots:[10923-16383] (5461 slots) master
S: af34800d1d69026a65730b21841074c4173b9a88 slave:6379
replicates 38893e64753481f053663756330f7654914113a0
S: af34800d1d69026a65730b21841074c4173b9a88 slave:6379
replicates 2f4808694e7d4c9cf798ec5fbe33bbf0bc999927
S: f3c9e03ed0cc1dc3b3ac3eeb9a17b03d4d37f985 slave2:6379
replicates 38893e64753481f053663756330f7654914113a0
S: 444c4fe7d900741077ffe11328b50f068677f032 slave3:6379
replicates 4b353d3b6ef42813fdd4b48c0c14cba7535c71a6
Can I set the above configuration? (type 'yes' to accept): yes
这里Redis会问你是否确认上面的配置,就是Redis会自动帮你分配主从.输入yes即可
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 192.168.188.99:6379)
M: 38893e64753481f053663756330f7654914113a0 192.168.188.99:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 4b353d3b6ef42813fdd4b48c0c14cba7535c71a6 192.168.188.100:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: af34800d1d69026a65730b21841074c4173b9a88 192.168.188.102:6379
slots: (0 slots) slave
replicates 2f4808694e7d4c9cf798ec5fbe33bbf0bc999927
S: 444c4fe7d900741077ffe11328b50f068677f032 192.168.188.104:6379
slots: (0 slots) slave
replicates 4b353d3b6ef42813fdd4b48c0c14cba7535c71a6
S: f3c9e03ed0cc1dc3b3ac3eeb9a17b03d4d37f985 192.168.188.103:6379
slots: (0 slots) slave
replicates 38893e64753481f053663756330f7654914113a0
M: 2f4808694e7d4c9cf798ec5fbe33bbf0bc999927 192.168.188.101:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
到这里集群就已经搭建成功,可以发现Redis已经帮我们配置好主从关系了,S为slave(从机),M为Master(主机)
Redis-Cli连接集群
命令
./redis-cli -a 你的redis密码 -c
查看当前主机的信息
info replication
这里可以发现我们这台主机的角色是master
查看集群信息
cluster info
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1033
cluster_stats_messages_pong_sent:882
cluster_stats_messages_sent:1915
cluster_stats_messages_ping_received:877
cluster_stats_messages_pong_received:1033
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1915
查看集群的节点信息
127.0.0.1:6379> cluster nodes
444c4fe7d900741077ffe11328b50f068677f032 192.168.188.104:6379@16379 slave 4b353d3b6ef42813fdd4b48c0c14cba7535c71a6 0 1565938612865 2 connected
af34800d1d69026a65730b21841074c4173b9a88 192.168.188.102:6379@16379 slave 2f4808694e7d4c9cf798ec5fbe33bbf0bc999927 0 1565938611858 4 connected
2f4808694e7d4c9cf798ec5fbe33bbf0bc999927 192.168.188.101:6379@16379 master - 0 1565938613871 3 connected 10923-16383
4b353d3b6ef42813fdd4b48c0c14cba7535c71a6 192.168.188.100:6379@16379 myself,master - 0 1565938612000 2 connected 5461-10922
38893e64753481f053663756330f7654914113a0 192.168.188.99:6379@16379 master - 0 1565938614877 1 connected 0-5460
f3c9e03ed0cc1dc3b3ac3eeb9a17b03d4d37f985 192.168.188.103:6379@16379 slave 38893e64753481f053663756330f7654914113a0 0 1565938612000 6 connected
集群操作
连接集群之后添加一个key.
192.168.188.100:6379> set money 888
-> Redirected to slot [11921] located at 192.168.188.101:6379
OK
192.168.188.100:6379> set age 100
-> Redirected to slot [741] located at 192.168.188.99:6379
OK
可以发现我们的key一个被重定向到192.168.188.101的槽内
money
一个被重定向到192.168.188.99的槽内.
age
当我们使用get money命令的时候因为之前是在101的槽内,所以不用重定向获取,获取age的时候会发现我们的连接已经被重定向到了192.168.188.99.
192.168.188.101:6379> get money
"888"
192.168.188.101:6379> get age
-> Redirected to slot [741] located at 192.168.188.99:6379
"100"
192.168.188.99:6379>
当我们在key所在的主机中get key的时候连接是不用重定向的.
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"100"
127.0.0.1:6379> get name
-> Redirected to slot [5798] located at 192.168.188.100:6379
"zhangsan"
192.168.188.100:6379>
开始的时候连接本地的redis,查看本机所有的key,在获取本地的key的时候,链接没有发生重定向,当我们获取集群中的key的时候,它会去集群中的节点中寻找这个key,然后重定向我们的连接.
Spring链接集群
SpringBean信息
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<!-- 连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30"/>
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10"/>
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024"/>
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000"/>
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500"/>
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="false"/>
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true"/>
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false"/>
</bean>
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg index="0">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.188.99"></constructor-arg>
<constructor-arg index="1" value="6379"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.188.100"></constructor-arg>
<constructor-arg index="1" value="6379"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.188.101"></constructor-arg>
<constructor-arg index="1" value="6379"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.188.102"></constructor-arg>
<constructor-arg index="1" value="6379"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.188.103"></constructor-arg>
<constructor-arg index="1" value="6379"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.188.104"></constructor-arg>
<constructor-arg index="1" value="6379"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg index="1" value="3000"></constructor-arg>
<constructor-arg index="2" value="3000"></constructor-arg>
<constructor-arg index="3" value="10"></constructor-arg>
<constructor-arg index="4" value="redis实例密码"></constructor-arg>
<constructor-arg index="5" ref="jedisPoolConfig"></constructor-arg>
</bean>
</beans>
测试代码
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* @program: JavaRedis
* @description: Jedis集群
* @author: Mr.Wang
* @create: 2019-08-15 17:54
**/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:cluster.xml")
public class SpringJedisCluster {
@Autowired
private JedisCluster jedisCluster;
@Test
public void testJedisCluster() throws IOException {
jedisCluster.set("age", "999");
String name = jedisCluster.get("age");
System.out.println(name);
}
}