连续性 一致性hash算法(Consistent hashing)( 五 )


* 每增加一个节点,就会在闭环上增加给定复制节点数
* 例如复制节点数是2,则每调用此方法一次,增加两个虚拟节点,这两个节点指向同一Node* 由于hash算法会调用node的toString方法,故按照toString去重* @param node 节点对象*/public void addNode(Node node) {for (int i = 0; i < virtualNodeNum; i++) {circleMap.put(HashUtils.murMurHash(node.toString() + i), node);}}/*** 移除节点的同时移除相应的虚拟节点* @param node 节点对象*/public void remove(Node node) {for (int i = 0; i < virtualNodeNum; i++) {circleMap.remove(HashUtils.murMurHash(node.toString() + i));}}/*** 获得一个最近的顺时针节点* @param key 为给定键取Hash,取得顺时针方向上最近的一个虚拟节点对应的实际节点* @return 节点对象*/public Node get(Object key) {if (circleMap.isEmpty()) {return null;}long hash = HashUtils.murMurHash(RText.toString(key));if (!circleMap.containsKey(hash)) {SortedMap tailMap = circleMap.tailMap(hash); //返回此映射的部分视图,其键大于等于 hashhash = tailMap.isEmpty() ? circleMap.firstKey() : tailMap.firstKey();}//正好命中return circleMap.get(hash);}}
这些是自己的实现,jedis 已经对分布式一致性哈希算法进行了封装
Jedis 添加服务器
JedisShardInfo jedisShardInfo1 = new JedisShardInfo(bundle.getString("redis1.ip"), Integer.valueOf(bundle.getString("redis.port")));JedisShardInfo jedisShardInfo2 = new JedisShardInfo(bundle.getString("redis2.ip"), Integer.valueOf(bundle.getString("redis.port")));List list = new LinkedList();list.add(jedisShardInfo1);list.add(jedisShardInfo2);
初始化代替:
ShardedJedisPool pool = new ShardedJedisPool(config, list);
测试
public void test() {// 从池中获取一个Jedis对象ShardedJedis jedis = pool.getResource();String keys = "name";String value = "http://www.kingceram.com/post/snowolf";// 删数据jedis.del(keys);// 存数据jedis.set(keys, value);// 取数据String v = jedis.get(keys);System.out.println(v);// 释放对象池pool.returnResource(jedis);assertEquals(value, v);}
这种分布式解决方案能解决只能最大程度的解决数据分布问题,但是还是会引起小范围的数据分布问题,增加节点的时候,当原来对应这台服务器的数据可能就会对应新加的数据库,但是读取的时候就会出问题了,会引起小范围的数据读取不到 。
解决方案
1.Redis 的主从同步,同步下数据,这个可以参考资料 。
【连续性一致性hash算法(Consistent hashing)】2.使用java进行数据的重定向,使用定时任务对数据库进行扫描,得到所有的key进行一次哈希运算,如果是本服务器的数据不处理,如果运算的结果是别的服务器就对这条数据进行迁移,来保持数据的一致性 。