welcome to xlongwei.com

欢迎大家一起学习、交流、分享


QQ群:162333776 邮箱:admin@xlongwei.com

jedis sharded 单点故障恢复


分类 Java   关键字 分享   标签 java   linux   spring   redis   发布 hongwei  1471230621152
注意 转载须保留原文链接,译文链接,作者译者等信息。  
redis 分片模式遇到单点故障时系统会崩溃,因为jedis缺乏自动重新分片的恢复功能,因此必须要实现自动重新分片,否则不能使用分片模式。

MyShardedRedisCacheManager实现重新分片,并更新所有MyShardedRedisCache使用的ShardedJedis实例。
private void reshard() {
ShardedJedis reshard = RedisShardUtil.reshard(shardedJedis);
if(shardedJedis != reshard) {
shardedJedis = reshard;
for(Cache cache : caches.values()) {
MyShardedRedisCache myShardedRedisCache = (MyShardedRedisCache)cache;
myShardedRedisCache.shardedJedis = shardedJedis;
}
logger.warn("ShardedJedis resharded");
}
}
//MyShardedRedisCache捕捉异常并触发重新分片
public ValueWrapper get(Object key) {
try {
byte[] computeKey = computeKey(key);
byte[] bs = shardedJedis.get(computeKey);
Object value = valueSerializer.deserialize(bs);
return (bs == null ? null : new SimpleValueWrapper(value));
}catch(JedisException e) { //这个异常若不捕捉会导致系统崩溃,这里正好可以触发重新分片
myShardedRedisCacheManager.reshard();
}
return null;
}

RedisShardUtil负责重新分片:保证节点顺序和数量,使用正常节点替换故障节点(故障节点缓存的数据会丢失,但比系统崩溃好很多了)。
/** 重新分片shardedJedis,使用正常节点替代故障节点 */
public static ShardedJedis reshard(ShardedJedis shardedJedis) {
if(reshard) return shardedJedis; //状态标记,大量reshard请求时只允许一个操作
reshard = true;
Collection<Jedis> allShards = shardedJedis.getAllShards();
Map<Jedis, Boolean> allShardsCheck = new LinkedHashMap<>();
List<Jedis> okNodes = new LinkedList<>();
for(Jedis jedis : allShards) {
boolean check = check(jedis);
allShardsCheck.put(jedis, check);
if(check) okNodes.add(jedis);
}
int allSize = allShardsCheck.size(), okSize = okNodes.size();
if(okSize>0 && okSize<allSize) {
List<JedisShardInfo> nodes = new LinkedList<>();
int okIndex = 0;
for(Jedis jedis : allShards) {
Boolean check = allShardsCheck.get(jedis);
if(!check) {
jedis = okNodes.get(okIndex);
okIndex = (okIndex+1)%okSize;//循环使用正常节点
}
Client client = jedis.getClient();//还有可以从Client获取host和port,不建议设password,用iptables控制端口访问即可
nodes.add(new JedisShardInfo(client.getHost(), client.getPort()));
}
shardedJedis = new ShardedJedis(nodes);
}
reshard = false;
return shardedJedis;
}

效果示例:



评论列表