百度学术改版与 CPU 100% 有关系么?

1,111 阅读5分钟

个人有个依赖百度学术的服务叫 AnyPaper,它具体是什么,感兴趣的朋友可以去了解下。

最近百度学术换了一张新面孔,这一换不要紧,我的整个网站经常出现无响应的情况,登陆服务器发现系统 CPU 稳定在 100%左右,这到底是怎么回事?

先列一下网站环境:

  • 主机:阿里云服务器(2H4G)
  • 系统:Windows Server 2016
  • 网站:SpringBoot 开发,单 Jar 运行

寻找问题

由于网站运行一直很稳定,所以基本可以排除是代码上的问题,CPU 占用很高,我的反应可能有以下几种原因:

  1. 系统中毒了,被植入了挖矿程序(网站程序停止后,CPU 立马恢复正常,可以排除系统中毒可能);
  2. 网站漏洞,被植入挖矿脚本(低版本的 Hutool 存在 ZipUtil 以及 FileUtil 的 slip 漏洞,貌似低版本的 SpringBoot 也有一些安全隐患);
  3. 用户请求量非常高(实际上访问人数可怜兮兮)。

综上,首先对 SpringBoot 和 Hutool 进行了版本升级,然后在本地开始调试运行,发现使用 AnyPaper 进行文献搜索的时候系统卡住了,单步进行调试,发现程序卡在了正则匹配(匹配内容为百度学术搜索结果的源代码):<h3 class="t c_font">[\s\S]+?target="_blank">([\s\S]+?)</a>\s*</h3>([\s\S]+?)(?:(?:publish'}"\s*title="([^"]+)[\s\S]+?)|(?:<span>([^<]+)</span>[^<]+<span class="sc_time"\s*))data-year="(\d+)[\S\s]+?被引量:&nbsp;\s*(?:(\d+)|(?:<a[^>]+>\s*(\d+)))[\s\S]+?c_abstract">\s+([\s\S]+?)(?:\s*<div class="sc_allversion">[\s\S]+?</span>\s*(<a class="v_source" title="[\s\S]+?)</div>[\s\S]+?sc_subject">\s+([\s\S]+?))?\s*<div class="sc_other">,正常情况下匹配结果如图所示:

正常匹配结果

修复正则匹配

由于卡在了正则匹配,所以怀疑是百度学术页面结构发生变化了,遂打开百度学术看了一下,果然换了一张面孔,不过调整不是很大(部分元素被移除了,而且元素的位置发生了调整),很快就改好了新的正则匹配表达式:h3\s*class="t c_font"[\s\S]+?_blank">([\s\S]+?)</a>\s*</h3>[\s\S]+?c_abstract">\s+([\s\S]+?)\s+</div>([\s\S]+?)publish'}"\s*title="([^"]+)[\s\S]+?被引量:&nbsp;\s*(?:<a[^>]+>)?\s*(\d+)[\S\s]+?data-year="(\d+)[\S\s]+?<div class="sc_allversion">[\s\S]+?</span>\s*(<a class="v_source" title="[\s\S]+?)</div>[\s\S]+?class="sc_other">,使用新的正则匹配后,程序恢复了正常,代码更新后,网站发布了新版本。

改版前的百度学术

换脸后的百度学术

深入问题

网站新版本发布后,特意点击了常用的服务,运行正常,一切恢复如初。

然而,过了没多久(不到 10 分钟),整个系统又出现了无响应的情况,登陆服务器查看后,发现还是 CPU 100%,这就非常诡异了,当时真的是一度怀疑程序有类似 Java 反序列化的漏洞,被植入了挖矿程序;不过这种可能性很低,所以决定深入挖掘一下原因。

在百度上搜索:windows 排查 cpu 占用,看到一篇文章:如何在 windows 下查找 java 应用占用 CPU 过高,非常契合目前的困境。

Windows 下排查 Java 应用占用 CPU 过高

上述的文章已经叙述的比较详细了,不过有一部分比较冗余,个人在做一个小小的总结。

安装 Process Explorer

从微软官方网址 technet.microsoft.com/en-us/sysin…下载安装包,安装包是一个 zip 压缩文件,解压到自定义的文件夹即可。

解压完成后,直接运行procexp64.exe,运行界面如下所示:

Process Explorer 运行界面

查找占用 CPU 的线程

从上图可以看到程序已经占用了 50% 左右的 CPU 了,因为 CPU 是双核的所以目前有一个请求卡住了所以占用了大概一半,选中程序,点击右键,然后选择Properties菜单,即可打开程序属性界面,在属性界面可以看到程序的全部线程所占用的资源。

在程序属性界面查找热点线程

使用 jstack 导出堆栈信息

jstack 是 java 虚拟机自带的一种堆栈跟踪工具,某些情况下(jdk 的 bin 目录没有配置到系统环境变量 PATH 时)jstack 不能直接在命令行使用,最直接的使用方法就是去 java 的安装目录下的 bin 目录,然后执行下面的命令:jstack.exe 2380 >c:/stack.log,2380 是网站程序的 pid,最后的是堆栈日志保存的路径。

使用 jstack 导出指定 pid 的堆栈信息

从堆栈中查找问题代码

如图我们看到热点线程 id 为:3952(0xf70)、5016(0x1398),打开堆栈日志c:/stack.log,搜索0xf70以及0x1398

找到问题代码

解决问题

看到问题代码,果然还是正则匹配的问题,不过这个正则确实是没有问题呀,搞了很久也没有找到正则表达式的问题。

最终发现问题的根本原因:**百度学术的界面有时候是新版,有时候是旧版,**两种正则表达式都可以应用到两种页面,但是对于不是正确的页面需要耗费很久才可能匹配到结果,真的是坑到了极点呀。

在找到问题之前,个人采用的方案是把上面很长的正则简化,简化就是说之前一句话把全部元素都匹配出来了,现在就分步匹配:先匹配单条记录,然后在单条记录里面匹配文章标题、年份、摘要等;采用分步匹配后,就不存在 CPU 占用过高的问题了。

总结

  1. 如没必要,正则表达式不要写的太长,即便你是一个正则表达式高手;
  2. 对于多条记录的匹配,先匹配单条记录(确定每一条记录的边界),然后在每一条记录的文本中匹配详细的字段;
  3. 可以使用 Html 解析工具,使用 XPATH 或者 CSS 选择器替代正则表达式。

Any Code,Code Any!

扫码关注『AnyCode』,编程路上,一起前行。