Netty 是如何解析 Redis RESP 协议的——请求篇

上文抓包分析了这个 Redis RESP 协议,看到 TCP 层面的 byte 信息,直观感受到这个 Human Readble 的二进制协议。

比如 bulk String 的格式就是: $<length>\r\n<data>\r\n

那么,剩下的特点就是 Simple to implement 和 Fast to parse。

刚好,Netty 中就有个现成的轮子,这节就一起来看看吧~

RESP2 协议

Netty 中的 Redis 模块

可以看到,整体代码并不多。

核心就在 RedisEncoder 和 RedisDecoder 上,其他就是针对这个 RESP 协议的 model。

这节是请求篇,对应 RedisEncoder ,相对比较简单,我们直接从 test 模块中找个例子来看。

RedisEncoderTest

这个代表 redis-cli ,负责发请求到这个 redis-server。

这里我摘抄了其中的 shouldEncodeSimpleString 例子,简单字符串的格式是:+OK\r\n

java 复制代码
public class RedisEncoderTest {

    private EmbeddedChannel channel;

    @BeforeEach
    public void setup() throws Exception {
        channel = new EmbeddedChannel(new RedisEncoder());
    }

    @AfterEach
    public void teardown() throws Exception {
        assertFalse(channel.finish());
    }
    
   @Test
    public void shouldEncodeSimpleString() {
        RedisMessage msg = new SimpleStringRedisMessage("simple");

        // 看这里
        boolean result = channel.writeOutbound(msg);
        assertThat(result, is(true));

        ByteBuf written = readAll(channel);
        assertThat(bytesOf(written), is(bytesOf("+simple\r\n")));
        written.release();
    }
    
    private static ByteBuf readAll(EmbeddedChannel channel) {
        ByteBuf buf = Unpooled.buffer();
        ByteBuf read;
        while ((read = channel.readOutbound()) != null) {
            buf.writeBytes(read);
            read.release();
        }
        return buf;
    }

}

图解

上面的核心流程大致如下

  1. 创建 EmbeddedChannel,并添加 RedisEncoder 这个 handler
  2. 创建 SimpleStringRedisMessage 简单字符串类型的消息
  3. 调用 writeOutbound 方法,实际会调用 handler 中的 encode 方法

这里画了个简略图 👇

下面开始源码解读 👇

创建 EmbeddedChannel

内嵌型的 Channel ,常见的还有 NioServerSockerChannel 等。

添加 RedisEncoder

new EmbeddedChannel(new RedisEncoder());

创建好这个通道后,给它添加 RedisEncoder 这个 Handler

这里的核心方法在 writeRedisMessage , 下面再聊。

创建 SimpleStringRedisMessage

java 复制代码
// 创建一个简单类型的字符串消息
// 简单字符串的格式是:`+OK\r\n` 
RedisMessage msg = new SimpleStringRedisMessage("simple");

主要提供 content 方法来获取这个字符串消息。

writeOutbound

实际去调用各个 OutboundHandler 上的 encode 方法。

这里调用到 RedisEncoder 中的 encode 方法,

writeSimpleStringMessage

还多一个 RedisMessageType.SIMPLE_STRING 参数。

RedisMessageType

一个枚举类,对应 RESP2 协议

writeString ⭐

创建 ByteBuf ,并初始化长度。

这里用 utf8 去编码这个 content,取最大值就是 3 * 6 = 18 的长度。再加上这个 + 1 个长度,EOL 两个长度,初始化时就是 21 的长度。

RedisConstants 如下

最终,写入了 9 个字节。

到了这里, channel.writeOutbound(msg); 就执行完了。

剩下就是 ByteBuf 的主场了 👇

执行 ByteBuf written = readAll(channel); 把数据读取到 ByteBuf 中,和 "+simple\r\n" 进行比较。

java 复制代码
assertThat(bytesOf(written), is(bytesOf("+simple\r\n")));

结尾

RedisEncoder 的小例子到这就结束了。

大家也可以换成下面这种,模拟常见的请求场景测试一下,上面的例子更像是服务器对客户端的应答。

java 复制代码
RedisMessage msg = new InlineCommandRedisMessage("get name");

下文再来看看这个响应篇。

本文就到这里啦,感谢您的阅读,有不对的地方也请您帮忙指正!谢谢~😋

喜欢的小伙伴们,别忘了点赞关注呀~😋 祝你有个美好的一天!😝

github.com/Java4ye 😆

相关推荐
假装我不帅1 小时前
asp.net framework从webform开始创建mvc项目
后端·asp.net·mvc
神仙别闹1 小时前
基于ASP.NET+SQL Server实现简单小说网站(包括PC版本和移动版本)
后端·asp.net
计算机-秋大田2 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue
货拉拉技术2 小时前
货拉拉-实时对账系统(算盘平台)
后端
掘金酱2 小时前
✍【瓜分额外奖金】11月金石计划附加挑战赛-活动命题发布
人工智能·后端
代码之光_19803 小时前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi3 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
颜淡慕潇3 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
尘浮生4 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea