环境准备

  • 架构: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-cli --cluster redis-cli --cluster create服务名_RedisCluster

删除文件

删除之前Redis的rdb文件,如果有aof文件的话需要把aof文件也删除了,以及以前集群遗留下来的node.conf文件.

下面是我每台主机redis安装目录详情.配置了三台master和三台slave

redis-cli --cluster redis-cli --cluster create服务名_Redis_02

密码认证

如果主机配置的有密码的话,需要在每台主机的redis.conf文件中修改配置密码访问

redis-cli --cluster redis-cli --cluster create服务名_RedisCluster_03

开机

创建集群

redis-cli --cluster redis-cli --cluster create服务名_Redis集群_04

  • -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

redis-cli --cluster redis-cli --cluster create服务名_redis-cli --cluster_05

查看集群信息

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);
    }
}

redis-cli --cluster redis-cli --cluster create服务名_Redis_06


redis-cli --cluster redis-cli --cluster create服务名_Redis集群_07