jedis 调用模式

1. jedis对应redis的四种工作模式

image.png

       图1-1是Jedis的主要模块,Jedis,JedisCluster,JedisSentinel和ShardedJedis对应了Redis的四种工作模式:Redis Standalone(单节点模式),Redis Cluster(集群模式),Redis Sentinel(哨兵模式)和Redis Sharding(分片模式)。

2. jedis的三种请求模式

      每个jedis实例对应一个Redis节点,我们对jedis实例的每个操作,都相当于redis-cli启动客户端的直接操作,无论是集群模式,哨兵模式,还是分片模式,内部均为对Jedis实例的操作,所以了解jedis类的内部结构以及jedis实例的请求模式是掌握jedis框架的基础。
​        Jedis实例有3种请求模式,Pipeline,Transaction和Client。


image.png

       jedis实例通过Socket建立客户端与服务端的长连接,往outputStream发送命令,从inputStream读取回复。
       Client模式就是常用的所见即所得,客户端发送一个命令,阻塞等待服务端执行,然后读取返回结果。
       Pipeline模式是一次性发送多个命令,最后一次取回所有的返回结果,这种模式通过减少网络的往返时间和io读写次数,大幅度提高通信性能,但pipeline不支持原子性,要想保证原子性,可同时开启事物模式。
       Transaction模式即开启Redis的事务管理,事务模式开启后,所有的命令(除了exec,discard,multi和watch)到达服务端以后不会立即执行,会进入一个等待队列,等待收到下述四个命令时执行不同操作:

  1. EXEC命令执行时,服务器以先进先出FIFO的方式执行事务队列中的命令,当事务队列的所有命令被执行完之后,将回复队列作为自己的执行结果返回给客户端,客户端从事务状态返回到非事务状态。
  2. DISCARD命令用于取消一个事务,它清空客户端的整个事务队列,然后将客户端从事务状态调整到非事务状态。最后返回字符串 OK 给客户端, 说明事务已被取消。
  3. Redis 的事务是不可嵌套的, 当客户端已经处于事务状态, 而客户端又再向服务器发送MULTI时, 服务器只是简单地向客户端发送一个错误, 然后继续等待其他命令的入队。 MULTI命令的发送不会造成整个事务失败, 也不会修改事务队列中已有的数据。
  4. WATCH只能在客户端进入事务状态之前执行, 在事务状态下发送 WATCH命令会引发一个错误, 但它不会造成整个事务失败, 也不会修改事务队列中已有的数据(和前面处理 MULTI的情况一样)。

2 jedis的类结构

image.png

jedis以输入的命令参数是否为二进制,将处理请求的具体实现部署在两个类中,Jedis和BinaryJedis, Client和BinaryClient。与Redis服务器的连接信息(Socket,host, port)封装在Client的基类Connection中,BinaryJedis类中提供了Client,Pipeline和Transaction变量,对应三种请求模式。

3. jedis的初始化流程

Jedis jedis = new Jedis("localhost", 6379, 15000);
Transaction t = jedis.multi();
Pipeline pipeline = jedis.pipelined();

​ Jedis通过传入Redis服务器地址(host,port)开始初始化,然后在BinaryJedis里实例化Client。Client通过Socket维持客户端与Redis服务器的连接与沟通。
Transaction和Pipeline很相似,他们继承同一个基类MultiKeyPipelineBase。区别在于Transaction在实例化的时候,会自动发送MULTI命令,开启事务模式,而Pipeline则按情况手动开启,他们都是依靠Client发送命令,下面通过发送一个get key的命令,看看这三种模式是如何运转的。

//BinaryJedis类
public Transaction multi() {
client.multi();
transaction = new Transaction(client);
return transaction;
}
public Pipeline pipelined() {
pipeline = new Pipeline();
pipeline.setClient(client);
return pipeline;
}

4. jedis工作模式的调用流程

4.1 Client模式的调用流程:
image.png

image.png

