likes
comments
collection
share

Wireshark网络分析之追踪Redisearch-go官方Bug

作者站长头像
站长
· 阅读数 20

问题描述

我所在公司某业务需要redis-json存储数据,然后通过redis-search对存储的json数据进行索引,利用索引进行快速的增删改查。

redis-json/redis-search都是redis官方提供的“武器库”。

Wireshark网络分析之追踪Redisearch-go官方Bug

如果读者对redis-json感兴趣,可参照官方或者本人拙作:小谈Redis JSON 系列一

那么说回来我们在使用时遇到的问题,对于redis-search的使用,我们的client采用了官方包github redisearch-go

在我们实验时,对某字段值分别进行闭区间和开区间查找时,发现了致命的错误

// 我想要对uid字段查找区间(1,49],结果遇到了问题
query := redisearch.NewQuery("*").AddFilter(
    redisearch.Filter{
        Field: "uid",
        Options: redisearch.NumericFilterOptions{
        Min: 1,
        ExclusiveMin: true,
        Max: 49,
        ExclusiveMax: false,
        },
    },
)

运行之后,报错如下

total: 0, err:Unknown argument 49 at position 5 for

这是为什么呢?

(通过对该问题的解决,也达成了我人生的第一个PR

问题分析

实际上,当时遇到这个报错,我毫无思绪。再次将代码粘贴在此处

// 我想要对uid字段查找区间(1,49],结果遇到了问题
query := redisearch.NewQuery("*").AddFilter(
    redisearch.Filter{
        Field: "uid",
        Options: redisearch.NumericFilterOptions{
        Min: 1,
        ExclusiveMin: true,
        Max: 49,
        ExclusiveMax: false,
        },
    },
)

我认为对redis-search库的使用貌似没问题,上述代码就是基本使用嘛。

怎么办,死马当活马医。

我将搜索区间确定为[1, 49],发现不会报错。

此时我想,难道redis-search本身不支持开区间搜索?

那么如何验证这个猜想呢?

那就是使用原生的redis命令,发送开区间查找请求

ft.search tags * filter uid (1 49

运行之后,发现成功的返回了结果。诶嘿,说明redis-search是支持开区间查找(这本来也是应该提供的功能嘛)

那么难道是这个官方提供的包有问题?

如何验证包的问题。如同上一篇查询TiDBbug那样,有两个方法。 Wireshark实战之追踪TiDB官方Bug

1、仔细查看代码库的实现,毕竟代码之下,全无秘密。但是缺点是需要仔细debug,层层嵌套,不一定好理解

2、直接抓包,进行分析。看看通过官方包发送出去的请求到底是什么样子的?

我选择进行wireshark抓包

wireshark抓包

我们抓包的目的就是查看,发送的redis请求到底是什么样子的。

抓包的步骤很简单,我们不再进行说明。我们直接进入分析包的环节。

首先浏览下,抓到的包

Wireshark网络分析之追踪Redisearch-go官方Bug

看到这些包,是不是有些疑惑。Protocol一列显示的都是TCP协议,Redis不应该和MySQL一样,作为应用软件应该有应用层的协议啊。

为什么没有显示呢?

答案很简单,wireshark作为一款抓包软件,它并不能提供所有网络协议的解析,尤其是应用层协议

应用层协议是应用程序自己设计的通信协议,并不是互联网的底层基石。确实有一些应用层协议非常有名,比如HTTP协议、MySQL协议、DNS协议、FTP协议等等,wireshark对这些协议理所应当的提供了支持。

我们可以向追踪TiDB官方bug那篇文章一样,选择Decode As,结果里面并没有“Redis协议”,如下图所示。

Wireshark网络分析之追踪Redisearch-go官方Bug

那么我们就无法分析了吗?

不,首先让我们了解一下Redis为自己准备的应用层协议。根据官网提供的信息,我们可知

Redis clients use a protocol called RESP (REdis Serialization Protocol) to communicate with the Redis server.

看来专属于Redis应用层的协议名为“RESP”。并且用官网的话来说RESP具有Human readable的特性,换句话来说,RESP是文本协议,是可以直接看的。

由此,我们可以在wireshark中简单的follow 一下TCP Stream即可。

Wireshark网络分析之追踪Redisearch-go官方Bug

我们可以看到,真实的信息交互

Wireshark网络分析之追踪Redisearch-go官方Bug

首先,的确是报错了

其次我们解析一下RESP:将RESP中的请求翻译成redis命令,即为

ft.search tags * filter uid ( 1 49

嗯哼,这个和上面那个没有报错的redis开区间搜索命令有何不同?我们将两个语句放在一起比较,立马就会发现两者的不同

ft.search tags * filter uid (1 49 // 未报错
ft.search tags * filter uid ( 1 49 // 报错

没错,真相大白:官方包“翻译”之后的redis命令,在开区间搜索时,多加了一个空格,导致了报错。

那还等什么,赶紧提了一个PR,也是人生中第一个有重要意义的PR

redis-search pr

总结

包括上一篇关于TiDB官方bug的文章以及本文,不论应用如何花里胡哨的变换,网络协议的分析是同样的。就像代码之下毫无秘密,网络协议包被抓取,我们可以拿着放大镜分析。因为底层TCP/IP都是共通的,分析方法是可以复用的。随着分析次数的增加,我们能够快速找到出问题的地方。

参考