【9k字+】第二篇:進階:掌握 Redis 的一些進階操作(Linux環境)

BWH_Steven發表於2021-01-26

九 Redis 常用配置檔案詳解

能夠合理的檢視,以及理解修改配置檔案,能幫助我們更好的使用 Redis,下面按照 Redis 配置檔案的順序依次往下講

  • 1k 和 1kb,1m 和 1mb 、1g 和 1gb 的大小是有區別的,同時其對大小寫不敏感

  • include 相當於 import 的概念,可以引入,然後組合多個配置檔案

  • 網路配置如下(為了解決遠端連線問題,會註釋掉 bind 127.0.0.1,以及將保護模式 protected-mode 改為 no)
    • bind 127.0.0.1 —— 繫結的ip
    • protected-mode yes —— 保護模式
    • port 6379 —— 埠設定

  • 以守護程式的方式執行,預設為 no,自行開啟為 yes

  • 後臺執行,需要指定 pid 檔案

  • 日誌相關
    • loglevel 指定日誌級別:debug ,verbose,notice,warning,其中 notice 是生產環境
    • logfile —— 具體的日誌名
    • database —— 資料庫的數量,預設為 16
    • always-show-logo —— 是否總是顯示 logo

  • 持久化相關:由於 Redis 是基於記憶體的資料庫,所以持久化就是將資料持久化到具體的檔案中去
    • 有兩種方式,RDB、AOF 下面我們會具體的講持久化的概念,這裡簡單提及
    • save 900 1 :如果 900 s 內,如果至少有 1 個 key 被修改,則進行持久化操作,下面兩個同理
    • stop-writes-on-bgsave-error:持久化出錯,是否還要繼續工作
    • rdbcompression:是否壓縮 rdb 檔案(會消耗 CPU)
    • rdbchecksum:儲存 rdb 檔案的時候,進行錯誤的檢查校閱
    • dir: rdb 檔案儲存的目錄

  • 主從複製會在下面專門講解,這裡暫時略過

  • 接下來的 SECURITY 部分,註釋中有提及到關於密碼的設定,這裡多提一下在客戶端中設定密碼的方式

127.0.0.1:6379> ping PONG 
127.0.0.1:6379> config get requirepass # 獲取redis的密碼 
1) "requirepass" 
2) "" 

127.0.0.1:6379> config set requirepass "123456" # 設定redis的密碼 
OK
127.0.0.1:6379> config get requirepass # 發現所有的命令都沒有許可權
(error) NOAUTH Authentication required. 
127.0.0.1:6379> ping
(error) NOAUTH Authentication required. 

127.0.0.1:6379> auth 123456 # 使用密碼進行登入
OK
127.0.0.1:6379> config get requirepass 
1) "requirepass" 
2) "123456"
  • CLIENTS 客戶端連線部分,註釋太多,這裡不好截圖,就簡單說一說

    • maxclients —— 最大客戶端數量

    • maxmemory —— 最大記憶體限制

    • maxmemory-policy noeviction —— 記憶體達到限制值的處理策略

    • redis 中的預設的過期策略是 volatile-lru ,設定方式如下:

      • config set maxmemory-policy volatile-lru

maxmemory-policy 六種方式

  • volatile-lru:只對設定了過期時間的key進行LRU(預設值)

  • allkeys-lru : 刪除lru演算法的key

  • volatile-random:隨機刪除即將過期key

  • allkeys-random:隨機刪除volatile-ttl :刪除即將過期的

  • noeviction: 永不過期,返回錯誤

  • APPEND ONLY 部分為持久化方式之一的 AOF 的配置方式,下面會細講這兩種持久化,所以這裡也是提及一下即可
    • appendonly no —— 預設是不開啟 AOF 模式的,預設是使用 RDB 方式持久化的,RDB 一般夠用
    • appendfilename "appendonly.aof" —— 持久化檔案的名字
    • appendfsync always —— 每次修改都會 sync(消耗效能 )
    • appendfsync everysec —— 每秒執行一次 sync,可能會丟失這1s的資料
    • appendfsync no —— 不執行 sync,作業系統自己同步資料,速度最快

十 Redis 持久化

