记一次优化经历

在当前的业务架构中,一个请求需要经过多个模块或者服务才能处理完成。经常遇到的问题是请求慢或者请求超时。这时需要定位到哪些模块拖累了服务,如何准确定位到问题并及时优化。

假设有3个模块A、B、C。A是接入层,即提供http(s)协议,B和C是内部模块,A、B、C 内部交互通过RPC协议。最明显方式当A请求B时,会把耗时时间记录到日志中,B请求C也是一样。当请求过长时,通过日志时间可以大致确定处理哪个模块慢了。假设在B的日志中,记录的请求C耗时长,但是这不一定说明C就是处理慢了,有可能C相应挺快,但是B接收慢了。

如何确定到底C是否有问题,可以通过网络包进行分析。B请求C这种情形中,C会通过固定的端口进行服务,可以在B的机器上,抓取C端口的网络包。

假设C端口为10102, sudo tcpdump port 10102 -nn -vv -c 20000 -w net.pcap, 通过tcpdump抓取了20000个包,写入到net.pcap文件中,然后把文件导入到wireshark进行分析。

<http://blog.bruceding.com/qq20171017-072843>” /></p>
<p>可以设置过滤条件,
			<span id=tcp.srcport=10102,这样会单独显示C的回包列表。按照 Time since previous frame in this TCP stream 排序,这个字段的含义是距离上次请求包的时间间隔。如果这个字段中时间过长,那么就可以确定是C的问题,反之,则需要从B中找问题了。

在我们的例子中,C确实响应时间慢了,问题定位到了C模块中。下一步我们可以观察C在机器中的表现行为,可以登上机器,通过top进行观察,发现C偶尔占用CPU较高,并且使用内存会大幅增长。这时可以先分析CPU情况。可以通过perf + 火焰图进行CPU分析。具体的方式参考

http://blog.bruceding.com/wp-content/uploads/2017/10/QQ20171017-074212-e1508501401840.jpg

火焰图很好的展示了使用CPU的热点路径,通过查看C模块的代码加深理解。结合代码,很容易发现处理JSON字段耗CPU。这个时候就很难处理了,一般会使用第三方库来处理JSON,想直接通过优化第三方库的来提高性能,耗的精力肯定多,也不见得有成效。

那么可以反过来想,什么会导致这个问题?Json数据大?调用方法次数多?结合代码进一步分析,一种方式是记录方法的耗时时间,这个需要改代码,需要上线。通过代码,看到C模块的处理是先从mysql中获取数据,然后对数据进行处理,mysql中的数据本身是JSON形式的。而且代码中,使用短连接的形式来获取的mysql数据,是否在获取数据中就慢了?可以通过tcpdump,分析mysql情况。在C模块机器中抓包, sudo tcpdump port 3306 -nn -vv -c 20000 -w mysql.pcap

通过抓包,发现了问题。发现在一次查询中,获取的数据特别多,整个耗时花费了1.5s。通过wireshark可以把相关的sql打印出来,然后在数据库中查询,发现一个字段数据量太大,这样导致数据传输就非常慢,进行JSON处理的话,也肯定很慢了。这是个偶发,还是经常出现呢?

已经定位到了相关的字段值D1B495AA8EFA95B600E3E941CBF57648,如何确定是偶发现象,还是出现频率高呢?还是通过抓包工具确定。 sudo tcpdump port 3306 -nn -s 0 -l -w - | strings | grep "D1B495AA8EFA95B600E3E941CBF57648" ,上面命令可以把包以字符的形式打印出来,然后公共grep进行搜索。发现出现的频率特别高,这样会引起CPU,内存高就解释的通了。

最终问题的解决非常容易,和业务同学确定后,发现这其实本身是条脏数据,可以直接删除掉。删除之后,CPU,内存一直非常平稳,耗时现象也消失了。

在当前的架构中,微服务,多模块甚至有可能出现网式的调用关系,应该充分利用tcpdump,wireshark,进行网络之间的分析, 使用perf,火焰图进行性能的分析。

此条目发表在性能分类目录,贴了标签。将固定链接加入收藏夹。

记一次优化经历》有 2 条评论

  1. 匿名说:

    你好,我是从极客时间过来的。你这里火焰图能看出来是json问题么?

    • 匿名说:

      cygnus 是 json 解析的封装。 这个需要熟悉项目的代码。上面的耗时点在 GetOrElse 函数上, 这个就是 json 取值的函数封装。

发表评论

电子邮件地址不会被公开。