redis持久化、可用性及壓力過大問題的解決

通過學習整理其他優秀資源,本文解決三個問題:

  • redis如何持久化?
  • 生產環境中,redis的可用性如何保證?
  • redis中遇到存到存儲上限如何解決?

一、redis持久化

redis是基於內存的, 內存特點是斷電易失。就必然涉及到持久化操作。redis持久化有兩種方式:快照(rdb)日誌(aof)

1.快照和日誌

快照類似於序列化和反序列化過程。把數據序列化成二進制放到磁盤,加載時把磁盤當中的數據直接反序列化,讀過來,不需要執行什麼。

日誌:redis每用一個操作(寫、修改),就把操作寫到日誌文件裏去。日誌裏存放的是操作指令(快照存的是數據自身)。日誌是恢復的時候,讀到日誌的東西還要去執行,變成數據。因此,日誌比快照恢復的慢。但快照比日誌丟東西丟得多(兩次快照之間掛機了,那麼中間的東西會丟失。)

日誌有三個級別:

  • 每操作(就是每次操作就保存數據fsync做數據同步)。好處:數據完整性比較強。缺點是使redis性能下降。
  • 每秒鐘

(定時器每到1秒,就刷寫)最多也就丟1秒鐘的數據。操作系統os的緩衝(緩衝滿了,os自己會刷寫),所以保證至多丟一個buffer(如果1秒之內buffer滿了,os自己刷寫;如果1s內buffer沒滿,定時器設置1s,也會刷寫。因此最多丟一個buffer的內容)

  • os緩衝刷寫,丟一個buffer的內容

1

2

一般是寫滿buffer才寫入磁盤:程序要調系統調用,即調用內核,操作系統裏有buffer緩衝區,程序要向磁盤中寫數據,要先把數據交給內核的緩衝區,緩衝區滿了之後,

內核纔會把數據刷新到磁盤。程序可以flush緩衝區,讓內核現在就把數據從緩衝區存到磁盤。(這就是爲什麼在關閉之前要flush,不然可能丟東西。)<br>調用fsync()函數可讓操作系統現在把緩衝區的數據寫到磁盤上,而不是等待緩衝區裝滿數據。

  

redis的日誌默認級別是每秒鐘。追求完整性和一致性的時候,就要把級別調高至每操作

快照rdb的優勢是恢復的快但丟失的多,日誌aof的優勢是恢復的數據更完整但恢復速度慢。

2.使用方法

早期是默認開啓快照rdb。因爲不會頻繁的對磁盤有io操作。那時用於緩存,而不是數據庫,丟失一些數據也無所謂。也可以手動開啓日誌aof,但開啓了快照rdb也就不起作用了。

後來(redis4.0)可以混合使用(各有優缺點),日誌aof中包含一個歷史狀態的快照rdb。比如說8點的快照,然後後面追加的日誌。這個混合的還叫做aof日誌。(全是日誌比較慢,混合的是週期(比如每個小時)的把前面的rof變成rdb(二進制),然後再把後面的日誌追加進去)。整體性能高於上面兩者。

 

在redis配置文件中, APPEND ONLY MODE下 的appendonly默認是no,即關閉的。可以打開yes,那麼就開啓了aof。目的文件是appendfilename "appendonly.aof"。三個級別:# appendfsync always(每筆操作都向磁盤刷寫)、appendfsync everysec(每秒鐘刷寫)和# appendfsync no(程序不觸發,讓操作系統自己觸發刷寫)。

新版本在配置文件的APPEND ONLY MODE最後有個aof-use-rdb-preamble yes表示混合模式。在SNAPSHOTTING下,有個dir ./表示存放的路徑是當前文件夾。

 

假如只是aof(沒有rdb)的模式(開啓了aof:appendonly yes,默認是rdb,關閉混合的aof-use-rdb-preamble no),當在redis裏操作時,在./文件夾下的appendonly.aof裏就有指令:*2代表後面有兩個東西。S6代表後面的單詞有6個字符。redis重啓時要讀取這個文件,然後要把裏面set這個過程執行一遍,內存裏面纔會有數據。

 

有個問題,如果刪除k1,再setk1,一直這麼操作,.aof文件會變大,但內存數據反而很少,所以有個壓縮機制,將創建和刪除抵消掉。比如都對k1進行set操作(set k1 aaa; set k1 222.....)日誌只會記錄最後一條。BGREWRITEAOF通過後臺的方式重寫aof(重寫會創建一個當前 AOF 文件的體積優化版本)。

  

當開啓了混合的(aof使用rdb),aof-use-rdb-preamble yes,此時設置值,再BGREWRITEAOF就.aof文件就由指令變成rdb二進制文件(序列化內容:rdb原生的文件做個序列化放到裏面了)。這個時候再設置值,沒有BGREWRITEAOF再打開.aof,就在序列化的內容後面追加剛纔設置值的指令。redis重啓時,.aof二進制內容直接讀,後面的指令就執行。---》比單單執行所有指令快很多。

 

總之,就是利用鏡像的速度,利用日誌的全量(完整性)。

 

二、redis可用性