前面已經講過,Redis是一個記憶體資料庫,也就是說,我們的資料全部儲存在記憶體中,而我們常見的MySQL和Oracle等SQL資料庫會將資料儲存到硬碟中,凡事都是有利有弊,雖然記憶體資料庫讀寫速度要比在硬碟中讀寫的資料庫快的多,但是卻出現了一個很麻煩的問題,也就是說,當 Redis 伺服器重啟或者當機後,記憶體中的資料會全部丟失,為了解決這個問題,Redis提供了一種持久化的技術,也就是將記憶體中的資料儲存到硬碟中去,日後方便我們使用這些檔案恢復資料庫中的資料

在配置檔案的解釋中,提到了兩種持久化方式 RDB、AOF ,下面我們具體來講解一下:

(一) RDB 方式

(1) 概念

在指定時間間隔後,將記憶體中的資料集快照寫入資料庫 ,在恢復時候,直接讀取快照檔案,進行資料的恢復

簡單理解:一定的時間內,檢測key的變化情況,然後持久化資料

預設情況下, Redis 將資料庫快照儲存在名字為 dump.rdb 的二進位制檔案中。

檔名可以在配置檔案中進行自定義,例如:dbfilename dump.rdb

(2) 工作原理

在進行 RDB 的時候,redis 的主執行緒是不會做 io 操作的,主執行緒會 fork 一個子執行緒來完成該操作(這也是保證了其極大效能的特點)

  1. Redis 呼叫forks,同時擁有父程式和子程式。
  2. 子程式將資料集寫入到一個臨時 RDB 檔案中。
  3. 當子程式完成對新 RDB 檔案的寫入時,Redis 用新 RDB 檔案替換原來的 RDB 檔案,並刪除舊的 RDB 檔案。

這種工作方式使得 Redis 可以從寫時複製(copy-on-write)機制中獲益(因為是使用子程式進行寫操作,而父程式依然可以接收來自客戶端的請求。

我們知道了一個程式如何採用請求調頁,僅調入包括第一條指令的頁面,從而能夠很 快開始執行。然而,通過系統呼叫 fork() 的程式建立最初可以通過使用類似於頁面共享的技術,繞過請求調頁的需要。這種技術提供了快速的程式建立,並最小化必須分配給新建立程式的新頁面的數量。

回想一下,系統呼叫 fork() 建立了父程式的一個複製,以作為子程式。傳統上,fork() 為子程式建立一個父程式地址空間的副本,複製屬於父程式的頁面。然而,考慮到許多子程式在建立之後立即呼叫系統呼叫 exec(),父程式地址空間的複製可能沒有必要。

因此,可以採用一種稱為寫時複製的技術,它通過允許父程式和子程式最初共享相同的頁面來工作。這些共享頁面標記為寫時複製,這意味著如果任何一個程式寫入共享頁面,那麼就建立共享頁面的副本。

(3) 持久化觸發條件

  1. 滿足 save 條件會自動觸發 rdb 原則

    • 如:save 900 1 :如果 900 s 內,如果至少有 1 個 key 被修改,則進行持久化操作
  2. 執行save / bgsave / flushall命令,也會觸發 rdb 原則

    • save:立即對記憶體中的資料進行持久化,但是會阻塞,即不再接受其他任何操作,這是因為 save 命令為同步命令,會佔用 Redis 主程式,若 Redis 資料非常多,阻塞時間會非常長
    • bgsave:非同步請求,持久化時,可以持續響應客戶端請求,阻塞發生在 fock 階段,通常很快,但是消耗記憶體
    • flushall:此命令也會觸發持久化 ;
  3. 退出 Redis,也會自動產生 rdb 檔案(預設生成位置就是 redis 的啟動目錄)

(4) 恢復 RDB 檔案

只要將 rdb 檔案,放在 Redis 的啟動目錄,Redis 會自動在這個目錄下檢查 dump.rdb 檔案,然後恢復其中的資料

查詢配置檔案中位置的命令

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"

(5) 優缺點

優點:

  1. 適合大規模的資料恢復
  2. 對資料的完整性要求不高

缺點:

  1. 易丟失最後一次操作,因為其需要一定的時間間隔進行操作,如果 Redis 意外當機了,這個最後一次修改的資料就沒有了
  2. fork程式的時候,會佔用一定的記憶體空間

(二) AOF 方式

(1) 概念

以日誌的形式來記錄每個寫的操作,將Redis執行過的所有指令記錄下來(讀操作不記錄),只許追加檔案但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,換言之,redis重啟的話就根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作。

如果你不深究其背後的操作,可以簡單理解為:每一個操作執行後,進行持久化操作

想要使用 AOF 方式,需要主動開啟,因為預設使用的是 RDB

在配置檔案中,我們找到這兩行,可以設定 aof 的啟動,以及其持久化檔案的名字

  • appendonly no :no 代表關閉 aof,改為 yes 代表開啟

  • appendfilename "appendonly.aof" —— 持久化檔案的名字

這裡可以修改其持久化的一個方式

  • appendfsync always —— 每次修改都會 sync(消耗效能 )

  • appendfsync everysec —— 每秒執行一次 sync,可能會丟失這1s的資料

  • appendfsync no —— 不執行 sync,作業系統自己同步資料,速度最快

其預設是無限追加模式的,如果 aof 檔案大於 64m,就 fork一個新的程式來將我們的檔案進行重寫

no-appendfsync-on-rewrite no
aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

(2) aof 檔案錯位的解決方案

如果這個 aof 檔案有錯位,這時候redis是啟動不起來的

Redis 給我們提供了一個工具 redis-check-aof --fix

# 命令示例
redis-check-aof --fix appendonly.aof

(3) 優缺點

優點

  1. 檔案的完整性會更加好,因為每一次修改都會同步
  2. 若使用 appendfsync no 速度最快,效率最高

缺點

  1. aof 檔案大小遠大於 rdb,修復速度因此比 rdb慢
  2. aof 執行效率也要比 rdb 慢,所以我們redis預設的配置就是rdb持久化
  3. 若使用每秒同步一次,可能會丟失一秒的資料

(三) 擴充套件要點(來源於網路,侵刪)

  1. 如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化,即只當做快取使用

  2. 同時開啟兩種持久化方式

    在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF

    檔案儲存的資料集要比RDB檔案儲存的資料集要完整。

    RDB 的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案,那要不要只使用AOF呢?作者

    建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份),快速重啟,而且不會有

    AOF可能潛在的Bug,留著作為一個萬一的手段。

  3. 效能建議

    因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠

    了,只保留 save 900 1 這條規則。

    如果Enable AOF ,好處是在最惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自

    己的AOF檔案就可以了,代價如下:

    • 一是帶來了持續的IO,

    • 二是AOF rewrite 的最後將 rewrite 過程中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。

    因此只要硬碟許可,應該儘量減少AOF rewrite的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上,預設超過原大小100%大小重寫可以改到適當的數值。

    如果不Enable AOF ,僅靠 Master-Slave Repllcation 實現高可用性也可以,能省掉一大筆IO,也

    減少了rewrite時帶來的系統波動。

    • 代價是如果Master/Slave 同時倒掉,會丟失十幾分鐘的資料,啟動指令碼也要比較兩個 Master/Slave 中的 RDB檔案,載入較新的那個,微博就是這種架構。

