1. 集群架构原理
redis集群是有多个主从节点群组成的分布式服务器集群,每一个主从节点都实现了master故障从新选举功能。支持水平扩容:官方建议不超过1000个节点)。
redis cluster 将全部数据划分红 16384 个槽位 slots,每组节点各负责一部分。每组主从节点存储的数据都不相同。当客户端操做时,先经过 key 按照必定算法计算出 key对应的 slots,经过slots定位到相应的主从节点,在当前节点操做。
槽位定位算法:
cluster对key进行crc16算法,获得一个整数,而后对13684取模,获得槽位。 HASH_SLOT = CRC16(key)mod 16384
集群节点之间的通讯:
节点之间采用gossip协议进行通讯。
跳转重定位:
当客户端接收到命令,算出来对应的槽位不是当前ip对应的节点时,会向客户端发出一个特殊的跳转指令,重定位到正确的槽位后再进行操做。
集群选举原理:
当从节点slave发现主节点mater状态变为FAIL后,尝试进行Failover,变为主节点。当msater有多个slave时,slave之间变存在竞争关系。争夺master流程以下:
1)发现master状态变为FAIL
2)将本身记录的集群currentEpoch值加1,并广播FAILOVER_AUTH_REQUEST信息
3)其余slave收到信息后,将向集群中其余的redis节点发送信息,其余节点收到信息后,只有主节点会响应而且只会对第一个slave发送过来的请求发送异常ack,从节点不会响应
4)尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
5)slave 收到超过半数mater的ack后变成新的Master
6)广播Pong消息通知其余集群节点
java
2. 集群搭建
redis.conf 配置文件修改node
daemonize yes
cluster‐enabled yes
cluster‐config‐file nodes‐6379.conf # 与节点 port 对应上
cluster‐node‐timeout 5000
# bind 127.0.0.1(去掉bind绑定访问ip信息)
protected‐mode no (关闭保护模式)
appendonly yes
requirepass 123123 (设置redis访问密码,测试环境可不设置)
masterauth 123123 (设置集群节点间访问密码,跟上面一致,测试环境可不设置) web
分别启动全部节点信息,注意关闭主机防火墙,或打开相应的端口号(redis端口和gossip协议端口),保证redis 各节点之间可以相互访问
用 redis-cli 建立集群信息(redis 5 及之后版本),链接任意一个客户端,输入如下命令
src/redis-cli -a 123123 --cluster create --cluster-replicas 1 192.168.137.10:8001 192.168.137.10:8002 192.168.137.10:8003 192.168.137.10:8004 192.168.137.10:8005 192.168.137.10:8006
(其中 --cluster-replicas 1 表示一个master 创建一个副本数)
输入 cluster nodes 查看节点列表,主节点 最后的 0-5460、5461-1092二、10923-16383 表示槽位信息
至此集群搭建完毕。redis
3. Jedis 链接 redis 集群
pom 文件算法
<dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> </dependencies>
Java 代码 spring
package com.zg.jedis; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; import java.util.HashSet; import java.util.Set; /** * jedis 链接redis集群架构 * @author zg * @date 2020/9/13 */ public class JedisClusterTest { public static void main(String[] args) { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(20); config.setMaxIdle(10); config.setMinIdle(5); Set<HostAndPort> jedisClusterNode = new HashSet<>(); jedisClusterNode.add(new HostAndPort("192.168.137.10", 8001)); jedisClusterNode.add(new HostAndPort("192.168.137.10", 8002)); jedisClusterNode.add(new HostAndPort("192.168.137.10", 8003)); jedisClusterNode.add(new HostAndPort("192.168.137.10", 8004)); jedisClusterNode.add(new HostAndPort("192.168.137.10", 8005)); jedisClusterNode.add(new HostAndPort("192.168.137.10", 8006)); JedisCluster jedisCluster = null; try { jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, config); System.out.println(jedisCluster.set("myCluster", "happy")); System.out.println(jedisCluster.get("myCluster")); } catch (Exception e){ e.printStackTrace(); } finally { if (null != jedisCluster){ try { jedisCluster.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
4. Springboot 链接 redis集群
pom文件apache
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> </dependencies>
application.propertites 服务器
spring.redis.database=0 spring.redis.timeout=3000ms spring.redis.password=123123 # 没有密码的话,不用加 spring.redis.lettuce.pool.max-idle=50 spring.redis.lettuce.pool.min-idle=10 spring.redis.lettuce.pool.max-active=100 spring.redis.lettuce.pool.max-wait=1000ms # 集群模式链接参数 spring.redis.cluster.nodes=192.168.137.10:8001,192.168.137.10:8002,192.168.137.10:8003,192.168.137.10:8004,192.168.137.10:8005,192.168.137.10:8006
java 代码 架构
package com.zg.redis.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 集群架构测试 * @author gz * @date 2020/9/13 */ @RestController public class RedisController { @Autowired private StringRedisTemplate stringRedisTemplate; @RequestMapping("testCluster") public void testCluster(){ stringRedisTemplate.opsForValue().set("myCluster", "Hello World"); System.out.println(stringRedisTemplate.opsForValue().get("myCluster")); } }