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

本文介绍了一种使用Java和MurmurHash算法稳定地将key映射到特定Redis分片的方法。通过生成虚拟节点并利用红黑树进行映射,确保了key能够均匀分布于各分片中。

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

具体的原理参照这篇文章http://blog.youkuaiyun.com/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

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值