十一 Redis 釋出與訂閱

(一) 概念

這部分,用的不是特別多,作為一個補充。 下面是我在 菜鳥教程(runoob)貼過來的定義,重製了一下圖

定義:Redis 釋出訂閱 (pub/sub) 是一種訊息通訊模式:傳送者 (pub) 傳送訊息,訂閱者 (sub) 接收訊息。

Redis 客戶端可以訂閱任意數量的頻道。

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關係:

當有新訊息通過 PUBLISH 命令傳送給頻道 channel1 時, 這個訊息就會被髮送給訂閱它的三個客戶端:

(二) 命令

  • PSUBSCRIBE pattern [pattern..] —— 訂閱一個或多個符合給定模式的頻道。
  • PUNSUBSCRIBE pattern [pattern..] —— 退訂一個或多個符合給定模式的頻道。
  • PUBSUB subcommand [argument[argument]] —— 檢視訂閱與釋出系統狀態。
  • PUBLISH channel message —— 向指定頻道釋出訊息
  • SUBSCRIBE channel [channel..] —— 訂閱給定的一個或多個頻道。
  • SUBSCRIBE channel [channel..] —— 退訂一個或多個頻道

演示

------------訂閱端----------------------
127.0.0.1:6379> SUBSCRIBE ideal-20 # 訂閱ideal-20頻道
Reading messages... (press Ctrl-C to quit) # 等待接收訊息
1) "subscribe" # 訂閱成功的訊息
2) "ideal-20"
3) (integer) 1

1) "message" # 接收到來自 ideal-20 頻道的訊息 "hello ideal"
2) "ideal-20"
3) "hello ideal"

