Redis集群搭建

10台

250G/台

160节点

16节点/台

1. 安装依赖

按照"redis集群所需要的依赖"中的解决方案,安装依赖即可。

redis5中不再需要这些依赖!

2. 集群介绍

redis3.x 后的集群 ,是多主多从的集群,多个主机组成一个集群的主体,共同负责对外提供读写服务。

每个主机都有自己的从机,从机的主要工作是:1. 同步主机数据 2.当主机宕机时顶替主机。

3.集群搭建

注意,集群的搭建,至少需要6台虚拟机,因为至少3台主机才能形成集群,每个主机至少有一个从机。

3.1 搭建配置

# 当前虚拟机的Redis,开启cluster支持
cluster-enabled yes
# 当前虚拟机的Redis 用来保存集群信息的文件,保存位置在工作目录下
cluster-config-file nodes-9001.conf
# bind配置中不配置127.0.0.1,否则redis会自动以127.0.0.1作为ip,使得无法通过java远程连接集群
bind 192.168.110.135

如上为两个核心配置,完整配置文件,详见 "rediss"目录,

将此目录直接上传给linux,放在 "/usr/local"目录即可。

如上配置目录中,定义了7份配置,用来启动7个redis服务(模拟7台虚拟机)

3.2 启动redis

# 在/usr/local/rediss目录下执行,启动6个redis服务
# 注意是否有执行权限
./startall.sh
# 查看redis服务
ps -ef | grep redis
root       4042      1  0 10:12 ?        00:00:00 redis-server zhj:9001 [cluster]
root       4044      1  0 10:12 ?        00:00:00 redis-server zhj:9002 [cluster]
root       4049      1  0 10:12 ?        00:00:00 redis-server zhj:9003 [cluster]
root       4054      1  0 10:12 ?        00:00:00 redis-server zhj:9004 [cluster]
root       4059      1  0 10:12 ?        00:00:00 redis-server zhj:9005 [cluster]
root       4064      1  0 10:12 ?        00:00:00 redis-server zhj:9006 [cluster]

3.3 创建集群

# 在 /usr/local/redis-4.0.14/src 目录下执行,开始创建集群
./redis-trib.rb create --replicas 1 192.168.110.135:9001  192.168.110.135:9002  192.168.110.135:9003 192.168.110.135:9004 192.168.110.135:9005 192.168.110.135:9006

如下,最后输入 “yes”

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.110.135:9001
192.168.110.135:9002
192.168.110.135:9003
Adding replica 192.168.110.135:9005 to 192.168.110.135:9001
Adding replica 192.168.110.135:9006 to 192.168.110.135:9002
Adding replica 192.168.110.135:9004 to 192.168.110.135:9003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: c3e026595c56e989cbcef7bcb6ac868b458141df 192.168.110.135:9001
   slots:0-5460 (5461 slots) master
M: 29fe6ceb1d7b698bfe161f8d8e15f9ee8d735527 192.168.110.135:9002
   slots:5461-10922 (5462 slots) master
M: 67e692825590b41b5017e93c9090eed82fc9f3b1 192.168.110.135:9003
   slots:10923-16383 (5461 slots) master
S: 27ecc39812069e764d880002d67bd252c78b051d 192.168.110.135:9004
   replicates 29fe6ceb1d7b698bfe161f8d8e15f9ee8d735527
S: 721c200f8e5cff46ab5b3332d9be01c988e37c9e 192.168.110.135:9005
   replicates 67e692825590b41b5017e93c9090eed82fc9f3b1
S: 07401d81b187002cbca95ec979580436a14e0d5d 192.168.110.135:9006
   replicates c3e026595c56e989cbcef7bcb6ac868b458141df
Can I set the above configuration? (type 'yes' to accept): yes

见到如下输出,集群即创建完毕:

M: c3e026595c56e989cbcef7bcb6ac868b458141df 192.168.110.135:9001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 67e692825590b41b5017e93c9090eed82fc9f3b1 127.0.0.1:9003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 721c200f8e5cff46ab5b3332d9be01c988e37c9e 127.0.0.1:9005
   slots: (0 slots) slave
   replicates 67e692825590b41b5017e93c9090eed82fc9f3b1
S: 27ecc39812069e764d880002d67bd252c78b051d 127.0.0.1:9004
   slots: (0 slots) slave
   replicates 29fe6ceb1d7b698bfe161f8d8e15f9ee8d735527
