1. 程式人生 > 實用技巧 >redis-持久化-主從-哨兵-高可用

redis-持久化-主從-哨兵-高可用

Redis持久化


持久化重點!!官網文件:http://www.redis.cn/topics/persistence.html

在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,也就是快照,它恢復時是將快照檔案直接讀到記憶體裡。

Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到一個臨時檔案中,待持久化過程都結束了,在用這個臨時檔案替換上次持久化好的檔案,整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能。如果需要進行大規模資料恢復,且對資料恢復的完整性不是非常敏感,那麼RDB方式要比AOF方式更加高效。RDB的缺點是最後一次持久化資料後的可能會丟失。

RDB

生產環境需要進行備份(dump.rdb

RDB儲存的檔案是dump.rdb 都是在配置檔案中配置的。

#save 60 10000
save 60 5 #測試:60秒內修改 5次 key,就會觸發rdb操作
  1. save 的規則滿足的情況下,會自動觸發rdb規則

  2. 執行flushall命令、也會觸發rdb規則

  3. 退出redis,也會產生rdb檔案

備份就自動生成一個dump.rdb檔案

恢復:

  • 只需要將 rdb檔案放在redis啟動目錄即可,redis啟動時會檢測dump.rdb恢復其中的資料

  • 檢視需要存在位置

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" #如果在這個目錄下存在dump.rdb 檔案,啟動時就會自動恢復其中的資料
  • 優點:

    1. 適合大規模的資料恢復!dump.rdb

    2. 如果對資料完整性要求不高!

  • 缺點:

    1. 需要一定的時間間隔進行操作,如果redis意外宕機,最後一次修改資料丟失了

    2. fork程序的時候,會佔用一定的記憶體空間。

AOF


aof是將所有命令以日誌的形式都記錄下來,history,將redis執行過得所有指令記錄下來,(讀操作不記錄)。恢復的時候就根據這個日誌檔案的內容將寫指令從頭到尾再執行一遍以完成資料的恢復工作。

AOF格式是appendonly.aof檔案

預設是不開啟的:

appendonly no  #預設狀態  需要手動開啟

# appendfsync always #每次修改都執行、並完成磁碟同步、最安全
appendfsync everysec #每秒執行一次 、並完成磁碟同步
# appendfsync no #從不執行、寫入aof檔案,不等待磁碟同步、最快

no-appendfsync-on-rewrite no #是否重寫、no狀態保證資料安全性
#no-appendfsync-on-rewrite引數。如果該引數設定為no,是最安全的方式,不會丟失資料,但是要忍受阻塞的問題。如果設定為yes、這就相當於將appendfsync設定為no,這說明並沒有執行磁碟操作,只是寫入了緩衝區,因此這樣並不會造成阻塞(因為沒有競爭磁碟),但是如果這個時候redis掛掉,就會丟失資料。在linux的作業系統的預設設定下,最多會丟失30s的資料。
#因此,如果應用系統無法忍受延遲,而可以容忍少量的資料丟失,則設定為yes。如果應用系統無法忍受資料丟失,則設定為no。

把appendonly no 修改 為yes

重啟redis服務即可看到appendonly.aof檔案

[root@localhost bin]# ls
appendonly.aof redis-check-aof redis-cli redis-sentinel
redis-benchmark redis-check-rdb redis.conf redis-server

如果appendonly.aof檔案有問題、服務是起不來的、需要修復aof檔案(redis-check-aof)

[root@localhost bin]# redis-cli  -p 6379
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> exit
#修復檔案
[root@localhost bin]# redis-check-aof --fix appendonly.aof
0x 8b: Expected prefix '*', got: 'f'
AOF analyzed: size=147, ok_up_to=139, diff=8
This will shrink the AOF from 147 bytes, with 8 bytes, to 139 bytes
Continue? [y/N]: y
Successfully truncated AOF
#測試、成功
[root@localhost bin]# redis-server redis.conf
[root@localhost bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> get kk
"kk"

優點:

  • 每一次修改 都同步,檔案完整性更可靠

  • 預設每秒同步一次,可能會丟失一秒的資料

  • 從不同步,效率是最高的

缺點:

  • 相對於資料檔案來說,aof遠遠大於rdb,修復速度也比rdb慢!

  • aof執行效率也要比rdb慢,所以預設配置是rdb方式

redis 釋出訂閱


測試:

訂閱端:

127.0.0.1:6379> SUBSCRIBE kobe  #訂閱一個頻道:kobe
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "kobe"
3) (integer) 1
#等待發布資訊
1) "message"
2) "kobe"
3) "hello qiangge"
1) "message"
2) "kobe"
3) "zheshi diertiao xinxi"

