那個,其實,我很多年沒碰過技術了,但還是覺得有必要把之前一些處理過的技術問題拿出來,其實每個問題,都是很小的問題,如果單獨說原因和答案都非常簡單,但關鍵是,遇到問題的思考方式和分析方法。
依然是,高手請無視,針對一些初入技術職場的童鞋,希望能對各位遇到問題時候的思考方式有所幫助。
當時情況是這樣,突然有一天,資料庫出現鏈結過多錯誤,導致**報錯。 熟悉mysql並操作過高併發系統的朋友知道,資料連線過多屬於很常見的問題。但當時的情況是,訪問量並不在高峰,按理說不應該有這樣的問題。
看了一下資料庫伺服器的負載,很低,並不存在cpu或記憶體跑滿的問題。
慢查詢日誌沒有異常的sql,更沒有鎖表。
於是就進入資料庫做一下 show processlist的查詢。
有些朋友可能會問,鏈結過多你還能看show processlist麼,那個,mysql裡root比普通使用者多乙個鏈結許可,所以,記得程式切忌用root鏈結,保留乙個給系統分析師用。
意外發現,幾乎所有的sql停留在sleep狀態,而且很多鏈結都持續了好幾秒,甚至十幾秒。
這裡說明一下,如果是用資料中介軟體鏈結池來操作,從中介軟體到資料庫存在固定數字的sleep鏈結是正常的,但從程式端到中介軟體,除非你是長連線,並且需要保持資料庫頻繁操作的應用,否則,通常不建議資料庫保持連線,也就是不應該出現太多sleep操作。
我們的場景就是普通的web應用,php程式而已,都是短鏈結,按理說,程式執行完就應該釋放的,所以這個問題就有點意外。
當然,這個和**的設計也有關係,因為系統用的開源軟體改寫的,涉及資料庫操作還是蠻多的,一般情況下,資料庫操作完應該及時關閉,但由於一般認為php**執行時間很短,所以在**架構有點複雜的情況下,很多都是預設整個程式執行完再關閉。那麼現在問題來了,到底php發生了什麼問題。
我們去web伺服器,看日誌,發現訪問量並沒有異常,也沒有針對我們的攻擊行為,但確實很多php程式執行時間較長,web連線數也明顯多於異常,即便是資料庫重啟,問題依然會重現,那麼這時候,我們工程師就在最常用的php**裡設定斷點,去看**到底卡在哪個環節上執行時間很長,結果,發現是我們的乙個非常重要的常識盲點。原來執行時間最長的,是在最後**資料都執行完,輸出執行 echo 的環節。
在本地做效能測試,壓力測試的時候,我們知道echo 這種語句是基本沒有開銷的,也不太可能成為一種負載的**,但這下我們明白了,echo原來不僅僅是php執行輸出,也包含了網路傳輸的時間開銷。只有客戶端接收到傳輸內容後,echo執行才結束。
而那天的問題,其實是因為同機房有其他公司伺服器被ddos,導致機房出口擁堵,按理說這只是websever的問題,但因為webserver本身有輪詢機制,而且設定的連線數較大,雖然訪問較慢,但沒有崩潰,而因為php**裡mysql鏈結沒有及時釋放,在php執行echo的時間等待較長,導致mysql鏈結過多崩潰。
知道這個問題,解決就簡單了,因為開源系統封裝了輸出template的物件,我們就在這個物件執行的時候,先執行mysql_close(); 這樣只改了一行**,問題就解決了。
但後來發現出了bug,bug的理由很無厘頭,居然部分template 的偽碼裡有資料庫操作,但這個問題解決也簡單,因為畢竟這樣的場景很少, 而且mysql物件也被封裝了,我們就在query方法裡加了一行**,如果沒有資料庫連線,就重建乙個。 這樣,這個重建過程只出現在極少數template裡有mysql操作的場景,對整體系統基本沒有效能干擾。
這個案例說來挺簡單,就是資料庫連線沒有及時釋放造成的,但因為觸動了乙個思維盲區,所以印象深刻。
線上的程式做斷點日誌分析是最常用的分析詭異問題的方法。基於斷點日誌分析,我們可以通過類似二分法,逐步遞進直到精確定位具體到每一行**的執行時間開銷。
大公司可能會把測試環境做的更好更規範,以及有更有經驗的工程師和分析師來解決問題,但創業公司,我建議要給程式設計師和分析人員一些線上應急處理的許可權,否則真的會束手無策,經驗值都是靠犯錯和解決問題來積累的。
案例2:看似正常的負載過高
當時有個新業務資料增長很快,該業務的資料庫伺服器每天處理數百萬次資料查詢請求,uptime比較高,經常在5-6的樣子,cpu負荷較重,運維負責人就發郵件,申請更換更好的伺服器,增加資源。
按理說,這是個合理請求,負載也確實很高,業務也確實增長,但我這個人天性財迷摳門,總覺得這個數字不應該是極限,就登入到資料庫伺服器看了一下,很簡單,我的方法就是先刷show processlist,連續刷幾遍,看資料庫都在執行啥,開銷都集中在什麼狀態,這一看還真就發現問題了,居然經常看到有些mysql程序停留在 storing result to query cache 上。
這事我就納悶了,因為按常規,這個狀態應該是基本沒有時間開銷的,也就是show processlist看到是小概率事件的。
所以就要驗證一下,執行 set profiling=1,然後從show processlist複製一條執行一次,然後執行 show profiles for query 1; 結果意外發現,常規來說執行開銷最大的sending data (這個開銷可不是輸出資料哦,其實是io定址)只有0.002秒,而 storing result to query cache 卻執行了 0.005秒的樣子,千分之五秒,一般人可能就無視了吧,但整個sql執行不到0.01秒,這個開銷比例蠻大的了。
那個,其實這個問題的責任者呢,是我自己,我覺得query cache是個好東西啊,所以開始配置伺服器的時候,還是我自己做的配置,因為伺服器記憶體夠大,我就把query cache設定的比較大,結果sql的反饋結果內容較多的情況下,就出現了query cache的碎片化比較嚴重,反而導致了query cache儲存額外的開銷,我在資料庫裡直接操作將query cache內容重置的命令,再執行這個sql,用profiling去分析,發現這個開銷就沒有了,負載瞬間顯著下降了60%左右。
然後我跟運維負責人說,半夜沒人的時候把資料庫的啟動引數,query cache那塊設定回預設值,重啟一下資料庫,於是就沒再追加預算和伺服器投入。
這個案例本身是我自己的烏龍,因為沒有明確理解query cache的讀取和儲存邏輯,自以為是的調高了引數,在sql返回值較大的情況下,導致了嚴重碎片化,帶來了額外的開銷,雖然每次開銷都極其微小,但由於系統的請求頻次非常高,所以系統不必要的負載就比較大。
那麼這個案例裡,需要分享的方法是,showprocesslist+一定的敏感度,再配合用set profiling去分析具體的開銷,是非常重要的一種分析查詢效能的方法。
案例3:io效能的優化案例
這個案例又是我的錯,唉,我發現我犯的錯誤還是蠻多的,不過我們工程師解決方案非常經典,所以也列在這裡以供參考。
還是乙個非常高併發的業務場景,最開始呢,為了達到查詢的最優化,資料結構還是我設計的,使用了復合索引,確保每次查詢的索引命中率極高,但這個業務場景有乙個問題,就是除了查詢請求很高之外,資料的插入請求基本上是同頻次的。(大部分場景都是資料插入後隨之查詢,個別會有單獨查詢場景),所以插入請求巨大,資料庫的io壓力特別大。
結果我們工程師也是受到我的影響吧,摳門的很,也是盡可能在有限資源下挖潛。結果怎麼做的呢? 說來簡單,索引降級,把兩個欄位的復合索引降到單鍵索引了。
單純從查詢而言,這一降級其實是犧牲了效率,但是犧牲的並不大,但從更新而言,從復合索引降級到單鍵索引,索引更新的io負載就有了明顯的降低,由於查詢的負載開銷遠低於更新的負載開銷,所以這一降級,在查詢與更新同頻的場景下,就變得效果特別好。
這個案例需要分享的經驗是,索引的建立,不但要考慮查詢的語句,更新的語句,也要考慮業務場景中相關的頻次,在更新頻次遠低於查詢頻次時,和更新頻次與查詢頻次相當時,同樣的資料結構,同樣的sql語句,可能索引的設計方案會有重大的調整和改變。
相關舊文
如何應對併發(1) - 關於資料索引
如何應對併發(2) - 請求合併及非同步處理
如何應對併發(3) - 需求裁剪
如何應對併發(4) - 分布式資料庫及反正規化設計
如何應對併發(5) - 關鍵的關鍵,是認識負載
如何應對併發(6) - 瑣碎的日常
mysql也有了很多的版本迭代,很多之前遇到的問題和瓶頸也許現在已經在系統中順暢解決,但我覺得,一些思路和方法依然值得分享。
當然,這些都不是什麼高大上的技術和解決方案,都是實戰中,屌絲創業團隊面臨一些實際問題的響應和處理能力。很多草根創業團隊,其實都是栽倒類似這樣的問題上的。
頂 0 踩
推薦系統 分析
收集使用者資訊的行為記錄模組 分析使用者喜好的模型分析模組 推薦演算法模組 推薦演算法 1.基於內容的推薦系統 content based recommendation 2.協同過濾推薦系統 collaborative filtering recommendation 3.混合推薦系統 hybrid...
系統分析基礎
1.軟體工程定義 總而言之,軟體工程就是把經過實踐考驗而證明正確的管理技術和當前能夠得到的最好的技術方法結合起來。2.軟體危機 定義主要表現 解決途徑 3.comomo模型 定義 cocomo,英文全稱為constructive cost model,中文為構造性成本模型。它是一種精確 易於使用的,...
系統分析步驟
拿到需求資料該怎樣進行系統分析呢?步驟如下 1 業務物件 把系統中的業務物件都找出來,分析其主要屬性和各業務物件之間的關係。業務物件主要屬性可以按大類來分,大類下面是基本屬性。例如進銷存系統中的業務物件包括物品 商 計畫單 訂單 倉庫 庫位 客戶 使用者等。物品的屬性分為基礎屬性 編碼 名稱 型號等...