M: 29fe6ceb1d7b698bfe161f8d8e15f9ee8d735527 127.0.0.1:9002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 07401d81b187002cbca95ec979580436a14e0d5d 127.0.0.1:9006
   slots: (0 slots) slave
   replicates c3e026595c56e989cbcef7bcb6ac868b458141df
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

4. 槽

slot : 槽,集群共有16384个slot,索引为 0-16383。如下为【主机1,2,3】【从机a,b,c】

M: c3e026595c56e989cbcef7bcb6ac868b458141df 192.168.110.135:9001 【主机1】
   slots:0-5460 (5461 slots) master 【主机1】
   1 additional replica(s) 【主机1有1个从机】
M: 67e692825590b41b5017e93c9090eed82fc9f3b1 127.0.0.1:9003 【主机2】
   slots:10923-16383 (5461 slots) master 【主机2】
   1 additional replica(s) 【主机2有1个从机】
S: 721c200f8e5cff46ab5b3332d9be01c988e37c9e 127.0.0.1:9005 【从机a】
   slots: (0 slots) slave 【从机a】
   replicates 67e692825590b41b5017e93c9090eed82fc9f3b1 【从机a的主机的id,则从机a是属于主机2的】
S: 27ecc39812069e764d880002d67bd252c78b051d 127.0.0.1:9004 【从机b】
   slots: (0 slots) slave 【从机b】
   replicates 29fe6ceb1d7b698bfe161f8d8e15f9ee8d735527  【从机b的主机的id,则从机b是属于主机3的】
M: 29fe6ceb1d7b698bfe161f8d8e15f9ee8d735527 127.0.0.1:9002 【主机3】
   slots:5461-10922 (5462 slots) master 【主机3】
   1 additional replica(s) 【主机3有1个从机】
S: 07401d81b187002cbca95ec979580436a14e0d5d 127.0.0.1:9006 【从机c】
   slots: (0 slots) slave 【从机c】
   replicates c3e026595c56e989cbcef7bcb6ac868b458141df  【从机c的主机的id,则从机c是属于主机1的】
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

如上是集群中的3主 3从,主机1持有槽【0-5460】 主机2持有槽【10923-16383】 主机3持有槽【5461-10922】。

注意:只有主机才占有槽,槽并不是一个存储单位。槽是redis集群做负载均衡的计量。

要进一步理解槽,需要看完 5,6两个章节

5. 连接集群

 # -c 即代表要连接集群
 redis-cli -c -p 9001 -h 192.168.110.135

6. 集群操作

192.168.110.135:9001> set name zhj
-> Redirected to slot [5798] located at 127.0.0.1:9002 【经计算 name应该由9002存储】
OK

192.168.110.135:9002> set gender true
-> Redirected to slot [15355] located at 127.0.0.1:9003 【经计算 gender应该由9003存储】
OK

192.168.110.135:9003> set age 19
-> Redirected to slot [741] located at 127.0.0.1:9001  【经计算 age应该由9001存储】
OK

所谓的计算,是对读/写 操作中的 key 做一致性hash运算,得到一个数字 num, 然后 num%16384

得到 一个 [0--16383]区间的数字

如 name 的运算结果为 5798 gender的运算结果为15355 age的运算结果为741

5798,15355,741是槽的下标,则对应的key由对应主机存储

7.连接集群-java

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <!-- 最多空闲连接数 -->
    <property name="maxIdle" value="1" />
    <!-- 最多有多少连接 -->
    <property name="maxTotal" value="5" />
    <property name="minIdle" value="1"></property>
    <!-- 连接数用完时,是否阻塞,阻塞超过maxWaitMillis会抛出异常 -->
    <property name="blockWhenExhausted" value="true" />
    <!-- 检出连接时,最大等待时长 -->
    <property name="maxWaitMillis" value="30000" />
    <!-- 在检出时是否检测 -->
    <property name="testOnBorrow" value="false" />
    <!-- 空闲时是否检测连接是否可用 -->
    <property name="testWhileIdle" value="false"></property>
    <!-- Evict=驱逐  连接至少要空闲多少时间才会成为可以被驱逐线程扫描并移除 -->
    <property name="minEvictableIdleTimeMillis" value="60000"></property>
    <!-- 驱逐线程 两次驱逐之间要sleep的时间 如果小于0,则不会有驱逐线程,则minEvictableIdleTimeMillis无效-->
    <property name="timeBetweenEvictionRunsMillis" value="30000"></property>
    <!-- 驱逐线程每次最多扫描几个连接 -->
    <property name="numTestsPerEvictionRun" value="3"></property>
    <!-- last in first out 检出(获取连接)策略 后入先出  或 先入先出 -->
    <property name="lifo" value="true"></property>
