Redis集群搭建采坑總結

背景

    先澄清一下,整個過程問題都不是我解決的,我在裡面就是起了個打醬油的角色。因為實際上我負責這個項目,整個過程也比較清楚。之前也跟具體負責的同事說過,等過段時間帶他做做項目復盤。結果一直忙,之前做的事情都快忘了也沒帶他做復盤。所以趁著還記得,總結一下這個問題,也算一起做個復盤總結了。

    本周一的時候,我們測試環境遇到一個問題:啟動一個服務就會導致後端調用耗時增加。當時諮詢了對這個問題之前有了解的同事得到的答覆是因為一筆請求發到兩套測試環境(一個請求需要在兩套環境下運行結果做對比),因為這兩套環境共用同一套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,就一句話:那些很多人說只有面試的時候才能用到的東西,我總是發現實際工作中很有用。

 

相關閱讀

    MySQL常見6個考題在實際工作中的運用

    Tair分散式快取

    Elasticsearch實戰-磁碟IO被打滿

    業務開發轉基礎開發,這三種「高可用」架構你會么?