Jedis 底层是如何和 redis 服务端进行通讯的?

Jedis 底层是如何和 redis 服务端进行通讯的?

1 个解决方案

AllenJiang
中间件研发,关注微信公众号 : 小哈学Java, 回复"666", 即可免费领取10G学习&面试资料

redis 客户端和 redis server 之间是通过 RESP(REdis Serialization Protocol)协议来进行通讯的,RESP 协议虽然专为 redis client 和 server 而设计的通讯协议,但是它同样可以被其他项目使用。

RESP 协议有以下优点:

  • 1.容易实现

  • 2.解析快速

  • 3.可读性强

Note: RESP 是 redis client 和 redis server 之间的二进制通讯协议,而 Redis 集群之间并非同样使用这种协议,集群使用不同的二进制协议来交换节点之间的消息。

RESP 协议描述

RESP 协议在 Redis 1.2 中引入,但它已成为在 Redis 2.0 中与 Redis 服务器交谈的标准方式。也是你应该在 Redis 客户端中实现的协议。

RESP 实际上是一个支持以下数据类型的序列化协议:简单 字符串错误整数批量字符串数组

RESID 在 Redis 中用作请求 - 响应协议的方式如下:

客户端将命令作为大容量字符串的 RESP 数组发送到 Redis 服务器。服务器根据命令实现回复一个 RESP 类型。 在 RESP 中,某些数据的类型取决于第一个字节:

  • 对于简单字符串,第一个字节是“+”

  • 对于错误,第一个字节是“ - ”

  • 对于整数,第一个字节是“:”

  • 对于批量字符串,第一个字节是“$”

  • 对于数组,第一个字节是“ *”

此外,RESP 能够使用后面指定的 Bulk Strings 或 Array 的特殊变体来表示空值。

在 RESP 中,协议的不同部分始终以“\ r \ n”(CRLF)结尾。

Jedis 源码分析

我们以 jedis 客户端调用 set 为例:

jedis.set("name", "allen");

跟踪源码:

 protected Connection sendCommand(final Command cmd, final byte[]... args) {
    try {
      connect(); # 获取 socket tcp 连接
      Protocol.sendCommand(outputStream, cmd, args); # 发送 RESP 协议命令
      pipelinedCommands++;
      return this;
    } catch (JedisConnectionException ex) {
      // ...
    }
  }

sendCommand 细节:

private static void sendCommand(final RedisOutputStream os, final byte[] command,
      final byte[]... args) {
    try {
      os.write(ASTERISK_BYTE); # 设置 * 开头,后面跟上命令的 length
      os.writeIntCrLf(args.length + 1); # 加 1 是命令头的头一个单词,这里是 "set",再加上 crlf 换行符
      os.write(DOLLAR_BYTE); # 跟上 $ 符
      os.writeIntCrLf(command.length); # 跟上发送命令第一个单词("set")的长度,再加上 crlf 换行符
      os.write(command); # 更上具体命令,也就是 "set" 字符串
      os.writeCrLf();  # 加上 crlf 换行符

      for (final byte[] arg : args) { # 开始处理 key 和 value, 步骤与上面一样
        os.write(DOLLAR_BYTE); 
        os.writeIntCrLf(arg.length);
        os.write(arg);
        os.writeCrLf();}
    } catch (IOException e) {
      throw new JedisConnectionException(e);
    }
  }

上面这一套流程走完,完成 RESP 协议的字符串拼装,得到结果:*3\r\n$3\r\nset$4\r\nname\r\n$5\r\nallen\r\n,拼装完成后,再以 socket 发送给 redis server.

参考文档:https://redis.io/topics/protocol