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