目錄
一、概述
1、Redis Sentinel
1.1、docker配置Redis Sentinel環(huán)境
2、Redis存儲方案
2.1、哈希鏈
2.2、哈希環(huán)
3、Redis分區(qū)(Partitioning)?
4、Redis面試題
一、概述
1、Redis Sentinel
Redis Sentinel為Redis提供了高可用解決方案。實際上這意味著使用Sentinel可以部署一套Redis,在沒有人為干預的情況下去應付各種各樣的失敗事件。
Redis Sentinel同時提供了一些其他的功能,例如:監(jiān)控、通知、并為client提供配置。
下面是Sentinel的功能列表:
- 監(jiān)控(Monitoring):Sentinel不斷的去檢查你的主從實例是否按照預期在工作。
- 通知(Notification):Sentinel可以通過一個api來通知系統(tǒng)管理員或者另外的應用程序,被監(jiān)控的Redis實例有一些問題。
- 自動故障轉(zhuǎn)移(Automatic failover):如果一個主節(jié)點沒有按照預期工作,Sentinel會開始故障轉(zhuǎn)移過程,把一個從節(jié)點提升為主節(jié)點,并重新配置其他的從節(jié)點使用新的主節(jié)點,使用Redis服務(wù)的應用程序在連接的時候也被通知新的地址。
- 配置提供者(Configuration provider):Sentinel給客戶端的服務(wù)發(fā)現(xiàn)提供來源:對于一個給定的服務(wù),客戶端連接到Sentinels來尋找當前主節(jié)點的地址。當故障轉(zhuǎn)移發(fā)生的時候,Sentinels將報告新的地址。
1.1、docker配置Redis Sentinel環(huán)境
后續(xù)補充...
2、Redis存儲方案
2.1、哈希鏈
原文鏈接:https://blog.csdn.net/Brave_heart4pzj/article/details/126448985
哈希鏈
原理簡介:每個數(shù)據(jù)存儲進來的時候,要根據(jù)hash算法,進行算值取余,存入到對應的機器中。取數(shù)據(jù)的時候,用同樣的hash算法對key進行計算,即可取出數(shù)據(jù)。
應用場景:
Redis集群擴容或宕機縮減,那么就需要進行全庫數(shù)據(jù)的重洗,hash取模的值調(diào)整。這樣,就比較耗費時間。所以,該方案,要預先估計一下自己公司業(yè)務(wù)的數(shù)據(jù)量多大,服務(wù)器的存儲能力多大,然后,考慮在擴容時,所需的時間多久,只要在允許的時間范圍內(nèi),能夠完成重洗數(shù)據(jù),那就可以采取該方案。該方案的一個好處就是,簡單。存數(shù)據(jù)簡單,取數(shù)據(jù)簡單,理解容易。
哈希環(huán)上面說的Hash鏈,只經(jīng)過了1次hash,即把key hash到對應的機器編號。
而Hash環(huán)有2次Hash:
(1)把所有機器編號hash到這個環(huán)上
(2)把key也hash到這個環(huán)上。然后在這個環(huán)上進行匹配,看這個key和哪臺機器匹配。這樣,每個機器負責對應段上的數(shù)據(jù)。
應用場景
當hash鏈性能滿足不了公司業(yè)務(wù)數(shù)據(jù)量的時候,就要采取該方案進行性能提升。
當服務(wù)器縮減時,對應段數(shù)據(jù)向下游轉(zhuǎn)移即可,這樣,就不會影響到其他段服務(wù)器的數(shù)據(jù)。
當服務(wù)器擴容時,對應服務(wù)器下游的服務(wù)器數(shù)據(jù)要進行重洗,把部分數(shù)據(jù)轉(zhuǎn)移到新擴容的服務(wù)器上即可。這樣,在查找時,按照最新的hash算法取余,即可取出對應的數(shù)據(jù)。
這相較于hash鏈,進行全庫沖洗,還是節(jié)省了很多
也就是說,hash鏈和hash環(huán),在新增服務(wù)器的時候,都是要沖洗數(shù)據(jù)的,只是,hash鏈是全庫沖洗(算法復雜度是N),hash環(huán)是下游節(jié)點沖洗(算法復雜度是1)
那么會有道友問,我直接上第二種方案不就得了。
這顯然是不行的。
原因:
hash環(huán)是有大小的,它的特點是把hash鏈首尾相連,那么,假設(shè)你公司業(yè)務(wù)只有百萬級數(shù)據(jù)量,你設(shè)置成一個hash環(huán)。假設(shè),hash環(huán)周長是100,小廠有4臺服務(wù)器,第一次可以人為均勻分布到環(huán)上,但是,如果業(yè)務(wù)量數(shù)據(jù)增加,導致需要擴容。這時候,如果你對hash環(huán)進行擴周長,如果不重新分配服務(wù)器在環(huán)上的位置,那就會出現(xiàn)數(shù)據(jù)傾斜問題,如果,重新均勻分布服務(wù)器在環(huán)上的位置,那么,就要全庫重洗數(shù)據(jù)。所以,這樣就和hash鏈沒什么區(qū)別。還多出一個數(shù)據(jù)傾斜問題。那么有道友就說了,那我把hash環(huán)周長設(shè)置的超大。這樣,不就可以減輕擴容時,數(shù)據(jù)傾斜問題的嚴重性了嗎?并不是這樣,當你保持環(huán)周長不變的前提下擴容的時候,數(shù)據(jù)傾斜和環(huán)的周長并沒有關(guān)系。只是和你擴容的服務(wù)器策略有關(guān),就是,假設(shè)第一次設(shè)置4臺服務(wù)器,那么,你擴容的服務(wù)器必須是2的N次方臺,這樣才能人為的避免數(shù)據(jù)傾斜。那么,你小廠有這個實力嗎?顯然沒有,不劃算。
另外,你的環(huán)周長越大,也就意味著取余的除數(shù)越大,那么,計算取余的時間就越久,比如,你對2取余,口算即可。你對2的32次方取余,那就要多用很多時間,這樣,隨著積累,你浪費的時間就很多了。相對于公司業(yè)務(wù),數(shù)據(jù)量不大,但是,損耗的計算時間卻很多,那就很不劃算了。所以,環(huán)的周長也是要考慮的點。
所以,使用hash環(huán)算法,要考慮兩點
1、公司自身實力,每次擴容需要的服務(wù)器數(shù)據(jù)量是:a*2^n。其中,a是第一次均勻分布的服務(wù)器數(shù)據(jù)量,n>=0的整數(shù)。這個擴容方法,解決數(shù)據(jù)傾斜問題。
2、hash環(huán)周長大小選擇。周長越大,計算越耗費時間。所以,要根據(jù)公司業(yè)務(wù)量大小,選擇合理的周長大小,不能太小,否則經(jīng)常擴容,不能太大,浪漫每次的取余時間。
3、數(shù)據(jù)傾斜問題的本質(zhì),就在于服務(wù)器節(jié)點在環(huán)上的分布是否均勻還是密集。分布密集了,那就會出現(xiàn)數(shù)據(jù)傾斜問題。
2.2、哈希環(huán)
原文鏈接:https://www.cnblogs.com/lpfuture/p/5796398.html
一致性Hash算法背景
一致性哈希算法在1997年由麻省理工學院的Karger等人在解決分布式Cache中提出的,設(shè)計目標是為了解決因特網(wǎng)中的熱點(Hot spot)問題,初衷和CARP十分類似。一致性哈希修正了CARP使用的簡單哈希算法帶來的問題,使得DHT可以在P2P環(huán)境中真正得到應用。
但現(xiàn)在一致性hash算法在分布式系統(tǒng)中也得到了廣泛應用,研究過memcached緩存數(shù)據(jù)庫的人都知道,memcached服務(wù)器端本身不提供分布式cache的一致性,而是由客戶端來提供,具體在計算一致性hash時采用如下步驟:
- 首先求出memcached服務(wù)器(節(jié)點)的哈希值,并將其配置到0~232的圓(continuum)上。
- 然后采用同樣的方法求出存儲數(shù)據(jù)的鍵的哈希值,并映射到相同的圓上。
- 然后從數(shù)據(jù)映射到的位置開始順時針查找,將數(shù)據(jù)保存到找到的第一個服務(wù)器上。如果超過232仍然找不到服務(wù)器,就會保存到第一臺memcached服務(wù)器上。
從上圖的狀態(tài)中添加一臺memcached服務(wù)器。余數(shù)分布式算法由于保存鍵的服務(wù)器會發(fā)生巨大變化而影響緩存的命中率,但Consistent Hashing中,只有在園(continuum)上增加服務(wù)器的地點逆時針方向的第一臺服務(wù)器上的鍵會受到影響,如下圖所示:
一致性Hash性質(zhì)
考慮到分布式系統(tǒng)每個節(jié)點都有可能失效,并且新的節(jié)點很可能動態(tài)的增加進來,如何保證當系統(tǒng)的節(jié)點數(shù)目發(fā)生變化時仍然能夠?qū)ν馓峁┝己玫姆?wù),這是值得考慮的,尤其實在設(shè)計分布式緩存系統(tǒng)時,如果某臺服務(wù)器失效,對于整個系統(tǒng)來說如果不采用合適的算法來保證一致性,那么緩存于系統(tǒng)中的所有數(shù)據(jù)都可能會失效(即由于系統(tǒng)節(jié)點數(shù)目變少,客戶端在請求某一對象時需要重新計算其hash值(通常與系統(tǒng)中的節(jié)點數(shù)目有關(guān)),由于hash值已經(jīng)改變,所以很可能找不到保存該對象的服務(wù)器節(jié)點),因此一致性hash就顯得至關(guān)重要,良好的分布式cahce系統(tǒng)中的一致性hash算法應該滿足以下幾個方面:
- 平衡性(Balance)
平衡性是指哈希的結(jié)果能夠盡可能分布到所有的緩沖中去,這樣可以使得所有的緩沖空間都得到利用。很多哈希算法都能夠滿足這一條件。
- 單調(diào)性(Monotonicity)
單調(diào)性是指如果已經(jīng)有一些內(nèi)容通過哈希分派到了相應的緩沖中,又有新的緩沖區(qū)加入到系統(tǒng)中,那么哈希的結(jié)果應能夠保證原有已分配的內(nèi)容可以被映射到新的緩沖區(qū)中去,而不會被映射到舊的緩沖集合中的其他緩沖區(qū)。簡單的哈希算法往往不能滿足單調(diào)性的要求,如最簡單的線性哈希:x = (ax + b) mod (P),在上式中,P表示全部緩沖的大小。不難看出,當緩沖大小發(fā)生變化時(從P1到P2),原來所有的哈希結(jié)果均會發(fā)生變化,從而不滿足單調(diào)性的要求。哈希結(jié)果的變化意味著當緩沖空間發(fā)生變化時,所有的映射關(guān)系需要在系統(tǒng)內(nèi)全部更新。而在P2P系統(tǒng)內(nèi),緩沖的變化等價于Peer加入或退出系統(tǒng),這一情況在P2P系統(tǒng)中會頻繁發(fā)生,因此會帶來極大計算和傳輸負荷。單調(diào)性就是要求哈希算法能夠應對這種情況。
- 分散性(Spread)
在分布式環(huán)境中,終端有可能看不到所有的緩沖,而是只能看到其中的一部分。當終端希望通過哈希過程將內(nèi)容映射到緩沖上時,由于不同終端所見的緩沖范圍有可能不同,從而導致哈希的結(jié)果不一致,最終的結(jié)果是相同的內(nèi)容被不同的終端映射到不同的緩沖區(qū)中。這種情況顯然是應該避免的,因為它導致相同內(nèi)容被存儲到不同緩沖中去,降低了系統(tǒng)存儲的效率。分散性的定義就是上述情況發(fā)生的嚴重程度。好的哈希算法應能夠盡量避免不一致的情況發(fā)生,也就是盡量降低分散性。
- 負載(Load)
負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內(nèi)容映射到不同的緩沖區(qū)中,那么對于一個特定的緩沖區(qū)而言,也可能被不同的用戶映射為不同的內(nèi)容。與分散性一樣,這種情況也是應當避免的,因此好的哈希算法應能夠盡量降低緩沖的負荷。
- 平滑性(Smoothness)
平滑性是指緩存服務(wù)器的數(shù)目平滑改變和緩存對象的平滑改變是一致的。
原理
基本概念
一致性哈希算法(Consistent Hashing)最早在論文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。簡單來說,一致性哈希將整個哈希值空間組織成一個虛擬的圓環(huán),如假設(shè)某哈希函數(shù)H的值空間為0-2^32-1(即哈希值是一個32位無符號整形),整個哈??臻g環(huán)如下:
整個空間按順時針方向組織。0和232-1在零點中方向重合。
下一步將各個服務(wù)器使用Hash進行一個哈希,具體可以選擇服務(wù)器的ip或主機名作為關(guān)鍵字進行哈希,這樣每臺機器就能確定其在哈希環(huán)上的位置,這里假設(shè)將上文中四臺服務(wù)器使用ip地址哈希后在環(huán)空間的位置如下:
接下來使用如下算法定位數(shù)據(jù)訪問到相應服務(wù)器:將數(shù)據(jù)key使用相同的函數(shù)Hash計算出哈希值,并確定此數(shù)據(jù)在環(huán)上的位置,從此位置沿環(huán)順時針“行走”,第一臺遇到的服務(wù)器就是其應該定位到的服務(wù)器。
例如我們有Object A、Object B、Object C、Object D四個數(shù)據(jù)對象,經(jīng)過哈希計算后,在環(huán)空間上的位置如下:
根據(jù)一致性哈希算法,數(shù)據(jù)A會被定為到Node A上,B被定為到Node B上,C被定為到Node C上,D被定為到Node D上。
下面分析一致性哈希算法的容錯性和可擴展性?,F(xiàn)假設(shè)Node C不幸宕機,可以看到此時對象A、B、D不會受到影響,只有C對象被重定位到Node D。一般的,在一致性哈希算法中,如果一臺服務(wù)器不可用,則受影響的數(shù)據(jù)僅僅是此服務(wù)器到其環(huán)空間中前一臺服務(wù)器(即沿著逆時針方向行走遇到的第一臺服務(wù)器)之間數(shù)據(jù),其它不會受到影響。
下面考慮另外一種情況,如果在系統(tǒng)中增加一臺服務(wù)器Node X,如下圖所示:
此時對象Object A、B、D不受影響,只有對象C需要重定位到新的Node X 。一般的,在一致性哈希算法中,如果增加一臺服務(wù)器,則受影響的數(shù)據(jù)僅僅是新服務(wù)器到其環(huán)空間中前一臺服務(wù)器(即沿著逆時針方向行走遇到的第一臺服務(wù)器)之間數(shù)據(jù),其它數(shù)據(jù)也不會受到影響。
綜上所述,一致性哈希算法對于節(jié)點的增減都只需重定位環(huán)空間中的一小部分數(shù)據(jù),具有較好的容錯性和可擴展性。
另外,一致性哈希算法在服務(wù)節(jié)點太少時,容易因為節(jié)點分部不均勻而造成數(shù)據(jù)傾斜問題。例如系統(tǒng)中只有兩臺服務(wù)器,其環(huán)分布如下,
此時必然造成大量數(shù)據(jù)集中到Node A上,而只有極少量會定位到Node B上。為了解決這種數(shù)據(jù)傾斜問題,一致性哈希算法引入了虛擬節(jié)點機制,即對每一個服務(wù)節(jié)點計算多個哈希,每個計算結(jié)果位置都放置一個此服務(wù)節(jié)點,稱為虛擬節(jié)點。具體做法可以在服務(wù)器ip或主機名的后面增加編號來實現(xiàn)。例如上面的情況,可以為每臺服務(wù)器計算三個虛擬節(jié)點,于是可以分別計算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六個虛擬節(jié)點:
同時數(shù)據(jù)定位算法不變,只是多了一步虛擬節(jié)點到實際節(jié)點的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三個虛擬節(jié)點的數(shù)據(jù)均定位到Node A上。這樣就解決了服務(wù)節(jié)點少時數(shù)據(jù)傾斜的問題。在實際應用中,通常將虛擬節(jié)點數(shù)設(shè)置為32甚至更大,因此即使很少的服務(wù)節(jié)點也能做到相對均勻的數(shù)據(jù)分布。
3、Redis分區(qū)(Partitioning)?
分區(qū)就是把你的數(shù)據(jù)分割到多個Redis實例中的一個過程,因此每個實例僅僅包含部分鍵。
Redis 集群和數(shù)據(jù)分片
Redis集群不是使用一致性哈希,而是使用哈希槽。整個redis集群有16384個哈希槽,決定一個key應該分配到那個槽的算法是:計算該key的CRC16結(jié)果再模16834。
集群中的每個節(jié)點負責一部分哈希槽,比如集群中有3個節(jié)點,則:
- 節(jié)點A存儲的哈希槽范圍是:0 -- 5500
- 節(jié)點B存儲的哈希槽范圍是:5501 -- 11000
- 節(jié)點C存儲的哈希槽范圍是:11001 -- 16384
這樣的分布方式方便節(jié)點的添加和刪除。比如,需要新增一個節(jié)點D,只需要把A、B、C中的部分哈希槽數(shù)據(jù)移到D節(jié)點。同樣,如果希望在集群中刪除A節(jié)點,只需要把A節(jié)點的哈希槽的數(shù)據(jù)移到B和C節(jié)點,當A節(jié)點的數(shù)據(jù)全部被移走后,A節(jié)點就可以完全從集群中刪除。
因為把哈希槽從一個節(jié)點移到另一個節(jié)點是不需要停機的,所以,增加或刪除節(jié)點,或更改節(jié)點上的哈希槽,也是不需要停機的。
集群支持通過一個命令(或事務(wù), 或lua腳本)同時操作多個key。通過"哈希標簽"的概念,用戶可以讓多個key分配到同一個哈希槽。哈希標簽在集群詳細文檔中有描述,這里做個簡單介紹:如果key含有大括號"{}",則只有大括號中的字符串會參與哈希,比如"this{foo}"和"another{foo}"這2個key會分配到同一個哈希槽,所以可以在一個命令中同時操作他們。
4、Redis面試題
4.1、使用過Redis分布式鎖么,它是怎么實現(xiàn)的?
先拿setnx來爭搶鎖,搶到之后,再用expire給鎖加一個過期時間防止鎖忘記了釋放。
4.2、什么是緩存擊穿?如何避免?什么是緩存穿透?如何避免?什么是緩存雪崩?何如避免?
緩存擊穿
KEY的過期,造成并發(fā)訪問數(shù)據(jù)庫
如何避免?
先拿setnx來爭搶鎖,搶到之后,get key? setnx ok去DB false,sleep 1。
1、防止死鎖:設(shè)置鎖的過期時間。2、沒掛,鎖超時:更新鎖時間
緩存穿透
一般的緩存系統(tǒng),都是按照key去緩存查詢,如果不存在對應的value,就應該去后端系統(tǒng)查找(比如DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對后端系統(tǒng)造成很大的壓力。這就叫做緩存穿透。
如何避免?
1:對查詢結(jié)果為空的情況也進行緩存,緩存時間設(shè)置短一點,或者該key對應的數(shù)據(jù)insert了之后清理緩存。
2:對一定不存在的key進行過濾??梢园阉械目赡艽嬖诘膋ey放到一個大的Bitmap中,查詢時通過該bitmap過濾。
布隆過濾器
緩存雪崩
當緩存服務(wù)器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給后端系統(tǒng)帶來很大壓力。導致系統(tǒng)崩潰。
如何避免?
1:在緩存失效后,通過加鎖或者隊列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個key只允許一個線程查詢數(shù)據(jù)和寫緩存,其他線程等待。
2:做二級緩存,A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設(shè)置為短期,A2設(shè)置為長期
3:不同的key,設(shè)置不同的過期時間,讓緩存失效的時間點盡量均勻。隨機過期時間。
零點:業(yè)務(wù)層增加零點延遲-->強依賴擊穿解決方案。
4.3、解釋Redis的復制功能?
Redis 可以使用主從同步,從從同步。第一次同步時,主節(jié)點做一次 bgsave,并同時將后續(xù)修改操作記錄到內(nèi)存 buffer,待完成后將 rdb 文件全量同步到復制節(jié)點,復制節(jié)點接受完成后將 rdb 鏡像加載到內(nèi)存。加載完成后,再通知主節(jié)點將期間修改的操作記錄同步到復制節(jié)點進行重放就完成了同步過程。
Redis緩存數(shù)據(jù)庫(一)文章來源:http://www.zghlxwxcb.cn/news/detail-454804.html
干我們這行,啥時候懈怠,就意味著長進的停止,長進的停止就意味著被淘汰,只能往前沖,直到鳳凰涅槃的一天!文章來源地址http://www.zghlxwxcb.cn/news/detail-454804.html
到了這里,關(guān)于Redis緩存數(shù)據(jù)庫(四)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!