個人有個依賴百度學術的服務叫 AnyPaper,它具體是什麼,感興趣的朋友可以去了解下。
最近百度學術換了一張新面孔,這一換不要緊,我的整個網站經常出現無響應的情況,登陸伺服器發現系統 CPU 穩定在 100%左右,這到底是怎麼回事?
先列一下網站環境:
- 主機:阿里雲伺服器(2H4G)
- 系統:Windows Server 2016
- 網站:SpringBoot 開發,單 Jar 執行
尋找問題
由於網站執行一直很穩定,所以基本可以排除是程式碼上的問題,CPU 佔用很高,我的反應可能有以下幾種原因:
- 系統中毒了,被植入了挖礦程式(網站程式停止後,CPU 立馬恢復正常,可以排除系統中毒可能);
- 網站漏洞,被植入挖礦指令碼(低版本的 Hutool 存在 ZipUtil 以及 FileUtil 的 slip 漏洞,貌似低版本的 SpringBoot 也有一些安全隱患);
- 使用者請求量非常高(實際上訪問人數可憐兮兮)。
綜上,首先對 SpringBoot 和 Hutool 進行了版本升級,然後在本地開始除錯執行,發現使用 AnyPaper 進行文獻搜尋的時候系統卡住了,單步進行除錯,發現程式卡在了正則匹配(匹配內容為百度學術搜尋結果的原始碼):<h3 class="t c_font">[sS]+?target="_blank">([sS]+?)</a>s*</h3>([sS]+?)(?:(?:publish`}"s*title="([^"]+)[sS]+?)|(?:<span>([^<]+)</span>[^<]+<span class="sc_time"s*))data-year="(d+)[Ss]+?被引量: s*(?:(d+)|(?:<a[^>]+>s*(d+)))[sS]+?c_abstract">s+([sS]+?)(?:s*<div class="sc_allversion">[sS]+?</span>s*(<a class="v_source" title="[sS]+?)</div>[sS]+?sc_subject">s+([sS]+?))?s*<div class="sc_other">
,正常情況下匹配結果如圖所示:
修復正則匹配
由於卡在了正則匹配,所以懷疑是百度學術頁面結構發生變化了,遂開啟百度學術看了一下,果然換了一張面孔,不過調整不是很大(部分元素被移除了,而且元素的位置發生了調整),很快就改好了新的正則匹配表示式:h3s*class="t c_font"[sS]+?_blank">([sS]+?)</a>s*</h3>[sS]+?c_abstract">s+([sS]+?)s+</div>([sS]+?)publish`}"s*title="([^"]+)[sS]+?被引量: s*(?:<a[^>]+>)?s*(d+)[Ss]+?data-year="(d+)[Ss]+?<div class="sc_allversion">[sS]+?</span>s*(<a class="v_source" title="[sS]+?)</div>[sS]+?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
,執行介面如下所示:
查詢佔用 CPU 的執行緒
從上圖可以看到程式已經佔用了 50% 左右的 CPU 了,因為 CPU 是雙核的所以目前有一個請求卡住了所以佔用了大概一半,選中程式,點選右鍵,然後選擇Properties
選單,即可開啟程式屬性介面,在屬性介面可以看到程式的全部執行緒所佔用的資源。
使用 jstack 匯出堆疊資訊
jstack 是 java 虛擬機器自帶的一種堆疊跟蹤工具,某些情況下(jdk 的 bin 目錄沒有配置到系統環境變數 PATH 時)jstack 不能直接在命令列使用,最直接的使用方法就是去 java 的安裝目錄下的 bin 目錄,然後執行下面的命令:jstack.exe 2380 >c:/stack.log
,2380 是網站程式的 pid,最後的是堆疊日誌儲存的路徑。
從堆疊中查詢問題程式碼
如圖我們看到熱點執行緒 id 為:3952(0xf70)、5016(0x1398),開啟堆疊日誌c:/stack.log
,搜尋0xf70
以及0x1398
:
解決問題
看到問題程式碼,果然還是正則匹配的問題,不過這個正則確實是沒有問題呀,搞了很久也沒有找到正規表示式的問題。
最終發現問題的根本原因:**百度學術的介面有時候是新版,有時候是舊版,**兩種正規表示式都可以應用到兩種頁面,但是對於不是正確的頁面需要耗費很久才可能匹配到結果,真的是坑到了極點呀。
在找到問題之前,個人採用的方案是把上面很長的正則簡化,簡化就是說之前一句話把全部元素都匹配出來了,現在就分步匹配:先匹配單條記錄,然後在單條記錄裡面匹配文章標題、年份、摘要等;採用分步匹配後,就不存在 CPU 佔用過高的問題了。
總結
- 如沒必要,正規表示式不要寫的太長,即便你是一個正規表示式高手;
- 對於多條記錄的匹配,先匹配單條記錄(確定每一條記錄的邊界),然後在每一條記錄的文字中匹配詳細的欄位;
- 可以使用 Html 解析工具,使用 XPATH 或者 CSS 選擇器替代正規表示式。
Any Code,Code Any!
掃碼關注『AnyCode』,程式設計路上,一起前行。