1) "message" # 接收到來自 ideal-20 頻道的訊息 "hello i am ideal-20"
2) "ideal-20"
3) "Hi,i am BWH_Steven"

--------------訊息釋出端-------------------
127.0.0.1:6379> PUBLISH ideal-20 "hello ideal" # 釋出訊息到ideal-20頻道
(integer) 1
127.0.0.1:6379> PUBLISH ideal-20 "Hi,i am BWH_Steven" # 釋出訊息
(integer) 1

-----------------檢視活躍的頻道------------
127.0.0.1:6379> PUBSUB channels
1) "ideal-20"

(三) 原理簡述

說明:每個 Redis 伺服器程式都維持著一個表示伺服器狀態的 redis.h/redisServer 結構,而結構的 pubsub_channels 屬性是一個字典, 這個字典就用於儲存訂閱頻道的資訊

  • 其中,字典的鍵為正在被訂閱的頻道, 而字典的值則是一個連結串列連結串列中儲存了所有訂閱這個頻道的客戶端

例子示意圖:在下圖展示的這個 pubsub_channels 示例中, client2 、 client5 和 client1 就訂閱了 channel1(頻道1) ,其他 channel (頻道)同理

有了這個結構上的概念,訂閱以及釋出的動作就很好理解了:

  • 訂閱:當客戶端呼叫 SUBSCRIBE 命令執行訂閱頻道操作時,程式就會把一個個客戶端(client)和要訂閱的頻道(channel)在 pubsub_channels 中關聯起來

  • 釋出: 程式首先根據 channel 定位到字典的鍵(例如找到 channel1), 然後將資訊傳送給字典值連結串列中的所有客戶端(例如 client2、client5、client1)。

(四) 缺點

  1. 依賴於資料傳輸的可靠性,訂閱方斷線,會導致其丟失在斷線期間釋出者釋出的訊息
  2. 客戶端如果讀取所訂閱頻道發來訊息的速度不夠快,積壓的訊息會使得 Redis 輸出快取區提及變得越來越大,輕則降低 Redis 速度,重則崩潰

(五) 應用

  1. 多人線上聊天室
  2. 訊息訂閱,如公眾號那種形式,但是實際大部分都用 MQ 來做(後面會寫)

十二 Redis主從複製

(一) 使用原因

首先,在一個專案中,使用一臺 Redis 伺服器肯定是有問題的:

  • 一臺伺服器處理所有請求,壓力過大,且容易出現故障,會導致整個相關服務出現問題

  • 一臺伺服器的記憶體是有限的,不可能將所有記憶體用作 Redis 儲存(推薦不應該超過 20g)

  • 大部分場景下,大部分都是讀的操作,寫的操作會相對少一點,所以對讀取的要求會大一些

而主從複製就可以將讀寫分離,下面來一起了解一下

(二) 概念

主從複製,是指將一臺Redis伺服器的資料,複製到其他的Redis伺服器

  • 前者稱為主節點(Master/Leader),後者稱為從節點(Slave/Follower)

  • 資料的複製是單向的!只能由主節點複製到從節點(主節點以寫為主、從節點以讀為主)

簡單理解一下就是:一臺伺服器作為主機器,其他伺服器作為從機器,他們通過命令或配置進行了連線,這樣從機就能獲取到主機的資料了,從機可以幫主機分擔很多讀的請求等等

(三) 作用

  1. 資料冗餘:主從複製實現了資料的熱備份,是持久化之外的一種資料冗餘的方式。
  2. 故障恢復:當主節點故障時,從節點可以暫時替代主節點提供服務,是一種服務冗餘的方式
  3. 負載均衡:在主從複製的基礎上,配合讀寫分離,由主節點進行寫操作,從節點進行讀操作,分擔伺服器的負載;尤其是在多讀少寫的場景下,通過多個從節點分擔負載,提高併發量。
  4. 高可用基石:主從複製還是哨兵和叢集能夠實施的基礎。

(四) 叢集環境搭建(模擬)

正常的情況,應該是多臺不同的伺服器,為了演示方便,這裡使用幾個不同的埠來模擬不同的 Redis 伺服器

首先,要使用不同的埠,自然需要多個不同的配置檔案了,我們先將原先的配置檔案,複製三份(分別代表等會的一臺主機和兩臺從機)

