`

根据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

 

分享到:
评论

相关推荐

    jedis-3.0.0.jar、jedis-3.0.0-javadoc.jar、jedis-3.0.0-sources.jar

    在开发过程中,jedis-3.0.0-javadoc.jar和jedis-3.0.0-sources.jar可以帮助开发者更好地理解和调试代码。API文档提供清晰的接口说明,而源代码则揭示了这些接口背后的实现逻辑。 总结来说,这三个JAR文件构成了一个...

    jedis-2.9.0-API文档-中文版.zip

    赠送jar包:jedis-2.9.0.jar; 赠送原API文档:jedis-2.9.0-javadoc.jar; 赠送源代码:jedis-2.9.0-sources.jar; 包含翻译后的API文档:jedis-2.9.0-javadoc-API文档-中文(简体)版.zip 对应Maven信息:groupId...

    jedis-x64-3.2.100.jar(内含commons-pool2-2.4.2.jar)

    在集成到项目中时,需要注意的是,`jedis-x64-3.2.100.jar`和`commons-pool2-2.4.2.jar`都应添加到项目的类路径中,否则可能会出现运行时错误。对于现代Java项目,这通常可以通过Maven或Gradle等构建工具来实现,将...

    jedis-3.6.0-API文档-中文版.zip

    赠送jar包:jedis-3.6.0.jar; 赠送原API文档:jedis-3.6.0-javadoc.jar; 赠送源代码:jedis-3.6.0-sources.jar; 赠送Maven依赖信息文件:jedis-3.6.0.pom; 包含翻译后的API文档:jedis-3.6.0-javadoc-API文档-...

    jedis-2.9.0-API文档-中英对照版.zip

    赠送jar包:jedis-2.9.0.jar 赠送原API文档:jedis-2.9.0-javadoc.jar 赠送源代码:jedis-2.9.0-sources.jar 包含翻译后的API文档:jedis-2.9.0-javadoc-API文档-中文(简体)-英语-对照版.zip 对应Maven信息:...

    jedis-2.9.0+commons-pool2-2.4.2redis依赖包

    标题中的"jedis-2.9.0+commons-pool2-2.4.2redis依赖包"指的是一款基于Java实现的Redis客户端库Jedis的2.9.0版本,与Apache Commons Pool 2.4.2版本相结合的依赖包。这个组合主要用于优化Redis连接池管理,提高应用...

    jedis.jar包commons-pool.jar包

    jedis2.3---jedis2.9版本jar包,附赠commons-pool.jar包

    jedis-jedis-1.5.0-RC2.zip

    6. **分片和集群支持**:Jedis支持Redis的分片和集群模式,能够在多个Redis实例之间分散负载。 7. **复制**:Jedis提供了主从复制的配置和操作,便于数据备份和故障恢复。 8. **Pipeline和Transaction**:这两个...

    jedis-3.0.0-m1.jar

    jedis 各个版本 jedis 连接 redis 数据库 jedis-sources 源码

    jedis-jedis-1.5.0-RC1.zip

    `jedis-jedis-1.5.0-RC1.zip`是一个包含Jedis 1.5.0 Release Candidate 1版本的压缩包,它可能包含了源代码、文档、示例和测试用例等内容,用于开发者在项目中集成或测试Jedis的最新功能。 Jedis的主要特点包括: 1...

    jedis-jedis-3.6.0-rc1.tar.gz

    在标题"jedis-jedis-3.6.0-rc1.tar.gz"中,我们可以看出这是Jedis的一个版本,即3.6.0的候选发布1版(Release Candidate 1,简称RC1)。RC1通常是软件正式发布前的最后一个测试版本,意味着它在功能和稳定性上已经...

    jedis-3.6.0-API文档-中英对照版.zip

    赠送jar包:jedis-3.6.0.jar; 赠送原API文档:jedis-3.6.0-javadoc.jar; 赠送源代码:jedis-3.6.0-sources.jar; 赠送Maven依赖信息文件:jedis-3.6.0.pom; 包含翻译后的API文档:jedis-3.6.0-javadoc-API文档-...

    jedis-2.9.0.jar

    jedis-2.9.0.jar jedis-2.9.0 jar 包,不包含源码,源码下载地址: http://download.csdn.net/download/tan3739/9993938 测试代码: 导入依赖包: commons-lang-2.5.jar commons-pool2-2.4.2.jar jedis-2.9.0 jar ...

    jedis-jedis-1.5.0-RC2.tar.gz

    标题中的"jedis-jedis-1.5.0-RC2.tar.gz"指的是Jedis的一个版本,即1.5.0的候选发布版2(Release Candidate 2),通常在正式版本发布之前,RC版本会进行最后的测试和调整,以确保软件的稳定性和兼容性。 在Java应用...

    jedis-3.0.1-API文档-中文版.zip

    赠送jar包:jedis-3.0.1.jar; 赠送原API文档:jedis-3.0.1-javadoc.jar; 赠送源代码:jedis-3.0.1-sources.jar; 赠送Maven依赖信息文件:jedis-3.0.1.pom; 包含翻译后的API文档:jedis-3.0.1-javadoc-API文档-...

    jedis-2.8.0-SNAPSHOT.jar

    jedis-2.8.0-SNAPSHOT.jar

    jedis-2.8.0-API文档-中文版.zip

    赠送jar包:jedis-2.8.0.jar; 赠送原API文档:jedis-2.8.0-javadoc.jar; 赠送源代码:jedis-2.8.0-sources.jar; 赠送Maven依赖信息文件:jedis-2.8.0.pom; 包含翻译后的API文档:jedis-2.8.0-javadoc-API文档-...

    jedis-jedis-3.1.0-rc.zip

    标题"jedis-jedis-3.1.0-rc.zip"表明这是一个关于Jedis的3.1.0 release candidate版本的压缩包,通常在正式版本发布前,release candidate(RC)是最后测试阶段的版本,意味着它可能包含了所有计划的新功能和改进,...

    jedis-2.9.0.jar和commons-pool2-2.6.0.jar下载(jedis连接redis数据库)

    标题"jedis-2.9.0.jar和commons-pool2-2.6.0.jar下载(jedis连接redis数据库)"指的是两个Java库的下载信息,用于连接Redis数据库。其中,`jedis-2.9.0.jar`是Jedis的特定版本,它是Java开发人员用来操作Redis的...

    jedis-jedis-1.5.0-RC1.tar.gz

    这个压缩包"jedis-jedis-1.5.0-RC1.tar.gz"包含了Jedis 1.5.0 Release Candidate 1版本的源代码和相关资源。在本文中,我们将深入探讨Jedis的功能、特性以及如何使用它来操作Redis。 首先,Jedis作为Redis的Java...

Global site tag (gtag.js) - Google Analytics