Jedis路由key的算法剥离
在Redis集群中,会有很多个分片,如果此时利用Jedis来操作此Redis集群,那么他会把数据路由到不到的分片上。而且如果动态的往集群中增加分片,也不会影响Jedis的功能。究竟是怎么做到的呢?
由于最近公司要集中迁移redis集群,也就是把旧集群的数据迁移到Redis Cluster中,就需要我们自己来整理数据。刚好我这里有个库存热点数据,我们叫做A吧,这个A在Redis集群中,每个分片上都有数据。比如,Redis集群有4个片,而我总库存量为1000,那么会在4个片上放上Key A,每个A中库存量为250.
新的Redis cluster,为了防止热点库存问题,也就申请了4个cluster,每个cluster相当于之前的一个分片。数据在写入的时候,每个cluster会写一个key A,库存量为250.
现在问题来了,有一些Key,比如说B,在原来的Redis集群中,是利用Jedis路由来导向某一片写入的,假设这里写入的是第3片。如果迁移到新的4个Redis cluster中,势必需要写到第三个Redis Cluster中。因为数据迁移,肯定是第一片redis数据迁移到第一个Cluster,第二片redis数据迁移到第二个Cluster,以此类推。
所以这里需要我们来实现和Jedis一样的路由算法,按照Jedis提供的类,我们实现如下:
首先,定义好ShardNode,继承自Jedis的ShardInfo:
public class ShardNode implements ShardInfo { public ShardNode(String index, Cluster cluster) {
this.index = index;
this.cluster = cluster;
} private String index; private Cluster cluster; @Override
public int getWeight() {
return 1;
} @Override
public String getName() {
return null;
} public Cluster getCluster() {
return cluster;
} public void setCluster(Cluster cluster) {
this.cluster = cluster;
} public String getIndex() {
return index;
} public void setIndex(String index) {
this.index = index;
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
注意,getName方法里面一定要return null, 这样就会根据配置的分片的数量先后顺序来运算哈希key。具体源码如下(翻看KetamaHashing类的源码):
protected void initialize(List<T> shards) {
Charset charset = Charset.forName("utf-8");
String key = null; for(int i = 0; i < shards.size(); ++i) {
T shardInfo = (ShardInfo)shards.get(i);
if (shardInfo == null) {
throw new IllegalArgumentException("shard element #" + i + " is null.");
} AtomicReference<T> wrapper = new AtomicReference(shardInfo);
this.originals.add(wrapper); for(int n = 0; n < 160 * shardInfo.getWeight(); ++n) {
if (shardInfo.getName() == null) {
key = "SHARD-" + i + "-NODE-" + n;
} else {
key = shardInfo.getName() + "*" + shardInfo.getWeight() + n;
} this.nodes.put(this.algo.hash(key.getBytes(charset)), wrapper);
}
} }
注意我标黄颜色部分,正式因为shardInfo.getName为null,所以我们的路由算法才能够按照配置的分片顺序进行路由。
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
然后进行实现即可:
public Cluster getCluster(String key) {
KetamaHashing ketamaHashing = new KetamaHashing(shardNodes, new MurmurHash());
ShardNode shard = (ShardNode) ketamaHashing.getShardInfo(key.getBytes());
return shard.getCluster();
}
这样我们就可以通过key来获取新的Redis Cluster实例了。通过测试用例结果,我们也可以看出Jedis路由算法和我们所写的路由算法是一致的。
@Test
public void testJedisHash() { Map<String, String> map = new HashMap<>();
map.put("192.168.155.84:6379", "0");
map.put("192.168.155.84:6390", "1");
map.put("192.168.155.85:6379", "2");
map.put("192.168.155.85:6390", "3"); String key;
List<String> list = new ArrayList<>(); for (int i = 0; i < 1000; i++) { key = UUID.randomUUID().toString(); ShardNode cluster = storeJimdbs.getShardNode(key); ShardInfo redisShard = jrc.getShardInfo(key);
String shardKey = redisShard.toString().split("/")[0]; if (cluster.getIndex().equals(map.get(shardKey))) {
list.add("OK");
} else {
System.out.println("NNNNNNNotMatch!!!!!!!");
}
} System.out.println(list.size());
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
最后运算出来的结果是1000,也就是说1000个随机key,利用Jedis路由算法操作,利用我们写的路由算法操作,其实是打到相同的分片序号上的。
也就是0号分片对应0号cluster。
Jedis路由key的算法剥离的更多相关文章
- 基于SNMP的路由拓扑发现算法收集
一.三层(网络层)发现 算法来源:王娟娟.基于SNMP的网络拓扑发现算法研究.武汉科技大学硕士学位论文,2008 数据结构: 待检路由设备网关链表:存放指定深度内待检路由设备的网关信息,处理后删除. ...
- key寻址算法
分布式寻址算法 hash 算法(大量缓存重建) 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡) redis cluster 的 hash slot 算法 hash 算法 来了一个 ...
- 用Jedis操作redis示例一,Key,value HashMap
简单的key,value形式 public class RedisDemo { public static void main(String[] args) { Jedis jedis = new J ...
- jedis连接池详解(Redis)
转自:http://tianxingzhe.blog.51cto.com/3390077/1684306 原子性(atomicity): 一个事务是一个不可分割的最小工作单位,事务中包括的诸操作要么都 ...
- 超大批量删除redis中无用key+配置
目前线上一个单实例redis中无用的key太多,决定删除一部分. 1.删除指定用户的key,使用redis的pipeline 根据一定条件把需要删除的用户统计出来,放到一个表里面,表为 del_use ...
- _00013 一致性哈希算法 Consistent Hashing 新的讨论,并出现相应的解决
笔者博文:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前.妳却感觉不到我的存在 技术方向: ...
- Jedis使用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】(转)
前段时间细节的了解了Jedis的使用,Jedis是redis的java版本的客户端实现.本文做个总结,主要分享如下内容: [pipeline][分布式的id生成器][分布式锁[watch][multi ...
- RabbitMQ之路由(Routing)【译】
在上一节中,我们创建了一个简单的日志系统,可以广播消息到很多接收者. 这一节,我们将在上一节的基础上加一个功能--订阅部分消息.例如,我们只将严重错误信息写入到日志文件保存在磁盘上,同时我们能将所有的 ...
- 一致性hash与CRUSH算法总结
相同之处:都解决了数据缓存系统中数据如何存储与路由. 不同之处:区别在于虚拟节点和物理节点的映射办法不同 由于一般的哈希函数返回一个int(32bit)型的hashCode.因此,可以将该哈希函数能够 ...
随机推荐
- vue用hbuilderX打包app嵌入h5方式云打包和遇到的问题
vue用hbuilderX打包app嵌入h5方式云打包和遇到的问题 vue用hbuilderX打包app就可以了,不过有兼容性问题,转换rem的用不了,嵌入到app的webview里面变得很小了,另外 ...
- workbench使用小笔记(不定期持续更新)
1. 删除不使用的工作空间 在使用workbench时,之前可能建了好几个工作空间,现在有一些不使用了,每次打开都能还能看到它们,对于强迫症来说多少有一些不爽.如下图: 现在,就把那些不使用的工作空间 ...
- 用java实现操作两个数据库的数据
1.首先需要在jdbc的配置文件里面配置两个数据库的连接 数据库1的配置 driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://地址:3306/数 ...
- vue脚手架3
跟脚手架2安装都一样,已经安装脚手架2的要执行下面的命令 ,先删除 npm uninstall vue-cli -g 或 yarn global remove vue-cli 卸载 在执行下面的命令 ...
- iOS进阶之TCP代理鉴权过程
这段时间接触了网络代理,而自己的任务是完成TCP和UDP的网络代理,所以在这里写些自己的理解吧. 这篇文章先介绍一下TCP代理的鉴权过程(采用的是用户名和密码鉴权),下一篇文章再介绍UDP代理的鉴权过 ...
- [C++ Primer Plus] 第10章、对象和类(一)程序清单——辨析三个const
程序清单10.1+10.2+10.3 头文件stock.h #ifndef STOCK00_H_ //先测试x是否被宏定义过 #define STOCK00_H_ //如果没有宏定义,就宏定义x并编译 ...
- 常用sql语句总结(一)(查询)
常用sql语句总结(一)(查询) 数据操作语句:DML 数据定义语句:DDL 数据控制语句:DCL (执行顺序------序号) 一.基本查询: 1. SELECT * ----- 2 FROM 数据 ...
- 浅谈Vue之双向绑定
VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的.那么Object.defineP ...
- Matlab 将两个图像进行分离 已知其中一个图像
5.下图(a)是一幅两个灰度图像合成的图像,已知其中一幅图像如图(b)所示,试把另一幅图像提取出来,并显示. 运用减法做 %加载入要处理的图片 A=imread('a.png'); %将I变为[0,1 ...
- 我的第一篇博客。(JavaScript的声明和数据类型的一些笔记)
这是我的第一篇博客,务必请大家多多关照. 下面是前端js的变量和数据类型的一些笔记,不是很全请多多包涵. 1.变量 变量的声明 var 变量名 变量这个容器中放的是数据 变量的赋值 变量名 = 数据 ...