# 一段都是為了告訴大家我的配置檔案的目錄,即redis 啟動目錄下面的 myconfig 目錄下
[root@centos7 ~]# cd /usr/local/bin 
[root@centos7 bin]# ls
appendonly.aof  dump.rdb  myconfig  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server  temp-2415.rdb
[root@centos7 bin]# cd myconfig/
[root@centos7 myconfig]# ls
redis.conf

# 複製三份,分別按照等會的埠號起名
[root@centos7 myconfig]# cp redis.conf redis6379.conf
[root@centos7 myconfig]# cp redis.conf redis6380.conf
[root@centos7 myconfig]# cp redis.conf redis6381.conf

# 這樣三份就賦值好了
[root@centos7 myconfig]# ls
redis6379.conf  redis6380.conf  redis6381.conf  redis.conf

複製後,就需要分別通過 vim 修改每個配置檔案的 port 、daemonize、pid 、 logfile、dbfilename

例如:

port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
logfile "6380.log"
dbfilename dump6380.rdb

在 XShell 中再開啟兩個視窗,然後分別執行不同埠號的 Redis

在第一個視窗執行 Redis 服務,使用 6379 這個配置檔案

[root@centos7 bin]# redis-server myconfig/redis6379.conf

其他兩個也是同理,分別啟動 6380、6381

檢視一下,三個埠的 Redis 都啟動了

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1b4bf5017e5d4e2781d83fe698f9a67c~tplv-k3u1fbpfcp-zoom-1.image)

(五) 一主二從

一主二從,就是代表一臺主機,還有兩臺是從機,而 Redis 預設都是主機,也就是說,我們上面模擬搭建出來的幾臺 Redis 伺服器,現在還都是主機,而且相互之間並不存在什麼關係

在客戶端中通過 info replication 命令可以檢視當前的一個資訊

127.0.0.1:6379> info replication
# Replication
role:master # 當前是一個 master 主機
connected_slaves:0
master_replid:bfee90411a4ee99e80ace78ee587fdb7b564b4b4
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

說明:以下演示中主機埠號為 6379,兩臺從機分別為 6380、6381

(1) 命令的方式(暫時)

配置一主二從,只需要配置從機,使用 SLAVEOF 127.0.0.1 6379 即可

分別在 6380 和 6381 的視窗中執行

然後查詢從機自身的資訊,例如查詢 6380 這臺

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:1
master_sync_in_progress:0
slave_repl_offset:364
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:bd7b9c5f3bb1287211b23a3f62e41f24e009b77e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:364
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:85
repl_backlog_histlen:280

同樣在主機中查詢,也能看到有兩臺從機已經連線

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=84,lag=0 # 第一臺
slave1:ip=127.0.0.1,port=6380,state=online,offset=84,lag=0 # 第二臺
master_replid:bd7b9c5f3bb1287211b23a3f62e41f24e009b77e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

(2) 修改配置檔案的方式(永久)

上面使用命令的方式,需要每一次重啟等都需要執行命令,而將其寫到配置檔案中的時候,就可以每次根據配置自動載入了,首先修改從機配置檔案中的 replicaof 後面跟隨主機的 ip 和 埠

如果主機的 Redis 設定了密碼,別忘了在從機中的 masterauth 中加上主機的密碼

(3) 規則說明

  1. 從機只能讀,不能寫,主機可讀可寫但是多用於寫。

    • 從機執行寫操作會報錯 (error) READONLY You can't write against a read only replica.
  2. 主機斷電/當機後,預設角色不變,從機仍是從機,叢集只是失去了寫操作,等待主機恢復,會重新回到原來的狀態

    • 主機故障後,若需要一臺從機作為主機,有兩種方式可選
      • ① 從機手動執行命令 slaveof no one 使其成為主機
      • ② 使用哨兵模式自動選舉(下面接著講解哨兵模式)
  3. 從機斷電/當機後,若之前使用的是命令的方式稱為從機,則啟動後無法獲取主機,重新配置或者是使用配置檔案的方式成為從機,重啟後,可以重新獲取到主機所有資料

(4) 複製原理

Slave(從機) 啟動成功連線到 Master(註解) 後會傳送一個 sync(同步命令)

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

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

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

但是隻要是重新連線master,一次完全同步(全量複製)將被自動執行,從機中就能看到所有資料

十三 哨兵模式

(一) 概念