釋出端:

127.0.0.1:6379> PUBLISH kobe "hello qiangge" #釋出訊息到頻道kobe
(integer) 1
127.0.0.1:6379> PUBLISH kobe "zheshi diertiao xinxi" #釋出訊息到頻道kobe
(integer) 1

Redis主從複製


一般來說,將Redis運用到生產環境上,只使用一臺redis是不可能的(宕機)。

  1. 結構上,單個redis伺服器會發生單點故障,並且一臺伺服器需要處理所以請求,負載壓力較大。

  2. 從容量上,單個redis伺服器記憶體容量有限,就算一臺redis伺服器記憶體256G,也不能將所有記憶體做redis的儲存,一般來說,單臺redis最大使用記憶體不超過20G。

電商網站上的商品,一般都是一次上傳,無數次瀏覽,就是多讀少寫。

主從複製,讀寫分離! 80%都在進行讀操作。架構經常使用一主二從!

預設情況下。每臺redis伺服器都是主節點,且一個主節點可以有多個從節點(或無),但是一個從節點只能有一個主節點!

環境配置

只配置從庫,不用配置主庫!

127.0.0.1:6379> info replication #檢視當前庫資訊
# Replication
role:master
connected_slaves:0
master_replid:aa439ac9973d1368f702b254d1f91c24512ade9c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

複製三個配置檔案,然後修改對應的資訊:

  1. pid名字

  2. log檔名字

  3. dump.rdb名字

修改完後分別啟動三個redis服務。

[root@localhost bin]# ps -ef | grep redis 
root 24629 1 0 13:27 ? 00:00:00 redis-server 127.0.0.1:637
root 24657 1 0 13:28 ? 00:00:00 redis-server 127.0.0.1:638
root 24673 1 0 13:28 ? 00:00:00 redis-server 127.0.0.1:638
root 24690 15649 0 13:28 pts/3 00:00:00 grep --color=auto redis

一主二從


預設情況下,每臺redis伺服器都是主節點;一般配置從機就可以!

主機(79);從機(80/81)

#從機配置
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379 # slaveof host port 認主
OK
127.0.0.1:6380> info replication [section]
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:1a52f712255b3dc52e458047f619c55651af014b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0

#主機檢視資訊
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=14,lag=0
master_replid:1a52f712255b3dc52e458047f619c55651af014b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

#配置完兩個檢視:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=168,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=168,lag=1
master_replid:1a52f712255b3dc52e458047f619c55651af014b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:168
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:168

真實的主從配置應該在配置檔案中配置的。永久生效。命令是暫時配置的!

#配置檔案修改(從機)
replicaof <masterip> <masterport> 新增主機 host port 即可
masterauth <master-password> 主機有密碼的在這裡配置密碼

注意:!!

主機可以寫,從機不能寫只能讀。

主機中的所有資訊和資料,都會自動被從機儲存!

主機斷開,從機依舊可以連線到主機,但是不能寫。如果主機回來,從機依舊可以獲取主機寫的資訊。

如果是用命令配置的主從,從機斷開,就回到master了。

複製原理

Slave 啟動成功連線到master後悔傳送一個sync同步命令

Master接到命令,啟動後臺的存檔程序,同時收集所有接收到的用於修改資料集命令,在後臺程序執行完畢之後,Master將傳送整個資料檔案到Slave,並完成一次完全同步

全量複製:slave服務在接收到資料庫檔案資料後,將其存檔並載入到記憶體中。