</bean>
<!-- 为 redisClusterConfiguration定制参数配置-->
<bean id="propertyPropertySource" class="org.springframework.core.env.PropertiesPropertySource">
    <constructor-arg index="0" type="java.lang.String" value="redisParam1911"></constructor-arg>
    <constructor-arg index="1" type="java.util.Properties">
        <props>
            <!-- 集群中的所有或部分节点ip:port -->
            <prop key="spring.redis.cluster.nodes">192.168.110.135:9006,192.168.110.135:9007</prop>
            <!--
                    默认为5,连接不到集群时,重试次数
                  -->
            <prop key="spring.redis.cluster.max-redirects">5</prop>
        </props>
    </constructor-arg>
</bean>
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
    <constructor-arg name="propertySource" ref="propertyPropertySource"/>
</bean>
<bean id="jedisConnectionFactory"
      class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <constructor-arg name="clusterConfig" ref="redisClusterConfiguration"></constructor-arg>
    <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
<!-- redis template definition -->
<bean id="ss" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<bean id="fast" class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"></bean>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
      p:connection-factory-ref="jedisConnectionFactory"
      p:keySerializer-ref="ss"
      p:stringSerializer-ref="ss"
      p:valueSerializer-ref="fast"/>

无论连接的是 单点redis,还是集群的redis,Spring-Data-Redis的所有API不变

8. 添加主节点

8.1 添加新节点

增加一套配置,并以此配置启动redis实例。并执行如下指令;

                                               新机器的ip:port      集群某个成员的ip:port
[root@zhj04 src]# ./redis-trib.rb add-node 192.168.79.128:9007 192.168.79.128:9006

如果成功,会有如下输出
>>> Adding node 192.168.79.128:9007 to cluster 192.168.79.128:9006
>>> Performing Cluster Check (using node 192.168.79.128:9006)
S: f6eb31694591a3d7d4d63a13d6775d0397ccabcc 192.168.79.128:9006
   slots: (0 slots) slave
   replicates 9a4d54b36e525118b1b9c0f94c65320e5584feb7
S: 3ababf9bd48fab51f0e786ba36dfbdab43e31741 192.168.79.128:9005
   slots: (0 slots) slave
   replicates 8c8acf426bc93340b01942b8567230db7bd82577
M: 8c8acf426bc93340b01942b8567230db7bd82577 192.168.79.128:9003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 9b7d58f0be57d54e6044dc1a8101f12e0fddc849 192.168.79.128:9004
   slots: (0 slots) slave
   replicates 798e705d85c0e6bd432e7103a6b5ccad0f30f29c
M: 9a4d54b36e525118b1b9c0f94c65320e5584feb7 192.168.79.128:9001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 798e705d85c0e6bd432e7103a6b5ccad0f30f29c 192.168.79.128:9002
   slots:5461-10922 (5462 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.
>>> Send CLUSTER MEET to node 192.168.79.128:9007 to make it join the cluster.
[OK] New node added correctly.

8.2 重新分片

新加的主机没有slot,需要将已有主机的slot分出部分给它。最终保证所有主机的slot个数是均衡的。

执行如下指令,开始重新分片:

                                             新机器的ip:port
[root@zhj04 src]# ./redis-trib.rb reshard 192.168.79.128:9008

下一步,会有如下输出
How many slots do you want to move (from 1 to 16384)? [在此输入要给新机器分配的槽的数量]

下一步,会有如下输出
What is the receiving node ID? [在此输入新机器的节点id]

下一步,会有如下输出
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:[再次输入"all"]

下一步,会有如下输出
Do you want to proceed with the proposed reshard plan (yes/no)? [在此输入”yes“]
之后便会进行分片操作

# 分片后,执行如下指令检查 集群状态
[root@zhj04 src]# ./redis-trib.rb check 192.168.79.128:9002

9.添加从节点

9.1 添加新节点

此过程和 8.1章节一样,先复制一套配置,然后开启新的redis节点.

然后,执行如下指令:

                                            从机             主机id
[root@zhj04 src]# ./redis-trib.rb  add-node --slave --master-id ad27f044c31b8c3e0e43a5b1dff080144d9ca85f 192.168.79.128:9008 192.168.79.128:9006
    新机器ip:port        已有及其ip:port