前兩天網站訪問慢的問題定位過程以及最終解決辦法

前提說明:目前開源中國社區在作改版,所以網站同時存在新舊兩種不一樣的版面,例如我的空間就是新的系統。所以整個網站包含兩套系統,改版前和改版後,咱們把改版前叫老系統,把改版後叫新系統。redis

大概一週多的時間,常常會感受網站,包括客戶端使用過程當中有卡頓的狀況,沒太在乎。可是前天這個卡頓就變得比較嚴重,動彈裏開始出現各類反應訪問慢的信息。數據庫

檢查全部的機器的 CPU 使用率都在一個正常的狀態,Tomcat 無特別的異常日誌,應用的數據庫鏈接池的忙鏈接比平時要高好多倍,可是數據庫操做一些正常。緩存

檢查數據庫慢查詢日誌,比平時多了一些,基本上集中在近期改版新的 SQL 上,把這些慢查詢經過索引調整、SQL 優化方式解決後,慢查詢再也不出現,可是系統響應速度仍舊沒有提高。併發

咱們一度懷疑是數據庫響應慢,想重啓一下社區的 MySQL 數據庫,這個數據庫已經運行超過 5 年沒重啓過了!!!但仍是忍住了!再試試其餘不行再說。框架

而後發現了一個很是很是慢的操做,就是在客戶端上收藏某篇文章的時候,徹底沒有響應,或者是要十幾秒纔有反應。性能

因而在這個收藏功能對應的代碼增長了數據監控點,在日誌中記錄該方法幾個邏輯的執行時間。更新到線上進行測試發現,從在界面上點擊收藏,到日誌的輸出中間隔了好幾十秒,而真正功能的執行時間很短。看似有不少請求在排隊等 Tomcat 處理致使的堵塞,可是 Tomcat 的日誌沒有關於處理請求隊列慢的日誌信息。這是其中一個疑點。測試

日誌顯示數據庫操做執行十幾毫秒,緩存操做一兩百毫秒,因此能夠肯定數據庫是沒問題的(幸好沒重啓)。而緩存操做就算是一兩百毫秒也不該該致使這個系統拖得那麼慢,可是能夠明確的是緩存是確定有問題的。沒準其餘更復雜的緩存操做耗時要大不少,致使請求處理的卡頓。優化

OSChina 一直在用 J2Cache 的兩級緩存框架,這個框架有不少人在噴,可是噴的人都沒用過它。因爲 OSChina 如今整個網站同時運行新老兩個系統,由於不少頁面還沒改版完成。老的系統基於 J2Cache 1.x 運行,新的系統基於 J2Cache 2.x。鏈接的同一個 Redis 服務,使用不一樣的 database 進行隔離。網站

因此咱們決定搞一個全新的乾淨的 Redis ,先把老系統切到這個新的 Redis 服務上,切換後先內部測試,首次訪問慢一點,再次訪問速度就很快了。切到生產上,全部的用戶請求的轉到這個系統上,訪問速度很快,請求的處理速度通常只有幾十毫秒。spa

運行了半天多,速度仍然很穩定。

可是我的空間依然很慢,由於我的空間是新的系統,接到仍是以前的 Redis。因而咱們又使用了另一個獨立的全新的 Redis 服務從新部署了一套空間,剛部署上線完後速度很快,可是過了半個小時一個小時候,就開始感受沒那麼順暢了。

在觀察系統日誌時,同時也發現了咱們新的業務代碼在緩存處理邏輯上的嚴重問題,例如生成大量動態的 Region ,而實際使用 Region 不該該這樣使用,Region 應該事先在配置文件中定義好的。由於在 J2Cache 中動態建立 Region 是一個線程同步的方法,大量併發請求勢必致使等待。

因而咱們修改了這部分處理邏輯,再也不動態建立大量的 Region ,再次更新後訪問速度終於恢復了,注意這裏是有兩個系統。

新系統運行改版後的頁面,老系統運行還沒有改版的頁面,新老系統經過 Nginx 進行路由。

通過一夜運行以後,新系統感受雖然沒有以前慢,可是也時常感受不暢!!!可是老系統依然很快。

因而如今的問題是:爲何老系統很快,可是新系統運行一段時間後會變慢。

禮拜二早上醒來以爲不服氣,在牀上操起電腦繼續看各類系統日誌和運行狀態 —— 發現了二者在使用 Redis 服務上的一個區別:

老系統使用 J2Cache 的 hash 模式在 Redis 存儲數據,而新系統使用 J2Cache 的 generic 模式記錄數據。也就是說老系統操做 Redis 使用 hget/hset 這些方法,Region 對應的是 Redis 的一個 key,而具體的緩存數據是 key 對應的子 key 。而新系統直接是 get/set 這樣的方法,也就是說不一樣 Region 的全部 Key 都揉在一塊兒造成一個巨大的哈希表。

那麼會不會是這個緣由致使新系統在運行一段時間後變慢呢?理論上是不該該的,由於 Redis 的處理速度不會由於 key 數量的增長而變慢。但咱們仍是決定一試。

修改 J2Cache 的配置,將 redis.storage 配置值改成 hash ,清理數據,再次更新系統後,到目前運行已經一成天了,一切很是正常。

自此訪問速度問題的處理告一段落。

可是仍有幾個疑點沒有搞清楚:

  1. 爲何 Tomcat 的請求堵塞那麼就沒獲得處理,卻沒有異常信息,難道是隊列還沒滿?
  2. 爲何 Redis 在 key 的數量達到必定程度後響應速度變慢呢?咱們用的是 Redis 3.0.5 版本
  3. 早在 J2Cache 1.x 的時候,當時 Redis 版本還比較低,好像是 2.x ,那時候我測試使用 hash 性能比使用 generic 的低不少,爲何如今反過來了? 

全文完 !

相關文章
相關標籤/搜索