日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis进阶-JedisCluster初始化 自动管理连接池中的连接 _ 源码分析

發(fā)布時間:2025/3/21 数据库 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis进阶-JedisCluster初始化 自动管理连接池中的连接 _ 源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • Pre
  • Code
  • 初始化
  • 槽計算
  • 無需手工調用close方法


Pre

Redis進階-Redis集群原理剖析及gossip協(xié)議初探 集群原理部分 簡單的提了下Jest是如何實現(xiàn)Redis Cluster 的 ,這里我們再來梳理一下


Code

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;public class JedisClusterDemo {public static void main(String[] args) throws IOException {JedisPoolConfig config = new JedisPoolConfig();config.setMaxTotal(20);config.setMaxIdle(10);config.setMinIdle(5);Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();jedisClusterNode.add(new HostAndPort("192.168.18.131", 8001));jedisClusterNode.add(new HostAndPort("192.168.18.131", 8004));jedisClusterNode.add(new HostAndPort("192.168.18.132", 8002));jedisClusterNode.add(new HostAndPort("192.168.18.132", 8005));jedisClusterNode.add(new HostAndPort("192.168.18.133", 8003));jedisClusterNode.add(new HostAndPort("192.168.18.133", 8006));JedisCluster jedisCluster = null;try {//connectionTimeout:指的是連接一個url的連接等待時間//soTimeout:指的是連接上一個url,獲取response的返回等待時間jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "artisan", config);System.out.println(jedisCluster.set("clusterArtisan", "artisanValue"));System.out.println(jedisCluster.get("clusterArtisan"));} catch (Exception e) {e.printStackTrace();} finally {if (jedisCluster != null)jedisCluster.close();}} }

這里是個簡單的demo, 生產中用的話,需要確保jedisCluster是單例的,并且無需手工調用close,不然的話 這個連接池就關閉了,你就無法獲取到連接了。


初始化

當 Redis Cluster 的客戶端來連接集群時,它也會得到一份集群的槽位配置信息并將其緩存在客戶端本地。這樣當客戶端要查找某個 key 時,可以直接定位到目標節(jié)點。

我們來看下jedis的實現(xiàn)

jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "artisan", config);

跟下源碼

public JedisClusterConnectionHandler(Set<HostAndPort> nodes,final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password) {this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout, password);initializeSlotsCache(nodes, poolConfig, password);}

重點看下 initializeSlotsCache

private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig, String password) {for (HostAndPort hostAndPort : startNodes) {Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort());if (password != null) {jedis.auth(password);}try {cache.discoverClusterNodesAndSlots(jedis);break;} catch (JedisConnectionException e) {// try next nodes} finally {if (jedis != null) {jedis.close();}}}}

繼續(xù) cache.discoverClusterNodesAndSlots(jedis); cache為 JedisClusterInfoCache 對象。

public void discoverClusterNodesAndSlots(Jedis jedis) {w.lock();try {reset();List<Object> slots = jedis.clusterSlots();for (Object slotInfoObj : slots) {List<Object> slotInfo = (List<Object>) slotInfoObj;if (slotInfo.size() <= MASTER_NODE_INDEX) {continue;}List<Integer> slotNums = getAssignedSlotArray(slotInfo);// hostInfosint size = slotInfo.size();for (int i = MASTER_NODE_INDEX; i < size; i++) {List<Object> hostInfos = (List<Object>) slotInfo.get(i);if (hostInfos.size() <= 0) {continue;}HostAndPort targetNode = generateHostAndPort(hostInfos);setupNodeIfNotExist(targetNode);if (i == MASTER_NODE_INDEX) {assignSlotsToNode(slotNums, targetNode);}}}} finally {w.unlock();}}

槽計算

set --------> run ----> runWithRetries ----> connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key))

CRC16算法,計算key對應的slot connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key))

public static int getSlot(byte[] key) {int s = -1;int e = -1;boolean sFound = false;for (int i = 0; i < key.length; i++) {if (key[i] == '{' && !sFound) {s = i;sFound = true;}if (key[i] == '}' && sFound) {e = i;break;}}if (s > -1 && e > -1 && e != s + 1) {return getCRC16(key, s + 1, e) & (16384 - 1);}return getCRC16(key) & (16384 - 1);}

無需手工調用close方法

進入到set方法中看下源碼

jedisCluster.set("clusterArtisan", "artisanValue")

如下:

@Overridepublic String set(final String key, final String value) {return new JedisClusterCommand<String>(connectionHandler, maxAttempts) {@Overridepublic String execute(Jedis connection) {return connection.set(key, value);}}.run(key);}

命令模式, 關注 run方法

public T run(String key) {if (key == null) {throw new JedisClusterException("No way to dispatch this command to Redis Cluster.");}return runWithRetries(SafeEncoder.encode(key), this.maxAttempts, false, false);}

繼續(xù) runWithRetries , 截取核心邏輯

private T runWithRetries(byte[] key, int attempts, boolean tryRandomNode, boolean asking) {Jedis connection = null;try {if (asking) {......} else {if (tryRandomNode) {connection = connectionHandler.getConnection();} else {connection = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));}}return execute(connection);} finally {releaseConnection(connection);}}

關注點

  • CRC16算法,計算key對應的slot connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key))
public static int getSlot(byte[] key) {int s = -1;int e = -1;boolean sFound = false;for (int i = 0; i < key.length; i++) {if (key[i] == '{' && !sFound) {s = i;sFound = true;}if (key[i] == '}' && sFound) {e = i;break;}}if (s > -1 && e > -1 && e != s + 1) {return getCRC16(key, s + 1, e) & (16384 - 1);}return getCRC16(key) & (16384 - 1);}
  • getConnectionFromSlot 通過 JedisPool 獲取連接

關注下 JedisCluster是如何獲取連接的 getConnectionFromSlot 方法

@Overridepublic Jedis getConnectionFromSlot(int slot) {JedisPool connectionPool = cache.getSlotPool(slot);if (connectionPool != null) {// It can't guaranteed to get valid connection because of node// assignmentreturn connectionPool.getResource();} else {renewSlotCache(); //It's abnormal situation for cluster mode, that we have just nothing for slot, try to rediscover stateconnectionPool = cache.getSlotPool(slot);if (connectionPool != null) {return connectionPool.getResource();} else {//no choice, fallback to new connection to random nodereturn getConnection();}}}

本質上還是通過 JedisPool 來獲取一個getResource ,跟我們使用Sentinel 啊 單節(jié)點獲取方法是一樣的


  • finally 語句中的 releaseConnection(connection); ,自動釋放連接

看下該方法

private void releaseConnection(Jedis connection) {if (connection != null) {connection.close();}}

說白了,JedisCluster set后會自動釋放連接,調用的是jedis 的close方法,所以我們無需手工關閉,否則你這個jedis的連接池就掛逼了…

總結

以上是生活随笔為你收集整理的Redis进阶-JedisCluster初始化 自动管理连接池中的连接 _ 源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。