增量複製:Master繼續將新收集到的修改命令一次傳給slave,完成同步。

所以只要是重新連線master,就會執行一次完全同步(全量)。

一主一從(主)一從

資料可以實現同步、此時中間依舊是從節點、無法寫操作。

如果主機斷開了,可以使用 Slaveof no one讓自己變成主機!其他節點就可以手動連線到這個主節點。(手動)

哨兵模式


(自動選舉Master節點)

哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令,哨兵是一個獨立的程序,作為程序,它會獨立執行。其原理就是哨兵通過命令傳送命令,等待Redis伺服器的響應,從而監控執行的多個Redis例項。

哨兵的作用:
  • 通過傳送命令,讓Redis伺服器返回監控其執行狀態,包括主伺服器和從伺服器。

  • 當哨兵監測到master宕機,會自動將slave切換成master,然後通過釋出訂閱模式通知其他的從伺服器,修改配置檔案.

然而一個哨兵程序對Redis伺服器進行監控,可能會出現問題,為此我們可以使用多個哨兵進行監控。各個哨兵之間還會進行監控,這樣就形成了多哨兵模式。

測試:
  1. 配置哨兵配置檔案:sentinel.conf

#sentinel monitor 被監控主機名稱 host port 1表示當有一個哨兵發現宕機、就會切換?
sentinel monitor myredis 127.0.0.1 6379 1
  1. 啟動哨兵

[root@localhost bin]# redis-sentinel sentinel.conf 
30092:X 18 Sep 2020 15:18:16.476 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
30092:X 18 Sep 2020 15:18:16.476 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=30092, just started
30092:X 18 Sep 2020 15:18:16.476 # Configuration loaded
30092:X 18 Sep 2020 15:18:16.477 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.0.8 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 30092
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

30092:X 18 Sep 2020 15:18:16.478 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
30092:X 18 Sep 2020 15:18:16.491 # Sentinel ID is 102ad91558aefe9d2eed0940da97b8226da0c9db
30092:X 18 Sep 2020 15:18:16.491 # +monitor master myredis 127.0.0.1 6379 quorum 1
30092:X 18 Sep 2020 15:18:16.491 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
30092:X 18 Sep 2020 15:18:16.492 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

如果master節點宕機,這時候就會在從機中選舉一個master

#主機宕機、從節點變為master
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=8295,lag=1
master_replid:0db4dfc0339504943a1d434e615071cf2610b3cc
master_replid2:182d395d80b02cac7ad33cd310eb048787ae31ef
master_repl_offset:8427
second_repl_offset:2749
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:8427
#哨兵資訊
30092:X 18 Sep 2020 15:22:29.338 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6380
30092:X 18 Sep 2020 15:22:29.338 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
30092:X 18 Sep 2020 15:22:59.347 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380

哨兵日誌:

如果此時主機修復了。只能做從機,這就是哨兵模式的規則!

哨兵優缺點

優點:

  • 哨兵叢集,基於主從複製模式,所有的主從配置優點,他都有。

  • 主從可以切換,故障可以轉移,系統可用性更好

  • 哨兵模式就是主從模式的升級,手動到自動!

缺點:

  • redis不好線上擴容、叢集容量一旦到達上限,線上擴容就十分麻煩!

  • 實現哨兵模式的配置其實就是很麻煩,裡面有很多選擇。繁瑣!

sentinel monitor <master-name> <ip> <redis-port> <quorum>
告訴sentinel去監聽地址為ip:port的一個master,這裡的master-name可以自定義,quorum是一個數字,指明當有多少個sentinel認為一個master失效時,master才算真正失效

port 埠號

sentinel auth-pass <master-name> <password>
設定連線master和slave時的密碼,注意的是sentinel不能分別為master和slave設定不同的密碼,因此master和slave的密碼應該設定相同。

sentinel down-after-milliseconds <master-name> <milliseconds>
這個配置項指定了需要多少失效時間,一個master才會被這個sentinel主觀地認為是不可用的。 單位是毫秒,預設為30秒

