Sharded数据分片定位数据
因为每个片是单独的主服务器,分片有一些限制的功能:例如,不能使用事务,pipelining,发布/订阅。然而,通常这些不允许的操作是可行的,只要关心keys在一个相同的片。更进一步的缺点是当前标准实现,在运行中的ShardedJedis不能添加或者移除片。如果需要这个特性,需要重现实现ShardedJedis,允许在一个运行ShardedJedis动态的添加和移除片:yaourt - dynamic sharding implementation
Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网 客户端列表 。当业务的数据量非常庞大时,需要考虑将数据存储到多个缓存节点上,如何定位数据应该存储的节点,一般用的是一致性哈希算法。Jedis在客户端角度实现了一致性哈希算法,对数据进行分片,存储到对应的不同的redis实例中。
Jedis对Sharded的实现主要是在 ShardedJedis.java 和 ShardedJedisPool.java 中。本文主要介绍ShardedJedis的实现,ShardedJedisPool是基于apache的common-pool2的对象池实现。
继承关系:
ShardedJedis--->BinaryShardedJedis--->Sharded <Jedis, JedisShardInfo>
构造函数
查看其构造函数
javapublic ShardedJedis(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
super(shards, algo, keyTagPattern);
}
构造器参数解释:
shards是一个JedisShardInfo的列表,一个JedisShardedInfo类代表一个数据分片的主体。
algo是用来进行数据分片的算法
keyTagPattern,自定义分片算法所依据的key的形式。例如,可以不针对整个key的字符串做哈希计算,而是类似对 thisisa{key} 中包含在大括号内的字符串进行哈希计算。
JedisShardInfo 是什么样的?
javapublic classJedisShardInfo extends ShardInfo<Jedis> {public String toString() {
return host + ":" + port + "*" + getWeight();
} privateint connectionTimeout;
privateint soTimeout;
private String host;
privateint port;
private String password = null;
private String name = null;
// Default Redis DBprivateint db = 0; public String getHost() {
return host;
} publicint getPort() {
return port;
} public JedisShardInfo(String host) {
super(Sharded.DEFAULT_WEIGHT);
URI uri = URI.create(host);
if (JedisURIHelper.isValid(uri)) {
this.host = uri.getHost();
this.port = uri.getPort();
this.password = JedisURIHelper.getPassword(uri);
this.db = JedisURIHelper.getDBIndex(uri);
} else {
this.host = host;
this.port = Protocol.DEFAULT_PORT;
}
} public JedisShardInfo(String host, String name) {
this(host, Protocol.DEFAULT_PORT, name);
} public JedisShardInfo(String host, int port) {
this(host, port, 2000);
} public JedisShardInfo(String host, int port, String name) {
this(host, port, 2000, name);
} public JedisShardInfo(String host, int port, int timeout) {
this(host, port, timeout, timeout, Sharded.DEFAULT_WEIGHT);
} public JedisShardInfo(String host, int port, int timeout, String name) {
this(host, port, timeout, timeout, Sharded.DEFAULT_WEIGHT);
this.name = name;
} public JedisShardInfo(String host, int port, int connectionTimeout, int soTimeout, int weight) {
super(weight);
this.host = host;
this.port = port;
this.connectionTimeout = connectionTimeout;
this.soTimeout = soTimeout;
} public JedisShardInfo(String host, String name, int port, int timeout, int weight) {
super(weight);
this.host = host;
this.name = name;
this.port = port;
this.connectionTimeout = timeout;
this.soTimeout = timeout;
} public JedisShardInfo(URI uri) {
super(Sharded.DEFAULT_WEIGHT);
if (!JedisURIHelper.isValid(uri)) {
thrownew InvalidURIException(String.format(
"Cannot open Redis connection due invalid URI. %s", uri.toString()));
} this.host = uri.getHost();
this.port = uri.getPort();
this.password = JedisURIHelper.getPassword(uri);
this.db = JedisURIHelper.getDBIndex(uri);
} @Override
public Jedis createResource() {
returnnew Jedis(this);
}
/**
* 省略setters和getters
**/
}
可见JedisShardInfo包含了一个redis节点ip地址,端口号,name,密码等等相关信息。要构造一个ShardedJedis,提供一个或多个JedisShardInfo。
最终构造函数的实现在其父类 Sharded 里面
javapublic Sharded(List<S> shards, Hashing algo, Pattern tagPattern) {
this.algo = algo;
this.tagPattern = tagPattern;
initialize(shards);
}
哈希环的初始化
Sharded类里面维护了一个TreeMap,基于红黑树实现,用来盛放经过一致性哈希计算后的redis节点,另外维护了一个LinkedHashMap,用来保存ShardInfo与Jedis实例的对应关系。
定位的流程如下
先在TreeMap中找到对应key所对应的ShardInfo,然后通过ShardInfo在LinkedHashMap中找到对应的Jedis实例。
Sharded类对这些实例变量的定义如下所示:
javapublic staticfinalint DEFAULT_WEIGHT = 1;
private TreeMap<Long, S> nodes;
privatefinal Hashing algo;
privatefinal Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>(); /**
* The default pattern used for extracting a key tag. The pattern must have
* a group (between parenthesis), which delimits the tag to be hashed. A
* null pattern avoids applying the regular expression for each lookup,
* improving performance a little bit is key tags aren't being used.
*/private Pattern tagPattern = null;
// the tag is anything between {}publicstaticfinal Pattern DEFAULT_KEY_TAG_PATTERN = Pattern.compile("\\{(.+?)\\}");
接下来看其构造函数中的initialize方法
javaprivate void initialize(List<S> shards) {
nodes = new TreeMap<Long, S>();
for (int i = 0; i != shards.size(); ++i) {
final S shardInfo = shards.get(i);
if (shardInfo.getName() == null)
for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n), shardInfo);
}
elsefor (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(
this.algo.hash(shardInfo.getName() + "*"
+ shardInfo.getWeight() + n), shardInfo);
}
resources.put(shardInfo, shardInfo.createResource());
}
}
可以看到,它对每一个ShardInfo通过一定规则计算其哈希值,然后存到TreeMap中,这里它实现了一致性哈希算法中虚拟节点的概念,因为我们可以看到同一个ShardInfo不止一次被放到TreeMap中,数量是,权重*160。增加了虚拟节点的一致性哈希有很多好处,能避免数据在redis节点间分布不均匀。
然后,在LinkedHashMap中放入ShardInfo以及其对应的Jedis实例,通过调用其自身的createSource()来得到jedis实例。
数据定位
从ShardedJedis的代码中可以看到,无论进行什么操作,都要先根据key来找到对应的Redis,然后返回一个可供操作的Jedis实例。
例如其set方法:
javapublic String set(String key, String value) {
Jedis j = getShard(key);
return j.set(key, value);
}
而getShard方法则在Sharded.java中实现,其源代码如下所示:
javapublic R getShard(byte[] key) {
return resources.get(getShardInfo(key));
}
public R getShard(String key) {
return resources.get(getShardInfo(key));
}
public S getShardInfo(byte[] key) {
SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
if (tail.isEmpty()) {
return nodes.get(nodes.firstKey());
}
return tail.get(tail.firstKey());
}
public S getShardInfo(String key) {
return getShardInfo(SafeEncoder.encode(getKeyTag(key)));
}
可以看到,先通过getShardInfo方法从TreeMap中获得对应的ShardInfo,然后根据这个ShardInfo就能够再LinkedHashMap中获得对应的Jedis实例了。
Sharded数据分片定位数据的更多相关文章
- 《大数据日知录》读书笔记-ch1数据分片与路由
目前主流大数据存储使用横向扩展(scale out)而非传统数据库纵向扩展(scale up)的方式.因此涉及数据分片.数据路由(routing).数据一致性问题 二级映射关系:key-partiti ...
- 数据库_数据分片与mycat服务
1.数据分片; 2.部署mycat服务;3.基于mycat服务创建新库新表. 一,数据分片 1.数据分片,也叫分库分表,即将存放在一台数据库服务器中的数据,按照特定方式进行拆分,分散存放到其它多台服务 ...
- elasticsearch6 学习之数据分片
ES: ElasticSearch(简称ES):是一个基于Lucene构建的开源.分布式.RESTful的全文本搜索引擎:它还是一个分布式实时文档存储,其中每个field均是被索引的数据且可被搜索:也 ...
- 26. ClustrixDB 分布式架构/数据分片
数据分片 介绍 共享磁盘vs.无共享 分布式数据库系统可分为两大类数据存储架构:(1)共享磁盘和(2)无共享. Shared Disk Architecture Shared Nothing Arch ...
- MongoDB分片之数据分割方式
随着移动互联网的发展,大量的非结构化数据随之产生,不仅对数据库存储大数据提出了新的要求,同时对于查询数据和进行大数据分析也提出了苛刻的要求,这些显然是单服务器处理能力无法满足的,自然建立一个集群是不可 ...
- MyCat 学习笔记 第十二篇.数据分片 之 分片事务处理
1 环境说明 VM 模拟3台MYSQL 5.6 服务器 VM1 192.168.31.187:3307 VM2 192.168.31.212:3307 VM3 192.168.31.150: 330 ...
- MyCat 学习笔记 第十篇.数据分片 之 ER分片
1 应用场景 这篇来说下mycat中自带的er关系分片,所谓er关系分片即可以理解为有关联关系表之间数据分片.类似于订单主表与订单详情表间的分片存储规则. 本文所说的er分片分为两种: a. 依据主键 ...
- MyCat 学习笔记 第九篇.数据分片 之 数值分布
1 应用场景 Mycat 自带了多套数据分片的机制,其实根据数值分片也是比较简单,其实这个和数据取摸是类似的实现. 优.缺点同上一篇 2 环境说明 参考 <MyCat 学习笔记>第六篇. ...
- MyCat 学习笔记 第八篇.数据分片 之 求摸运算分片
1 应用场景 Mycat 自带了多套数据分片的机制,其实根据数值取摸应该是最简单的一种. 优点:数据离散概率较为平均,可以有效的提高应用的数据吞吐. 缺点:比较明显,后期数据运维与迁移比较困难.好在M ...
随机推荐
- react-native 中使用redux 优化 Connect 使用装饰器简化代码报错
报错信息 error: bundling failed: Error: The 'decorators' plugin requires a 'decoratorsBeforeExport' opti ...
- python函数回顾:hex()
描述 hex() 函数用于将10进制整数转换成16进制,以字符串形式表示. 语法 hex 语法: hex(x) 参数说明: x -- 10进制整数 返回值 返回16进制数,以字符串形式表示. 实例 & ...
- 获取JDBC响应做接口关联
1:从sql表中将需要取的数据查出来 2:我们需要把这个id为4451的数据从sql里面取出来,传到下一个sql里面,执行删除 3:写一个接口的传参有些不同,变成了var_id_1.var_id是之前 ...
- 20170405-STO库存转储单
1.工厂间转储: (1)MB1B 移动类型 301 工厂到工厂(一步)转账,->简单明了一步转储过账后会产生 GR,MITA增加了,MIZH减少了,MB03, **会产生 GR,如果俩工厂 标准 ...
- windows下python调用c文件流程
1.新建fun.c文件和fun.h文件 #include <stdio.h> #include <stdlib.h> #include <string.h> int ...
- [笔记]如何将传统的回调函数转换为C#5.0支持的await格式
C#5.0引入了编译器支持的 async 和 await 关键字,这就为开发者提供了使用同步思想写异步代码的方便. 但是有些传统函数仅提供了异步回调实现,如何对其封装,使其可以享受await的便利呢? ...
- selection createTextRange setSelectionRange
http://www.cnblogs.com/rainman/archive/2011/02/27/1966482.html http://www.zhangxinxu.com/wordpress/2 ...
- pyhton3 logging模块
1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message')logging.info('This is info mess ...
- 前端之 Ajax(补)
概述 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操作需要 ...
- 面向服务体系架构(SOA)和数据仓库(DW)的思考
摘要: 当前业界对面向服务体系架构(SOA)和数据仓库(Data Warehouse,DW)都介绍的很多,提出了很多优秀的解决方案,但是一般是把 SOA 和 DW 单独考虑,SOA 和 DW 有着共同 ...