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 😆

相关推荐
superman超哥2 分钟前
Rust 内存对齐与缓存友好设计:性能优化的微观艺术
开发语言·后端·性能优化·rust·内存对齐·缓存优化设计·微观艺术
IT_陈寒6 分钟前
SpringBoot 3.2实战:我用这5个冷门特性将接口QPS提升了200%
前端·人工智能·后端
辣机小司6 分钟前
【踩坑记录:EasyExcel 生产级实战:策略模式重构与防御性导入导出校验指南(实用工具类分享)】
java·spring boot·后端·重构·excel·策略模式·easyexcel
BingoGo15 分钟前
2025 年的 PHP 虽低调内敛没大改 但是更好用了
后端·php
JaguarJack16 分钟前
2025 年的 PHP 虽低调内敛没大改 但是更好用了
后端·php
后端小张17 分钟前
【JAVA 进阶】Spring Boot自动配置详解
java·开发语言·人工智能·spring boot·后端·spring·spring cloud
IT 行者21 分钟前
Spring Security Session 序列化策略分析
java·spring boot·后端·spring
IT 行者23 分钟前
Spring Boot 4.0 整合Spring Security 7 后的统一异常处理指南
spring boot·后端·spring
掘根2 小时前
【消息队列项目】客户端四大模块实现
开发语言·后端·ruby
NAGNIP9 小时前
多个 GitHub 账户SSH 密钥配置全攻略
后端