在前面的主從複製的概念中,我們知道,一旦主伺服器當機,就需要使用手動的方式,將一臺從伺服器切換為主伺服器,這種方式很麻煩,還有一種方式就是哨兵模式,也是一種比較推薦的方式

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

其作用如下:

  • 通過傳送命令,讓Redis伺服器返回監控包括主伺服器和從伺服器的執行狀態,。
  • 當哨兵監測到master當機,會自動將slave切換成master,然後通過釋出訂閱模式通知其他的從伺服器,修改配置檔案,讓它們切換主機。

單哨兵與多哨兵模式:

單哨兵模式:以獨立的程式監控3臺 Redis 伺服器是否正常執行

多哨兵模式:除了監控Redis 伺服器,哨兵之間也會互相監控

(二) 配置以及啟動

Redis 啟動目錄下的 redis-sentinel 就是我們要啟動的哨兵,但是我們需要為其指定配置檔案,這樣哨兵太知道要監控誰

我在我的 Redis 啟動目錄 /usr/local/bin/ 下的 myconfig 目錄中,建立了一個名為 sentinel.conf 的配置檔案

[root@centos7 bin]# vim myconfig/sentinel.conf

裡面寫入了其核心配置內容,即指定監控我們本地 6379 埠的主機,後面的數字1,代表主機當機後,會使用投票演算法機制選擇一臺從機作為新的主機

# sentinel monitor 被監控的名稱 host port 1 
sentinel monitor myredis 127.0.0.1 6379 1

接著我們回到 Redis 啟動目錄,以剛才那個配置檔案啟動哨兵

[root@centos7 bin]# redis-sentinel myconfig/sentinel.conf

啟動成功如下圖:

一旦將主機斷開連線,等待一下,哨兵監測到,就會發起投票(這裡只有一個哨兵,所以是 100%的),然後切換一臺從機成為新的主機,而主機一旦重新上線後,也只能作為新主機的一臺從機了

可以根據哨兵這邊自動彈出來的日誌看到,首先 6379 這臺主機斷開後,1 個哨兵認為其斷開,然後下面的 switch 即選擇了新的 6380 作為新的主機,6379 重新上線後,只能作為 6380 的從機了

檢視一下 6380 的資訊,其果然已經成為了主機

127.0.0.1:6380> info replication
# Replication
role:master # 主機
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=147896,lag=0
slave1:ip=127.0.0.1,port=6379,state=online,offset=147764,lag=0
master_replid:d32e400babb8bfdabfd8ea1d3fc559f714ef0d5a
master_replid2:bd7b9c5f3bb1287211b23a3f62e41f24e009b77e
master_repl_offset:147896
second_repl_offset:7221
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:85
repl_backlog_histlen:147812

(三) 完整配置檔案

實際上最核心的也就是我們剛才演示中的那一句即下面的:sentinel monitor mymaster 127.0.0.1 6379 1

還有埠修改會用到,其他的可以根據情況設定

其配置檔案還是比較複雜的

# Example sentinel.conf
 
# 哨兵sentinel例項執行的埠 預設26379
port 26379
 
# 哨兵sentinel的工作目錄
dir /tmp
 
# 哨兵sentinel監控的redis主節點的 ip port 
# master-name  可以自己命名的主節點名字 只能由字母A-z、數字0-9 、這三個字元".-_"組成。
# quorum 當這些quorum個數sentinel哨兵認為master主節點失聯 那麼這時 客觀上認為主節點失聯了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 1
 
# 當在Redis例項中開啟了requirepass foobared 授權密碼 這樣所有連線Redis例項的客戶端都要提供密碼
# 設定哨兵sentinel 連線主從的密碼 注意必須為主從設定一樣的驗證密碼
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
 
 
# 指定多少毫秒之後 主節點沒有應答哨兵sentinel 此時 哨兵主觀上認為主節點下線 預設30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
 
# 這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,
這個數字越小,完成failover所需的時間就越長,
但是如果這個數字越大,就意味著越 多的slave因為replication而不可用。
可以通過將這個值設為 1 來保證每次只有一個slave 處於不能處理命令請求的狀態。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
 
 
 
# 故障轉移的超時時間 failover-timeout 可以用在以下這些方面: 
#1. 同一個sentinel對同一個master兩次failover之間的間隔時間。
#2. 當一個slave從一個錯誤的master那裡同步資料開始計算時間。直到slave被糾正為向正確的master那裡同步資料時。
#3.當想要取消一個正在進行的failover所需要的時間。  
#4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來了
# 預設三分鐘
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
 
