根据jedis的murmurhash算法-反推key到指定分片

由于项目特殊需求,必须稳定key到特定的分片。因为目前的redis集群是通过客户端来实现的,为此研究了jedis客户端。

具体的原理参照这篇文章http://blog.csdn.net/guanxinquan/article/details/10231899说的挺明白,很感谢这位兄弟。主要涉及到treeMap(红黑树算法)

原理是将每个redis的实例映射到空间的一部分上,即生成n倍的虚拟节点,然后根据hash(key)算法的落点去映射空间,找到最近的节点。

下面是我的Java代码:依赖jedis

package com.hash;

 

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.SortedMap;

import java.util.TreeMap;

 

import redis.clients.util.MurmurHash;

 

/**

 * 生成可以稳定到分片的key

 * @author sugongp

 * @创建时间 2014-4

 */

public class MurmurHashTest {

 

//jedis中使用的murmur hash

MurmurHash murmur = new MurmurHash();

 

//每个value都相当于是一个分片编号

TreeMap<Long, Integer> tm = new TreeMap<Long, Integer>();

 

//计数器

static Map<String,Integer> countMap = new HashMap<String,Integer>();

 

//可认为是实际的server分片

List<Shard> shards = null;

 

//实际server端分片数量,根据实际情况而定,这里以server为16个分片为例

int serverShards =16;

 

//key=shard编号 value 第一个放入shard的key

static Map<Integer, String>  keyShardMap = new HashMap<Integer, String>();

 

void init(){

shards = new ArrayList<Shard>();

Shard sd = null;

for(int i=0; i<serverShards; i++){

sd = new Shard();

/**

* 默认权重是1,如果修改,即使将全部的shard都修改为10

* 那么key映射到的shard也会随之改变

*/

sd.setWeiht(1);

//默认情况下没有名字,name也会影响hash分片的结果

//sd.setName("shard"+i);

shards.add(sd);

}

}

 

void start(){

int i=0;

//遍历分片

for (Shard sd : shards) {

if(sd.getName() == null) {

//将每个分片,分散的映射到treeMap空间,即在红黑树上生成了大量的虚拟分片

for (int n = 0; n < 160 * sd.getWeiht(); n++) {

tm.put(murmur.hash("SHARD-" + i + "-NODE-" + n), i);

        }

}else {

for (int n = 0; n < 160 * sd.getWeiht(); n++) {

tm.put(murmur.hash(sd.getName() + "*" + sd.getWeiht() + n), i);

        }

        }

        i++;

        }

}

 

 

void test(){

String key; 

//随机生成一万个key

for(int i=0; i<10000; i++){

key = "key"+i;

SortedMap<Long, Integer> sm = tm.tailMap(murmur.hash(key));

int d ; 

if(sm.isEmpty()) {

//找到了她的shard

d = tm.get(tm.firstKey());

System.out.println(String.format("%s = shard%s" ,key, d));

count(d);

if(!keyShardMap.containsKey(d)){

keyShardMap.put(d, key);

}

continue;

}

d = tm.get(sm.firstKey());

System.out.println(String.format("%s = shard%s" ,key, d));

count(d);

if(!keyShardMap.containsKey(d)){

keyShardMap.put(d, key);

}

}

}

 

static void count(int d){

if(countMap.containsKey("shard" + d)){

int c = countMap.get("shard" + d);

countMap.put("shard" + d, ++c);

}else {

countMap.put("shard" + d, 1);

}

}

 

static void print(){

System.out.println(String.format("----------%d个分片中key的数量统计-------------",countMap.size()));

for(String mkey : countMap.keySet()){

System.out.println(String.format("分片%s中key的数量%s个", mkey ,countMap.get(mkey)));

}

System.out.println(String.format("-----------%d个分片中稳定的key统计-------------",keyShardMap.size()));

for(int i : keyShardMap.keySet()){

System.out.println(String.format("第一个稳定到分片%s的key是%s", i, keyShardMap.get(i)));

}

}

 

public static void main(String[] args) {

MurmurHashTest m = new MurmurHashTest();

m.init();

m.start();

m.test();

print();

}

 

}

依赖的类

package com.hash;

 

public class Shard {

 

String name;

 

int weiht;

 

public int getWeiht() {

return weiht;

}

 

public void setWeiht(int weiht) {

this.weiht = weiht;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

}

 

程序执行结果:

----------16个分片中key的数量统计-------------

分片shard13中key的数量606个

分片shard14中key的数量581个

分片shard15中key的数量553个

分片shard0中key的数量645个

分片shard1中key的数量633个

分片shard11中key的数量673个

分片shard4中key的数量559个

分片shard5中key的数量596个

分片shard12中key的数量646个

分片shard2中key的数量712个

分片shard10中key的数量699个

分片shard3中key的数量611个

分片shard8中key的数量591个

分片shard9中key的数量649个

分片shard6中key的数量647个

分片shard7中key的数量599个

-----------16个分片中稳定的key统计-------------

keyShardMap size = 16

第一个稳定到分片0的key是key4

第一个稳定到分片1的key是key0

第一个稳定到分片2的key是key14

第一个稳定到分片3的key是key10

第一个稳定到分片4的key是key5

第一个稳定到分片5的key是key9

第一个稳定到分片6的key是key23

第一个稳定到分片7的key是key32

第一个稳定到分片8的key是key12

第一个稳定到分片9的key是key62

第一个稳定到分片10的key是key3

第一个稳定到分片11的key是key60

第一个稳定到分片12的key是key18

第一个稳定到分片13的key是key51

第一个稳定到分片14的key是key1

第一个稳定到分片15的key是key35

 

猜你喜欢

转载自sugongp.iteye.com/blog/2047915