问题是这样的,打开我们的网站后,打开开发者工具,然后偶尔会看到某个请求一直处于 pending 状态,大概会过去个十几秒,偶尔又全部都很快,几百毫秒就完成了。
看了下 TTFB, 发现基本就花在了等服务器响应的时间上。 其实到这里基本上就可以断定问题出在了服务器上,但是我有点不信邪,觉得一个 TTFB 有可能不太准确,然后就分析了 chrome 的网络日志。具体方法:
- 打开
chrome://net-export/
,然后点击 Start Logging to Disk 然后会让你选择一个地方来存储日志文件,好了之后录制也就开始了。 - 现在去出现问题的页面疯狂尝试重现,重现完毕后,回到第一步的那个页面Stop 就可以了。
- 查看日志, 打开这个地址
https://netlog-viewer.appspot.com/#import
然后选择文件,将刚才的日志文件导入。选择 event, 搜索那个出问题的 api, 就可以查看到详细的日志,简单到点的话,看看有没有 error 之类的日志,如果没有的话,看看从哪一步开始时间边长的,我这个是从读取响应 header 的时候边长的,估计是在等待,也没有 error , 基本就断定问题出现在了服务端。
然后在服务端查了一会,没有查到,最后靠猜猜到的。当时有个现场就是服务器重新部署后,严谨的说应该是第一次请求,发现大量接口都处于 pending 状态,这个时候基本就可以知道结论了, 某些初始化采用了类似单例模式中的懒汉模式,就是访问的时候才进行初始化,这就导致第一次非常慢。 然后继续往下看,发现数据库的连接池有点问题, 采用了 Blocking 模式,并且也没有按需增加和减少连接数,这样的话,如果某个 库的连接急剧上涨,那后面的请求肯定得处于 pending 状态。 最终将连接池 Blocking 改掉发现 pending 消失了。 其实当时考虑到,在以前的代码中有的使用了select LAST_INSERT_ID()
这就搞得无法使用共享的连接池, 最终只能改成随线程创建,随线程销毁的模式的连接池,这种模式也没有 blocking 模式,最终就解决了。
感谢以下文章的作者,让我学习到了新的分析方法