搜尋
首頁後端開發php教程全面掌握Redis服務架構分析與搭建

全面掌握Redis服務架構分析與搭建

Feb 27, 2018 am 10:17 AM
redis服務架構

基於記憶體的Redis應該是目前各種web開發業務中最常用的key-value資料庫了,我們經常在業務中用其儲存使用者登陸態(Session儲存),加速一些熱資料的查詢(相比較mysql而言,速度有數量級的提升),做簡單的訊息佇列(LPUSH和BRPOP)、訂閱發布(PUB/SUB)系統等等。規模比較大的網路公司,一般都會有專門的團隊,將Redis儲存以基礎服務的形式提供給各個業務呼叫。

不過任何一個基礎服務的提供方,都會被呼叫方問起的一個問題是:你的服務是否具有高可用性?最好不要因為你的服務常常出問題,導致我這邊的業務跟著遭殃。最近我所在的專案中也自己搭了一套小型的「高可用」Redis服務,在此做一下自己的總結和思考。

首先我們要定義一下對Redis服務來說怎樣才算是高可用,也就是在各種出現異常的情況下,依然可以正常提供服務。或者寬鬆一些,出現異常的情況下,只經過很短暫的時間即可恢復正常服務。所謂異常,應該至少包含了以下幾種可能性:

【異常1】某個節點伺服器的某個進程突然down掉(例如某開發手殘,把一台伺服器的redis-server進程kill了)

【異常2】某台節點伺服器down掉,相當於這個節點上所有進程都停了(例如某運維手殘,把一個伺服器的電源拔了;例如一些老舊機器出現硬體故障)

【異常3】任兩個節點伺服器之間的通訊中斷了(例如某臨時工手殘,把用於兩個機房通訊的光纜挖斷了)

其實以上任一種異常都是小機率事件,而做到高可用性的基本指導想法就是:多個小機率事件同時發生的機率可以忽略不計。只要我們設計的系統可以容忍短時間內的單點故障,即可實現高可用性。

對於搭建高可用Redis服務,網路上已有了許多方案,例如Keepalived,Codis,Twemproxy,Redis Sentinel。其中Codis和Twemproxy主要是用於大規模的Redis群集中,也是在Redis官方發布Redis Sentinel之前twitter和豌豆莢提供的開源解決方案。我的業務中資料量並不大,所以搞叢集服務反而是浪費機器了。最後在Keepalived和Redis Sentinel之間做了個選擇,選擇了官方的解決方案Redis Sentinel。

Redis Sentinel可以理解為監控Redis Server服務是否正常的進程,並且一旦偵測到不正常,可以自動地將備份(slave)Redis Server啟用,使得外部使用者對Redis服務內部出現的異常無感知。我們按照由簡至繁的步驟,建造一個最小型的高可用的Redis服務。

 

方案1:單機版Redis Server,無Sentinel

一般情況下,我們搭的個人網站,或是平常做開發時,會起一個單一實例的Redis Server。呼叫方直接連接Redis服務即可,甚至Client和Redis本身就處於同一台伺服器上。這種搭配僅適合個人學習娛樂,畢竟這種配置總會有單點故障的問題無法解決。一旦Redis服務進程掛了,或是伺服器1停機了,那麼服務就不可用了。而如果沒有配置Redis資料持久化的話,Redis內部已經儲存的資料也會遺失。

 

方案2:主從同步Redis Server,單一實例Sentinel

為了實現高可用,解決方案1中所述的單點故障問題,我們必須增加一個備份服務,即在兩台伺服器上分別各啟動一個Redis Server進程,一般情況下由master提供服務,slave只負責同步和備份。同時,在額外啟動一個Sentinel進程,監控兩個Redis Server實例的可用性,以便在master掛掉的時候,及時把slave提升到master的角色繼續提供服務,這樣就實現了Redis Server的高可用。這基於一個高可用服務設計的依據,即單點故障本身就是個小機率事件,而多個單點同時故障(即master和slave同時掛掉),可以認為是(基本)不可能發生的事件。

對於Redis服務的呼叫方來說,現在要連接的是Redis Sentinel服務,而不是Redis Server了。常見的呼叫過程是,client先連接Redis Sentinel並詢問目前Redis Server中哪個服務是master,哪些是slave,然後再去連接對應的Redis Server操作。當然目前的第三方函式庫一般都已經實現了這個呼叫過程,不再需要我們手動去實作(例如Nodejs的ioredis,PHP的predis,Golang的go-redis/redis,JAVA的jedis等)。

然而,我們實作了Redis Server服務的主從切換之後,又引入了一個新的問題,即Redis Sentinel本身也是個單點服務,一旦Sentinel進程掛了,那麼客戶端就沒辦法連結Sentinel了。所以說,方案2的配置並無法實現高可用性。

 

