Wireshark网络分析之追踪Redisearch-go官方Bug
问题描述
我所在公司某业务需要redis-json存储数据,然后通过redis-search对存储的json数据进行索引,利用索引进行快速的增删改查。
redis-json/redis-search都是redis官方提供的“武器库”。

如果读者对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是支持开区间查找(这本来也是应该提供的功能嘛)
那么难道是这个官方提供的包有问题?
如何验证包的问题。如同上一篇查询TiDB的bug那样,有两个方法。
Wireshark实战之追踪TiDB官方Bug
1、仔细查看代码库的实现,毕竟代码之下,全无秘密。但是缺点是需要仔细debug,层层嵌套,不一定好理解
2、直接抓包,进行分析。看看通过官方包发送出去的请求到底是什么样子的?
我选择进行wireshark抓包
wireshark抓包
我们抓包的目的就是查看,发送的redis请求到底是什么样子的。
抓包的步骤很简单,我们不再进行说明。我们直接进入分析包的环节。
首先浏览下,抓到的包

看到这些包,是不是有些疑惑。Protocol一列显示的都是TCP协议,Redis不应该和MySQL一样,作为应用软件应该有应用层的协议啊。
为什么没有显示呢?
答案很简单,wireshark作为一款抓包软件,它并不能提供所有网络协议的解析,尤其是应用层协议。
应用层协议是应用程序自己设计的通信协议,并不是互联网的底层基石。确实有一些应用层协议非常有名,比如HTTP协议、MySQL协议、DNS协议、FTP协议等等,wireshark对这些协议理所应当的提供了支持。
我们可以向追踪TiDB官方bug那篇文章一样,选择Decode As,结果里面并没有“Redis协议”,如下图所示。

那么我们就无法分析了吗?
不,首先让我们了解一下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即可。

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

首先,的确是报错了
其次我们解析一下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。
总结
包括上一篇关于TiDB官方bug的文章以及本文,不论应用如何花里胡哨的变换,网络协议的分析是同样的。就像代码之下毫无秘密,网络协议包被抓取,我们可以拿着放大镜分析。因为底层TCP/IP都是共通的,分析方法是可以复用的。随着分析次数的增加,我们能够快速找到出问题的地方。
参考
-
《Wireshark数据分析实战》
转载自:https://juejin.cn/post/7171389808110108685