在云服务器部署redis集群遇到的问题 - 简书
具体环境:两台云端服务器 专有网络
一台云端服务器 经典网络
软件环境: 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);
}
}
`