##方案3:主從同步Redis Server,雙重實例Sentinel

為了解決方案2的問題,我們把Redis Sentinel進程也額外啟動一份,兩個Sentinel進程同時為客戶端提供服務發現的功能。對於客戶端來說,它可以連接任何一個Redis Sentinel服務,來取得目前Redis Server實例的基本資訊。通常情況下,我們會在Client端配置多個Redis Sentinel的連結位址,Client一旦發現某個位址連接不上,會去試圖連接其他的Sentinel實例,這當然也不需要我們手動實現,各個開發語言中比較熱門的redis連線庫都幫我們實現了這個功能。我們預期是:即使其中一個Redis Sentinel掛掉了,還有另外一個Sentinel可以提供服務。

然而,願景是美好的,現實卻是很殘酷的。如此架構下,依然無法實現Redis服務的高可用。方案3示意圖中,紅線部分是兩台伺服器之間的通信,而我們所設想的異常場景(【異常2】)是,某台伺服器整體down機,不妨假設伺服器1停機,此時,只剩下伺服器2上面的Redis Sentinel和slave Redis Server進程。這時,Sentinel其實是不會將僅剩的slave切換成master繼續服務的,也就導致Redis服務不可用,因為Redis的設定是只有當超過50%的Sentinel進程可以連通並投票選取新的master時,才會真正發生主從切換。本例兩個Sentinel只有一個可以連通,等於50%並不在可以主從切換的場景。

你可能會問,為什麼Redis要有這個50%的設定?假設我們允許小於等於50%的Sentinel連通的場景下也可以進行主從切換。試想【異常3】,也就是伺服器1和伺服器2之間的網路中斷,但是伺服器本身是可以運作的。如下圖所示:

其實對伺服器2來說,伺服器1直接down掉和伺服器1網路連不通是一樣的效果,反正都是突然就無法進行任何通信了。假設網路中斷時我們允許伺服器2的Sentinel把slave切換為master,結果就是你現在擁有了兩個可以對外提供服務的Redis Server。 Client做任何的增刪改操作,有可能落在伺服器1的Redis上,也有可能落在伺服器2的Redis上(取決於Client到底連通的是哪個Sentinel),造成資料混亂。即使後面伺服器1和伺服器2之間的網路又恢復了,那我們也無法把數據統一了(兩份不一樣的數據,到底該信任誰呢?),數據一致性完全被破壞。

 

##方案4:主從同步Redis Server,三個實例Sentinel

鑑於方案3並沒有辦法做到高可用,我們最終的版本就是上圖所示的方案4了。實際上這就是我們最終搭建的架構。我們引入了伺服器3,並且在3上面又搭建起一個Redis Sentinel進程,現在由三個Sentinel進程來管理兩個Redis Server實例。在這種場景下,不管是單一進程故障、還是單一機器故障、還是某兩個機器網路通訊故障,都可以繼續對外提供Redis服務。

實際上,如果你的機器比較空閒,當然也可以把伺服器3上面也開啟一個Redis Server,形成1 master + 2 slave的架構,每個資料都有兩個備份,可用性會提升一些。當然也不是slave越多越好,畢竟主從同步也是需要時間成本的。

在方案4中,一旦伺服器1和其他伺服器的通訊完全中斷,那麼伺服器2和3會將slave切換為master。對於客戶端來說,在這麼一瞬間會有2個master提供服務,而且一旦網路恢復了,那麼所有在中斷期間落在伺服器1上的新資料都會遺失。如果想要部分解決這個問題,可以設定Redis Server進程,讓其在偵測到自己網路有問題的時候,立即停止服務,避免在網路故障期間還有新資料進來(可以參考Redis的min-slaves-to -write和min-slaves-max-lag這兩個配置項目)。

至此,我們就用3台機器搭建了一個高可用的Redis服務。其實網路上還有更節省機器的辦法,就是把一台Sentinel流程放在Client機器上,而不是服務提供者的機器上。只不過在公司裡面,一般服務的提供者和呼叫方並不來自同一個團隊。兩個團隊共同操作同一個機器,很容易因為溝通問題導致一些誤操作,所以出於這種人為因素的考慮,我們還是採用了方案4的架構。而且由於伺服器3上面只跑了一個Sentinel進程,對伺服器資源消耗並不多,還可以用伺服器3來跑一些其他的服務。

 

易用性:像使用單機版Redis一樣使用Redis Sentinel

作為服務的提供方,我們總是會講到使用者體驗問題。在上述方案當中始終有一個讓Client端用的不是那麼舒服的地方。對於單機版Redis,Client端直接連接Redis Server,我們只需要給一個ip和port,Client就可以使用我們的服務了。而改造成Sentinel模式之後,Client不得不採用一些支援Sentinel模式的外部依賴包,並且還要修改自己的Redis連接配置,這對於「矯情」的用戶來講顯然是不能接收的。有沒有辦法還是像在使用單機版的Redis一樣,只給Client一個固定的ip和port就可以提供服務呢?

