赞
踩
Redis作为目前通用的缓存选型,因其高性能而倍受欢迎。Redis的2.x版本仅支持单机模式,从3.0版本开始引入集群模式。
Redis的Java生态的客户端当中包含Jedis、Redisson、Lettuce,不同的客户端具备不同的能力是使用方式,本文主要分析Jedis客户端。
Jedis客户端同时支持单机模式、分片模式、集群模式的访问模式,通过构建Jedis类对象实现单机模式下的数据访问,通过构建ShardedJedis类对象实现分片模式的数据访问,通过构建JedisCluster类对象实现集群模式下的数据访问。
Jedis客户端支持单命令和Pipeline方式访问Redis集群,通过Pipeline的方式能够提高集群访问的效率。
本文的整体分析基于Jedis的3.5.0版本进行分析,相关源码均参考此版本。
Jedis客户端操作Redis主要分为三种模式,分表是单机模式、分片模式、集群模式。
单机模式不涉及任何分片的思想,所以我们着重分析分片模式和集群模式的理念。
分片模式的整体应用如下图所示,核心在于客户端的一致性Hash策略。
集群模式本质属于服务器分片技术,由Redis集群本身提供分片功能,从Redis 3.0版本开始正式提供。
集群的原理是:一个 Redis 集群包含16384 个哈希槽(Hash slot), Redis保存的每个键都属于这16384个哈希槽的其中一个, 集群使用公式CRC16(key)%16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键key的CRC16校验和 。
集群中的每个节点负责处理一部分哈希槽。举个例子, 一个集群可以有三个哈希槽, 其中:
Redis在集群模式下对于key的读写过程首先将对应的key值进行CRC16计算得到对应的哈希值,将哈希值对槽位总数取模映射到对应的槽位,最终映射到对应的节点进行读写。以命令set("key", "value")为例子,它会使用CRC16算法对key进行计算得到哈希值28989,然后对16384进行取模得到12605,最后找到12605对应的Redis节点,最终跳转到该节点执行set命令。
集群模式的整体应用如下图所示,核心在于集群哈希槽的设计以及重定向命令。
(引用自:www.jianshu.com)
- // Jedis单机模式的访问
- public void main(String[] args) {
- // 创建Jedis对象
- jedis = new Jedis("localhost", 6379);
- // 执行hmget操作
- jedis.hmget("foobar", "foo");
- // 关闭Jedis对象
- jedis.close();
- }
-
- // Jedis分片模式的访问
- public void main(String[] args) {
- HostAndPort redis1 = HostAndPortUtil.getRedisServers().get(0);
- HostAndPort redis2 = HostAndPortUtil.getRedisServers().get(1);
- List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(2);
- JedisShardInfo shard1 = new JedisShardInfo(redis1);
- JedisShardInfo shard2 = new JedisShardInfo(redis2);
- // 创建ShardedJedis对象
- ShardedJedis shardedJedis = new ShardedJedis(shards);
- // 通过ShardedJedis对象执行set操作
- shardedJedis.set("a", "bar");
- }
-
- // Jedis集群模式的访问
- public void main(String[] args) {
- // 构建redis的集群池
- Set<HostAndPort> nodes = new HashSet<>();
- nodes.add(new HostAndPort("127.0.0.1", 7001));
- nodes.add(new HostAndPort("127.0.0.1", 7002));
- nodes.add(new HostAndPort("127.0.0.1", 7003));
-
- // 创建JedisCluster
- JedisCluster cluster = new JedisCluster(nodes);
-
- // 执行JedisCluster对象中的方法
- cluster.set("cluster-test", "my jedis cluster test");
- String result = cluster.get("cluster-test");
- }
Jedis通过创建Jedis的类对象来实现单机模式下的数据访问,通过构建JedisCluster类对象来实现集群模式下的数据访问。
要理解Jedis的访问Redis的整个过程,可以通过先理解单机模式下的访问流程,在这个基础上再分析集群模式的访问流程会比较合适。
Jedis访问单机模式Redis的整体流程图如下所示,从图中可以看出核心的流程包含Jedis对象的创建以及通过Jedis对象实现Redis的访问。
熟悉Jedis访问单机Redis的过程,本身就是需要了解Jedis的创建过程以及执行Redis命令的过程。
Jedis本身的类关系图如下图所示,从图中我们能够看到Jedis继承自BinaryJedis类。
在BinaryJedis类中存在和Redis对接的Client类对象,Jedis通过父类的BinaryJedis的Client对象实现Redis的读写。
Jedis类在创建过程中通过父类BinaryJedis创建了Client对象,而了解Client对象是进一步理解访问过程的关键。
- public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommands,
- AdvancedJedisCommands, ScriptingCommands, BasicCommands, ClusterCommands, SentinelCommands, ModuleCommands {
-
- protected JedisPoolAbstract dataSource = null;
-
- public Jedis(final String host, final int port) {
- // 创建父类BinaryJedis对象
- super(host, port);
- }
- }
-
- public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKeyBinaryCommands,
- AdvancedBinaryJedisCommands, BinaryScriptingCommands, Closeable {
-
- // 访问redis的Client对象
- protected Client client = null;
-
- public BinaryJedis(final String host, final int port) {
- // 创建Client对象访问redis
- client = new Client(host, port);
- }
- }
Client类的类关系图如下图所示,Client对象继承自BinaryClient和Connection类。在BinaryClient类中存在Redis访问密码等相关参数,在Connection类在存在访问Redis的socket对象以及对应的输入输出流。本质上Connection是和Redis进行通信的核心类。
Client类在创建过程中初始化核心父类Connection对象,而Connection是负责和Redis直接进行通信。
p
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。