从上图可以看出,在每次发送命令之前,会先通过connect()方法判断是否已经连接,如果未连接则:

  1. 实例化Socket,并配置
  2. 连接Socket,获取OutputStream和InputStream
  3. 如果是SSL连接,通过SSLSocketFactory创建socket连接
          Protocol是一个通讯工具类,将Redis的各类执行关键字存储为静态变量,比如Protocol.Command.GET, 同时将命令包装成符合Redis的统一请求协议,回复消息的处理也是在这个类进行,它先通过通讯协议提取出当次请求的回复消息,将Object类型的消息转化为String,List 等具体类型,如果回复消息有Error则以异常的形式抛出。
4.2 pipeline调用模式
4.2.1 为什么会出现Pipeline?

      Redis本身是基于Request/Response协议的,正常情况下,客户端发送一个命令,等待Redis应答,Redis在接收到命令,处理后应答。在这种情况下,如果同时需要执行大量的命令,那就是等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁的调用系统IO,发送网络请求。


image.png

      为了提升效率,这时候Pipeline出现了,它允许客户端可以一次发送多条命令,而不等待上一条命令执行的结果,这和网络的Nagel算法有点像(TCP_NODELAY选项)。不仅减少了RTT,同时也减少了IO调用次数(IO调用涉及到用户态到内核态之间的切换)。


image.png
4.2.2 pipeline详解
image.png

    上图为Transaction和Pipeline两个类的类结构,可以看到Pipeline和Transaction都继承MultikeyPipelineBase,其中,MultiKeyPipelineBase和PipelineBase的区别在于处理的命令不同,内部均调用Client发送命令,Pipeline有一个内部类对象MultiResponseBuilder,当Pipeline开启事务后,其用于存储所有返回结果。Queable用一个LinkedList装入每个命令的返回结果,Response<T>是一个泛型,set(Object data)方法传入格式化之前的结果,get()方法返回格式化之后的结果。


image.png

    上图显示了Pipeline从发送请求到读取回复的具体实现,Pipeline通过Client发送命令(这时并未真正地发送命令,只是将命令放入了缓冲区,缓冲区大小为8192byte, 超过这个大小会自动将缓冲区的命令输出到服务端),Client在sendCommand时,会同时执行pipelinedCommands++,记录发送命令的条数。之后,返回一个Response<T>实例,并将这个实例塞入了pipelinedResponses队列中。Response<T>主要有3个属性:

  1. 格式化前的回复消息data,
  2. 格式化后的回复消息response,
  3. 格式化方式builder。
        刚发送消息后,Response<T>里面的data和response是空值,只有格式化的方式builder。Sync()用于一次性读取所有回复,首先调用client的getAll()方法,getAll()方法根据之前记录的pipelinedCommands和Redis通讯协议,getAll()之前先调用flush()刷新此输出流并强制写出所有缓冲的输出字节(这个时候才真正地发送命令), 然后读取相同条数的回复消息到一个List,并返回给Pipeline。随后遍历这个List,逐个将回复消息赋给pipelinedResponses中每个Response<T>的data。在执行Response<T>.get()命令时,Response<T>里面data已经有值了,但是是Object类型的,因而还要调用build()方法,做一次数据转换,返回格式化之后的数据。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,288评论 19 139
  • NOSQL类型简介键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,volde...
    MicoCube阅读 4,102评论 2 27
  • 1.1 资料 ,最好的入门小册子,可以先于一切文档之前看,免费。 作者Antirez的博客,Antirez维护的R...
    JefferyLcm阅读 17,176评论 1 51
  • 今天去拿孩子的体检报告,白细胞和红血球指数有点偏高,医生建议复查!美好的心情突然沉了下来!自己的管用模式:事情没有...
    米勒Li阅读 212评论 0 0
  • 现实是种方式 是梦的魇,影射灵魂 是梦想的包袱,臃肿杂乱,不曾甩去 理想编织的梦,被现实无情打破 碎末残片,待风袭...
    流泪的洋葱头阅读 338评论 0 2