redis用在生產系統中,有兩種問題:可用性(單點故障,會掛);壓力(存儲上限:存不進去或者高併發訪問不過來)。也適用其他服務。

解決可用性問題,最先想到的是集羣。但更細來說,應該是主從/主備集羣。壓力過大可以使用分片集羣或者代理集羣。都是集羣,因此單單說集羣就不恰當。

 

單點掛了,那麼就多準備幾個備份的(多機),首先就涉及到這幾個redis的數據同步問題,注意這是主從/主備,纔會有數據同步,而分片集羣是不會有數據同步這概念(分片是每個redis存不同的數據)

數據同步

數據同步方式:(1)強一致性:客戶端給主寫了,主先不給客戶端回送消息,而是讓備也去寫數據,備寫成功就通知主,然後主再通知客戶端。(強一致性就是主備內容絕對一致)。問題:主這邊沒問題,而主和備之間有問題(延時、備掛了),那麼會阻塞客戶端,就是強制一致性破壞可用性(從外界來看應用不可用了)問題。

(2)弱一致性:客戶端給主寫了,主立即告訴客戶端成功,然後異步的通知給備(中間有些地方可能有問題)。主掛掉後,備接管可能之前的數據有些丟失,因此叫弱一致性。

(3)最終一致性:假設有個黑盒,具備自身是可靠的,是集羣的(不會掛),主先把數據寫到可靠的黑盒中,這個過程是同步和強一致的,然後不可靠的其他redis在可用的時候就從黑盒中讀回內容,那麼備就會最終具備主掛機之前的狀態。redis沒有使用最終一致性。

redis主從複製默認工作在弱一致性級別。(強一致性也可開啓,但響應速度退化到關係型數據庫)。redis做緩存場景比較多,弱一致性是接受的(丟失點數據)

 redis基於單點故障需要主從複製(集羣方式),特點是節點間數據是全量的(每個redis裏的內容是一樣的,全部都有)。

 

三、負載問題

1.akf劃分

redis實例中數據太多(壓力過大)怎末辦?(1)根據業務劃分數據到不同的redis實例,不同維度存儲。(比如,一個維度是用戶信息的redis的主從,再一個維度是購物車的,再一個是商品詳情的.....)。(2)分片:將一個redis實例的全量數據分散到不同實例,具體分法可以是hash取模(單號hash模上實例的個數),也可以按照區間劃分(0-100,101-200...)

 

 

x軸解決問題:冗餘數據,提高可靠性。y軸解決問題:業務劃分,分治(不同業務治理自己的數據)。z軸對同類數據做負載均衡或者是分片sharding。(相同業務分片)。

這個劃分劃小的過程就是akf。akf是微服務劃分的拆分原則。

2.分片

每個redis存放1/n的數據,但單個redis也可能掛,因此針對單個redis做主從複製。因此分片和主從要混合使用

實現方式:
在客戶端實現。任何大的數據流經客戶端後,就通過算法(映射算法)最終流向不同的redis實例中。弊端:多個客戶端同時消耗這批數據,就誰涉及到算法同步問題,因此在部署和更新版本上有一定難度;客戶端是個service,會消耗指令集佔用cpu內存等-----》拆出去好點。

代理集羣。多個客戶端裏都有個輕量級線程,把數據扔給代理,代理裏面有算法,代理給不同的redis寫不同的數據。如果代理壓力大,也可以做個負載均衡。

兩個問題:數據分片存儲,如果現在是分片2個節點,但未來又要擴展到更多節點,這個擴展好做嗎?客戶端併發時,代理層處理負載均衡,那麼redis能不能不需要代理層,自發滿足負載均衡?

 

解決分片的問題:

redis提出一個槽位(虛擬)的概念。第一步:假設槽位數是1000,算法對數據的key進行hash計算,然後模的是槽位1000,而不是物理節點數,得到key的模數值(0-999)。第二步:用物理節點綁定(映射)不同的模數值。比如0-500的模數值放到node1,500-999映射到node2。好處:未來增加物理節點,將前面node裏的槽位屬於新增節點的遷移到新增節點。

應用場景:HBASE和Elastic Search。HBASE裏有個預分區(HBASE是分佈式的,數據分佈在不同節點),剛開始建表時分100個小表,未來數據放在小表裏。Elastic Search有個分片的概念,分片分多點,以後數據量增大,直接增加物理臺數,就可以動態擴展集羣的分佈式能力。(動態擴縮容)

 

解決負載的問題:

無主模型/無主集羣。(ES在使用環節也是無主的:應用業務接入的尋址操作是無主的,即客戶端可以發送請求給任何一節點,該節點就會變成代理節點,幫助把客戶端的請求分散到所有節點或者找到正確的節點)。redis也是。算法在每一臺redis實例裏,實例裏除了有算法,還有一個映射(節點和槽位的對應)。客戶端現在隨便連個節點,該節點的算法算出區間,然後對應映射,找到正確的節點,再告訴客戶端,客戶端就重新連到正確的節點(這樣客戶端的增刪改查就在正確的節點上。)。

 

 

原文地址:https://www.cnblogs.com/yq055783/p/13043590.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章