sentinel parallel-syncs <master-name> <numslaves>
這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,這個數字越小,完成failover所需的時間就越長,但是如果這個數字越大,就意味著越 多的slave因為replication而不可用。可以通過將這個值設為 1 來保證每次只有一個slave 處於不能處理命令請求的狀態。

sentinel failover-timeout <master-name> <milliseconds>
failover-timeout 可以用在以下這些方面:
1. 同一個sentinel對同一個master兩次failover之間的間隔時間。
2. 當一個slave從一個錯誤的master那裡同步資料開始計算時間。直到slave被糾正為向正確的master那裡同步資料時。
3.當想要取消一個正在進行的failover所需要的時間。
4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來了。

Redis快取穿透和雪崩

伺服器高可用問題!!

快取穿透:(查詢不到)

概念:使用者想要查詢一個數據,發現redis記憶體資料庫沒有,也就是快取沒有命中,於是向持久層資料庫查詢,發現也沒有,於是本次查詢失敗。當用戶很多的時候(秒殺),快取沒有命中,於是都去請求了持久層資料庫,這會給持久層資料庫造成很大的壓力,這個時候就相當於出現了快取穿透。

解決方案:

  1. 布隆過濾器

布隆過濾器是一種資料結構,對所有可能查詢的引數以hash形式儲存,在控制層先進行校驗,不符合則丟棄,從而避免了對底層儲存系統的查詢壓力。

  1. 快取空物件

    當儲存層不命中後,既使返回的空物件也將其快取起來,同時設定一個過期時間,之後再訪問這個資料將會從快取中獲取,保護了後端的資料來源。

但是這種方法會存在兩個問題:

  1. 如果空值能夠被快取起來,這就意味著快取需要更多的空間儲存更多的鍵,因為這當中會有很多的空值的鍵。

  2. 既使對空值設定了過期時間,還是會存在快取層和儲存層的資料會有一段時間視窗的不一致, 這對需要保持一致性的業務會有影響。

快取擊穿(量太大、快取過期)

微博伺服器宕機(熱搜)

這裡的和快取穿透的區別,快取擊穿,是指一個key非常熱點,在不停的扛著大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破快取,直接請求資料庫,就像一個屏障上鑿開了一個洞。

當某個key在過期的瞬間,有大量的請求併發訪問,這類資料一般是熱點資料,由於快取過期,會同時訪問資料庫來查詢最新的資料,並且回寫快取,會導致資料庫瞬間壓力過大。

解決方案:

  1. 設定熱點資料永不過期

    從快取層面來看,沒有設定過期時間,所以不會出現熱點key過期後產生的問題。

  2. 加互斥鎖

    分散式鎖:使用分散式鎖,保證對每個key同時只有一個執行緒去查詢後端服務其他執行緒沒有獲得分散式鎖的許可權,因此只需要等待即可。這種方式將高併發的壓力轉移到了分散式鎖,因此對分散式鎖分考研很大。

快取雪崩

快取雪崩指的是在某一時間段,快取集中過期失效。redis宕機!

其中集中過期好過於快取伺服器某個節點宕機或者斷網。因為在自然形成的雪崩,一定是在某個時間段集中建立快取,這個時候,資料庫也是可以頂住壓力的。而快取服務節點的宕機,對資料伺服器造成的壓力是不可預知的,可能瞬間就把資料庫壓垮。

解決方案:

  1. redis高可用

    搭建叢集(異地多活)、其中一臺掛掉,其他伺服器依舊可以工作

  2. 限流降級

    在快取失效後,通過加鎖或者佇列來控制讀資料庫寫快取的執行緒數量。比如對某個key只允許一個執行緒查詢資料和寫快取,其他執行緒等待。

  3. 資料預熱

    就是在正式部署之前,先把可能得資料先訪問一遍,這樣部分可能大量訪問的資料就會載入到快取中。在即將發生大併發訪問前手動觸發載入快取不同的key,設定不同的過期時間,讓快取失效的時間點儘量均勻。

  4. 停掉一些(不主要)的服務、保證其他服務(主要)的可用。