具體環境:兩臺云端服務器 專有網絡
一臺云端服務器 經典網絡
軟件環境: jedis 2.9.0 redis3.2.10
1、先是設置了redis密碼再集群,見 http://blog.csdn.net/jtbrian/article/details/53691540
補充點: /usr/lib/ruby/gems/1.8/gems/redis-3.3.0/lib/redis/client.rb
這里的 client.rb
文件路徑是按照你安裝ruby、在通過gems安裝redis3.3的時候的路徑(不熟悉ruby的軟件安裝)。像我通過rvm安裝的ruby, client.rb
就在 /usr/local/rvm/gems/ruby-2.3.3/gems/redis-3.3.3/lib/redis/client.rb
路徑因ruby的安裝方法而異。
2、集群之后,在本地使用jedisCluster進行操作的時候出現 Could not get a resource from the pool
原因:出現這個原因有很多,例如:確實分配資源不夠。但是我只是寫了一個小demo,而且集群的配置確實沒問題,可以在本地通過redis-cli訪問集群。而且我的jedisCluster還有神奇的地方,只是個別Master無法操作(會報異常),其他點操作正常。
解決方法:
1、先研究jedisCluster源碼,發現jedisCluster這么處理集群的:
1)依次獲取集群中的 HostAndPort
2)對于每個 HostAndPort
獲取各CLusterNodes節點消息,并保存。
2、jedisCluster是如何獲取各ClusterNodes節點消息?
他是通過命令 cluster nodes獲取的,也就是根據 服務器端產生的 nodes-xxx.conf
( xxx
為端口號)。
3、登陸服務器端,查看對應cluster 配置文件, 我的是默認存放在 /nodes-6379.conf
。可以發現,在阿里云的專有網絡里面,主機只擁有內網網卡,所以cluster只綁定了內網地址。
修改方法,先停止該節點,然后修改 /node-6379.conf
將
053420032000043aa9983d5b30e09c83258b3186 內網IP地址:6379 myself,master - 0 0 1 connected 0-5460
改為
053420032000043aa9983d5b30e09c83258b3186 你的公網IP地址:6379 myself,master - 0 0 1 connected 0-5460
其他無需改動。
后感
因為在redis的配置文件里面已經說明cluster是自動產生的配置文件,一般情況下無需自己去修改,但是有時候例如我這種情況,只擁有內網網卡,公網IP地址估計是通過NAT轉換到私有地址的話,自己不嘗試去修改一下配置文件,也許問題一直都無法解決。還有能找到這個bug也只是恰好三臺服務器里面有一臺還是經典網絡幫我配置好了公網網卡,所以jedisCluster通過這個節點可以訪問所有的Master。
另附源碼:jedis-2.9\src\main\java\redis\clients\jedis\JedisClusterConnectionHandler.java
private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig, String password, String clientName) {
for (HostAndPort hostAndPort : startNodes) {
Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort());
try {
if (password != null) {
jedis.auth(password);
}
if (clientName != null) {
jedis.clientSetname(clientName);
}
cache.discoverClusterNodesAndSlots(jedis);
break;
} catch (JedisConnectionException e) {
// try next nodes
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
jedis-2.9\src\main\java\redis\clients\jedis\JedisClusterInfoCache.java
:
private void discoverClusterSlots(Jedis jedis) {
List<Object> slots = jedis.clusterSlots();
this.slots.clear();
for (Object slotInfoObj : slots) {
List<Object> slotInfo = (List<Object>) slotInfoObj;
if (slotInfo.size() <= MASTER_NODE_INDEX) {
continue;
}
List<Integer> slotNums = getAssignedSlotArray(slotInfo);
// hostInfos
List<Object> hostInfos = (List<Object>) slotInfo.get(MASTER_NODE_INDEX);
if (hostInfos.isEmpty()) {
continue;
}
// at this time, we just use master, discard slave information
HostAndPort targetNode = generateHostAndPort(hostInfos);
assignSlotsToNode(slotNums, targetNode);
}
}
`