# SCRIPTS EXECUTION
 
#配置當某一事件發生時所需要執行的指令碼,可以通過指令碼來通知管理員,例如當系統執行不正常時發郵件通知相關人員。
#對於指令碼的執行結果有以下規則:
#若指令碼執行後返回1,那麼該指令碼稍後將會被再次執行,重複次數目前預設為10
#若指令碼執行後返回2,或者比2更高的一個返回值,指令碼將不會重複執行。
#如果指令碼在執行過程中由於收到系統中斷訊號被終止了,則同返回值為1時的行為相同。
#一個指令碼的最大執行時間為60s,如果超過這個時間,指令碼將會被一個SIGKILL訊號終止,之後重新執行。
 
#通知型指令碼:當sentinel有任何警告級別的事件發生時(比如說redis例項的主觀失效和客觀失效等等),將會去呼叫這個指令碼,
#這時這個指令碼應該通過郵件,SMS等方式去通知系統管理員關於系統不正常執行的資訊。呼叫該指令碼時,將傳給指令碼兩個引數,
#一個是事件的型別,
#一個是事件的描述。
#如果sentinel.conf配置檔案中配置了這個指令碼路徑,那麼必須保證這個指令碼存在於這個路徑,並且是可執行的,否則sentinel無法正常啟動成功。
#通知指令碼
# sentinel notification-script <master-name> <script-path>
  sentinel notification-script mymaster /var/redis/notify.sh
 
# 客戶端重新配置主節點引數指令碼
# 當一個master由於failover而發生改變時,這個指令碼將會被呼叫,通知相關的客戶端關於master地址已經發生改變的資訊。
# 以下引數將會在呼叫指令碼時傳給指令碼:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>總是“failover”,
# <role>是“leader”或者“observer”中的一個。 
# 引數 from-ip, from-port, to-ip, to-port是用來和舊的master和新的master(即舊的slave)通訊的
# 這個指令碼應該是通用的,能被多次呼叫,不是針對性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

十四 Redis 快取穿透、擊穿、和雪崩

此部分為一個補充知識點,本文重點還是 Redis 的一個基本入門,而下面的這些知識點,更多的是在具體場景中產生的一些問題,而且其每一個內容展開講都是非常複雜的,所以這裡只做一個基本概念的介紹,不做詳細說明

(一) 快取穿透

使用者查詢資料,首先在 Redis 快取中去查,如果沒有,也就是快取沒有命中,就會去持久層資料庫,例如 MySQL 中去查。

快取穿透:大量快取未命中的情況下,大量請求持久層資料庫,持久層資料庫承載很大的壓力,出現問題。

常見解決方案有兩種:

  • 布隆過濾器
  • 快取空物件

① 布隆過濾器:

對所有可能查詢的引數以Hash的形式儲存,以便快速確定是否存在這個值,在控制層先進行攔截校驗,校驗不通過直接打回,減輕了儲存系統的壓力。

② 快取空物件:

次請求若在快取和資料庫中都沒找到,就在快取中方一個空物件用於處理後續這個請求

不過此方法存在兩種問題:

  • 空值也能被快取的話,就會需要更多的空間來儲存更多的空值
  • 即使對空值設定了過期時間,還是會存在快取層和儲存層的資料會有一段時間視窗的不一致,這對於需要保持一致性的業務會有影響

(二) 快取擊穿

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

解決方案:

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

    這樣就不會出現熱點資料過期的情況,但是當 Redis 記憶體空間滿的時候也會清理部分資料,而且此種方案會佔用空間,一旦熱點資料多了起來,就會佔用部分空間。

  2. 加互斥鎖(分散式鎖)

    在訪問 key 之前,採用SETNX(set if not exists)來設定另一個短期key來鎖住當前key的訪問,訪問結束再刪除該短期 key 。保證同時刻只有一個執行緒訪問。這樣對鎖的要求就十分高。

(三) 快取雪崩

大量的key設定了相同的過期時間,導致在快取在同一時刻全部失效,造成瞬時DB請求量大、壓力驟增,引起雪崩。

解決方案:

① redis高可用

  • 這個思想的含義是,既然redis有可能掛掉,那我多增設幾臺redis,這樣一臺掛掉之後其他的還可以繼續工作,其實就是搭建的叢集

② 限流降級

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

③ 資料預熱

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

相關文章