背景
先澄清一下,整個過程問題都不是我解決的,我在裡面就是起了個打醬油的角色。因為實際上我負責這個專案,整個過程也比較清楚。之前也跟具體負責的同事說過,等過段時間帶他做做專案覆盤。結果一直忙,之前做的事情都快忘了也沒帶他做覆盤。所以趁著還記得,總結一下這個問題,也算一起做個覆盤總結了。
本週一的時候,我們測試環境遇到一個問題:啟動一個服務就會導致後端呼叫耗時增加。當時諮詢了對這個問題之前有了解的同事得到的答覆是因為一筆請求發到兩套測試環境(一個請求需要在兩套環境下執行結果做對比),因為這兩套環境共用同一套redis叢集。收到第二個相同請求的時候,會將這筆請求標記為重複請求。下游接收到這筆請求是重複的,需要重新查詢資料庫驗證請求是否重複,不是的話做一個糾正。所以這時候會造成請求延遲升高。
負責解決這個問題的同事小A就問我:那是不是再搭建一套將兩套Redis叢集分開就解決了。我說不一定,還有解釋不通的地方:一個環境服務不啟動不寫redis,另一個環境服務啟動寫redis的時候也會遇到這個問題。
於是小A找了這個服務相關負責的同事瞭解業務。因為測試環境的總責任人是我,所以瞭解業務的時候,小A也把我拉了一起了解。通過同事的講述瞭解到一個環境中服務要寫兩個機房。如果兩個機房的Redis是同一套也會被標記成重複請求。
至此,解決環境問題的方法有了答案:每套環境要搭建兩套Redis叢集,兩個環境4套Redis叢集來解決問題。
往往,一個答案只是一系列問題的開始。
時間線
我們的搭建方案是直接在使用Redis的服務上搭建連線它的兩套Redis叢集,只改下埠,多跑兩個程式。
問題1:伺服器退出登入Redis服務會停止
小A告訴我遇到問題的現象:按照網上經典的安裝啟動教程,啟動成功了。但是當幹會兒別的,ssh自動退出登入之後再看Redis服務就停止了。
我聽到這裡首先想到的是這個現象基本可以斷定是以非daemon程式在執行,於是我上網上找了以deamon方式執行的命令發給小A:
redis-server ./redis.conf --daemonize yes
小A看了解決方法補充到那一定也可以在配置檔案裡直接配置daemon方式執行。我表示贊同,他也是這麼做的。我當時沒有點破,相信剛畢業的他不久也自己會發現配置檔案和顯示命令實際上是一回事。只是一個是永久生效,一個是每次執行時生效。而直接用這條命令只是為了說明本質問題。
問題2:服務連線Redis報錯Not Auth
小A又向我反饋報了一個錯,說他在網上查的是Redis版本問題,估計需要重新搭建Redis。我過去看了一下:Redis叢集是3.X的版本,jedis客戶端用的是2.9的版本。沒有聽說過Redis3.X的版本有不向下相容的問題,同時因為這個Redis是從負責Redis的團隊要過來的安裝包,應該和現在跑著的是一個版本。如果懷疑Redis的團隊發的安裝包與之前不一樣的話,我也確信之前肯定版本不會低於3.0,因為Redis是從3.0之後才支援叢集的。所以我判定不是Redis版本問題。讓他再查查。實際上我的意思是讓他換關鍵詞來查。比如可以按照報錯的提示原因來查,也可以按照異常來查,不同的關鍵詞搜尋可以獲得不同的資訊。
然後我看了報的錯:其他的沒細看,只見赫然寫著:Not Auth。我就問:Redis服務有沒有設定密碼。他說沒有,還演示了一下,我在旁邊確認了沒有。就檢視客戶端配置有沒有配置密碼。果然客戶端裡有密碼配置。這就與服務端不匹配了。
問題3:報錯cluster support disabled
小A將客戶端密碼去掉重新打包部署之後,Not Auth的錯不報了,但是其實報了兩個錯,還有一個錯沒解決:就是提示cluster support disabled。
我說叢集方式啟動應該就是一個配置,應該有個cluster-enabled什麼的從no改成yes。我還出了個餿主意(注意這裡用到的餿主意,想想《紅樓夢》裡每句話都是劇透,這裡也不例外):我說理論上一臺叢集也可以算一個叢集。應該可以直接改個配置就以叢集方式啟動了。
小A按照我說的思路用直接改配置為叢集的方法,客戶端再啟動果然沒有報錯了。
問題4:請求延遲沒有好轉,Redis服務端沒有寫入成功資料
客戶端沒有報錯之後,小A重試原問題現場,請求延遲沒有好轉。另外,還發現Redis服務端沒有寫入成功的資料。
這次我和小A首先一起排查配置有沒有配置對。發現配置沒有問題,我就跟小A說:讓他多打日誌。客戶端連線的地方打一些,讀寫資料的地方打一些。
通過這個方法,小A定位到客戶端連線的連線池為空。最終自己排查到是一臺機器的叢集的雜湊槽在一臺機器情況下雜湊槽分配有問題,資料寫入失敗。最後每個叢集多起了2個Redis程式做成3個節點的叢集解決了問題。
可優化的排查思路分析
在問題4排查的時候,我和小A一起檢查了配置是否正確來確認Redis請求是請求到了正確的服務端。其實,有個更為直接和說明問題的方法:抓包。可以tcpdump埠查請求流量是不是正確從客戶端發出來了,被轉發到了哪裡。
在《技術方案設計的方法》裡我也提到,很多時候搜尋不到自己想要的資訊很可能是關鍵詞的問題。排查問題的時候也可以試著換換關鍵詞來搜尋。
根本原因分析
這裡面有個問題沒有徹底搞清楚:為什麼一臺機器的Redis叢集會有問題。
問了小A,當時異常時getSlots方法時返回了空。就是說問題實際上可能是slot沒有被分配。
我就問他單臺機器的時候有沒有在redis-cli客戶端上執行cluster info命令。他給我發了下面的執行情況截圖。
這張截圖驗證了我的猜想,slot沒有被分配,叢集狀態為失敗,所以連線不上。
那需要連線上的條件並非是叢集裡有幾個節點,而是slots分配,叢集狀態成功。
為了驗證這個猜想,我搭建了一個一個節點的叢集,手動cluster addslots了0到16383個slot。叢集判斷16384個slot都分配完畢,自動狀態改成OK。
這整個過程說明了:網上都是說Redis叢集必須是3個節點以上的最好是單數個節點來啟動。單數個節點是為了投票的時候可以三局兩勝得出結論:一半以上的節點掛掉整個叢集不可用。而對於Redis根本上判斷叢集是否可用是根據slot有沒有完整的16384個slot在提供服務決定的。
總結
我覺得在整個過程中小A的表現我覺得很OK的。有4點:
1>主觀能動性
在過程中,他自己通過網上搜素找資源,自己解決了很多問題。整個問題處理過程中其實沒花費我多少時間,花時間的事情他都自己解決了。
2>合理的利用了各種資源
對於業務不理解,他找了理解業務的同事。技術問題搞不定他找了我。因為我對專案負責,所以找我是很合情合理的。同時,我是很希望他遇到這種事情來找我的。因為他找我證明他是信任我的,相信我能一定程度幫到他。第二,他找我是把我當成一種資源。作為資源我被需要,是有價值的。被需要讓人覺得很踏實。
我在有搞不定的事情的時候也向上尋求幫助。比如之前需要其他組協作的時候人家有排期遇到困難,領匯出面幫忙搞定了。還有申請資源由於暫時性資源緊張,申請不到,也是更上級出面幫忙搞定了。一個稱職的上級一定可以成為一種資源,也願意讓自己成為資源。但是成為資源的形式不同,有的可能提供的是戰略,有的提供的是精神支援等。
3>事後總結
問題解決後,小A有自己寫wiki總結事情經過,避免後人採坑,同時自身也有總結收穫。
4>及時溝通
中間過程中,他每個關鍵步驟都有及時跟我溝通。因為解決完後他反饋給我:他自己覺得對於redis原理還沒有理解,所以不清楚為什麼3個節點就OK的原因。我因為了解他的想法,所以才自己又實驗給出一個根本原因分析。
關於Redis,就一句話:那些很多人說只有面試的時候才能用到的東西,我總是發現實際工作中很有用。
相關閱讀