答案當然是肯定的。這可能就要引入虛擬IP(Virtual IP,VIP),如上圖所示。我們可以把虛擬IP指向Redis Server master所在的伺服器,在發生Redis主從切換的時候,會觸發一個回呼腳本,回呼腳本中將VIP切換到slave所在的伺服器。這樣對Client端來說,他彷彿在使用的依然是單機版的高可用Redis服務。

結語

建構任何一個服務,做到「能用」其實是非常簡單的,就像我們運行一個單機版的Redis。不過一旦要做到“高可用”,事情就會變得複雜起來。業務中使用了額外的兩台伺服器,3個Sentinel進程+1個Slave進程,只是為了確保在那小機率的事故中依然做到服務可用。在實際業務中我們也啟用了supervisor做進程監控,一旦進程意外退出,就會自動嘗試重新啟動。

相關推薦:

linux安裝redis服務以及php redis擴充

以上是全面掌握Redis服務架構分析與搭建的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何防止會話固定攻擊?如何防止會話固定攻擊?Apr 28, 2025 am 12:25 AM

防止會話固定攻擊的有效方法包括:1.在用戶登錄後重新生成會話ID;2.使用安全的會話ID生成算法;3.實施會話超時機制;4.使用HTTPS加密會話數據,這些措施能確保應用在面對會話固定攻擊時堅不可摧。

您如何實施無會話身份驗證?您如何實施無會話身份驗證?Apr 28, 2025 am 12:24 AM

實現無會話身份驗證可以通過使用JSONWebTokens(JWT)來實現,這是一種基於令牌的認證系統,所有的必要信息都存儲在令牌中,無需服務器端會話存儲。 1)使用JWT生成和驗證令牌,2)確保使用HTTPS防止令牌被截獲,3)在客戶端安全存儲令牌,4)在服務器端驗證令牌以防篡改,5)實現令牌撤銷機制,如使用短期訪問令牌和長期刷新令牌。

PHP會議有哪些常見的安全風險?PHP會議有哪些常見的安全風險?Apr 28, 2025 am 12:24 AM

PHP會話的安全風險主要包括會話劫持、會話固定、會話預測和會話中毒。 1.會話劫持可以通過使用HTTPS和保護cookie來防範。 2.會話固定可以通過在用戶登錄前重新生成會話ID來避免。 3.會話預測需要確保會話ID的隨機性和不可預測性。 4.會話中毒可以通過對會話數據進行驗證和過濾來預防。

您如何銷毀PHP會議?您如何銷毀PHP會議?Apr 28, 2025 am 12:16 AM

銷毀PHP會話需要先啟動會話,然後清除數據並銷毀會話文件。 1.使用session_start()啟動會話。 2.用session_unset()清除會話數據。 3.最後用session_destroy()銷毀會話文件,確保數據安全和資源釋放。

如何更改PHP中的默認會話保存路徑?如何更改PHP中的默認會話保存路徑?Apr 28, 2025 am 12:12 AM

如何改變PHP的默認會話保存路徑?可以通過以下步驟實現:在PHP腳本中使用session_save_path('/var/www/sessions');session_start();設置會話保存路徑。在php.ini文件中設置session.save_path="/var/www/sessions"來全局改變會話保存路徑。使用Memcached或Redis存儲會話數據,如ini_set('session.save_handler','memcached');ini_set(

您如何修改PHP會話中存儲的數據?您如何修改PHP會話中存儲的數據?Apr 27, 2025 am 12:23 AM

tomodifyDataNaphPsession,startTheSessionWithSession_start(),然後使用$ _sessionToset,修改,orremovevariables.1)startThesession.2)setthesession.2)使用$ _session.3)setormodifysessessvariables.3)emovervariableswithunset()

舉一個在PHP會話中存儲數組的示例。舉一個在PHP會話中存儲數組的示例。Apr 27, 2025 am 12:20 AM

在PHP會話中可以存儲數組。 1.啟動會話,使用session_start()。 2.創建數組並存儲在$_SESSION中。 3.通過$_SESSION檢索數組。 4.優化會話數據以提升性能。

垃圾收集如何用於PHP會議?垃圾收集如何用於PHP會議?Apr 27, 2025 am 12:19 AM

PHP會話垃圾回收通過概率機制觸發,清理過期會話數據。 1)配置文件中設置觸發概率和會話生命週期;2)可使用cron任務優化高負載應用;3)需平衡垃圾回收頻率與性能,避免數據丟失。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具