概述
Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网客户端列表。当业务的数据量非常庞大时,需要考虑将数据存储到多个缓存节点上,如何定位数据应该存储的节点,一般用的是一致性哈希算法。Jedis在客户端角度实现了一致性哈希算法,对数据进行分片,存储到对应的不同的redis实例中。
Jedis对Sharded的实现主要是在ShardedJedis.java
和ShardedJedisPool.java
中。本文主要介绍ShardedJedis的实现,ShardedJedisPool是基于apache的common-pool2的对象池实现。
继承关系
ShardedJedis--->BinaryShardedJedis--->Sharded <Jedis, JedisShardInfo>
构造函数
查看其构造函数
public ShardedJedis(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
super(shards, algo, keyTagPattern);
}
构造器参数解释:
-
shards是一个JedisShardInfo的列表,一个JedisShardedInfo类代表一个数据分片的主体。
-
algo是用来进行数据分片的算法
-
keyTagPattern,自定义分片算法所依据的key的形式。例如,可以不针对整个key的字符串做哈希计算,而是类似对thisisa{key}中包含在大括号内的字符串进行哈希计算。
JedisShardInfo
是什么样的?
public class JedisShardInfo extends ShardInfo<Jedis> {
public String toString() {
return host + ":" + port + "*" + getWeight();
}
private int connectionTimeout;
private int soTimeout;
private String host;
private int port;
private String password = null;
private String name = null;
// Default Redis DB
private int db = 0;
public String getHost() {
return host;
}
public int 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)) {
throw new 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() {
return new Jedis(this);
}
/**
* 省略setters和getters
**/
}
可见JedisShardInfo包含了一个redis节点ip地址,端口号,name,密码等等相关信息。要构造一个ShardedJedis,提供一个或多个JedisShardInfo。
最终构造函数的实现在其父类Sharded
里面
public 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类对这些实例变量的定义如下所示:
public static final int DEFAULT_WEIGHT = 1;
private TreeMap<Long, S> nodes;
private final Hashing algo;
private final 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 {}
public static final Pattern DEFAULT_KEY_TAG_PATTERN = Pattern.compile("\\{(.+?)\\}");
接下来看其构造函数中的initialize方法
private 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);
}
else
for (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方法:
public String set(String key, String value) {
Jedis j = getShard(key);
return j.set(key, value);
}
而getShard方法则在Sharded.java中实现,其源代码如下所示:
public 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实例了。
相关推荐
这个压缩包文件"jedis-master"很可能包含了Jedis的完整源代码,包括测试用例,是学习Jedis的绝佳资源。 1. **Jedis基本使用**: Jedis的使用通常始于创建Jedis实例,通过连接池管理连接。在源码中,你可以看到`...
jedis 2.9jar包括源代码及common-pool 下面是官方地址,不用积分: https://github.com/xetorthio/jedis http://mvnrepository.com/artifact/redis.clients/jedis/2.9.0
本文将深入探讨如何使用Jedis进行Redis操作,并通过具体的代码示例来详细解析其API的使用。 首先,我们需要了解如何添加Jedis依赖到项目中。如果你使用的是Maven,可以在pom.xml文件中添加以下依赖: ```xml ...
在“spring-data集成jedis测试代码”中,我们可以期待看到如何配置Spring Data Redis来使用Jedis客户端。这通常涉及以下步骤: 1. 添加Jedis和Spring Data Redis依赖到项目构建文件(如pom.xml或build.gradle)。 2....
Jedis是redis的java版本的客户端实现,使用Jedis提供的Java API对Redis进行操作,是Redis官方推崇的方式;并且,使用Jedis提供的对Redis的支持也最为灵活、全面;不足之处,就是编码复杂度较高。
java源代码(基于spring-boot)工程介绍:(Jedis存取redis的测试)1、直接连接redis,通过jedis实例直接连接redis,并存入和获取数据2、连接池JedisPool方式连接redis,通过连接池连接redis,可配置最大连接数、...
3. **jedis-3.0.0-sources.jar**:这个文件包含了Jedis库的源代码,对于想要深入理解Jedis内部实现或者进行二次开发的开发者来说,这是一个非常宝贵的资源。通过阅读源代码,可以了解Jedis如何封装Redis协议,如何...
以下是一些基本操作的代码示例: ```java import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; // 创建JedisPoolConfig对象,设置连接池参数 JedisPoolConfig poolConfig = ...
* redis主从架构的jedis客户端管理类,大概1000行代码左右 * 1 支持主从复制key/value,pop/push,pub/sub,读/写分离等功能的灾难失败自动选择和恢复 * 2 可以选择读写分离功能,主写从读,默认不启用,都使用主服务进行...
赠送源代码:jedis-2.9.0-sources.jar; 包含翻译后的API文档:jedis-2.9.0-javadoc-API文档-中文(简体)版.zip 对应Maven信息:groupId:redis.clients,artifactId:jedis,version:2.9.0 使用方法:解压翻译后...
https://github.com/xetorthio/jedis 开源Redis java client jedis源代码编译后的jar 文件.
赠送源代码:jedis-3.6.0-sources.jar; 赠送Maven依赖信息文件:jedis-3.6.0.pom; 包含翻译后的API文档:jedis-3.6.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:redis.clients:jedis:3.6.0; 标签:redis、...
然后,通过以下Java代码创建Jedis实例并执行操作: ```java import redis.clients.jedis.Jedis; public class RedisSingleNodeExample { public static void main(String[] args) { Jedis jedis = new Jedis(...
这个压缩包包含了Jedis的核心组件,即`jedis-3.0.0.jar`,以及源代码文件`jedis-3.0.0-sources.jar`和API文档`jedis-3.0.0-javadoc.jar`,对于开发者来说,这是一份非常全面的学习和开发资源。 首先,`jedis-3.0.0....
3. `jedis-2.9.0-sources.jar`:这个文件包含了Jedis的源代码,开发者可以查看源码来理解Jedis的工作原理,对于学习、调试和贡献代码非常有帮助。 Jedis的主要特性包括: - 连接管理:支持连接池,可配置连接超时...
**Jedis:Redis的Java客户端** Jedis是Java开发者用于操作Redis数据库的一个高效、轻量级的客户端。Redis是一款开源的、高性能的键值存储系统,常被用作数据缓存、消息中间件以及数据库。Jedis提供了丰富的API,...
描述中提到"可用于编写jedis demo",这意味着这个jar包可以用来创建和运行Jedis的示例代码,帮助开发者理解和学习如何使用Jedis进行数据操作。Jedis支持的操作包括但不限于连接管理、字符串操作、哈希处理、列表操作...
在这个压缩包"jedis-jedis-2.8.2.tar.gz"中,包含了Jedis库的源代码、文档和其他相关资源。 首先,让我们深入理解Redis。Redis是一个开源的、基于键值对的数据存储系统,通常用作数据库、缓存和消息中间件。它以其...
这个压缩包"jedis-jedis-1.5.0-RC1.tar.gz"包含了Jedis 1.5.0 Release Candidate 1版本的源代码和相关资源。在本文中,我们将深入探讨Jedis的功能、特性以及如何使用它来操作Redis。 首先,Jedis作为Redis的Java...
Jedis是Java开发的一款高效、轻量级的Redis客户端,专为处理Redis数据库服务而设计。Redis是一款开源的、高性能的键值存储系统,常用于数据缓存、消息队列、分布式锁等场景。Jedis提供了丰富的API,使得开发者能够...