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

  • 2021 年 1 月 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 都啟動了

![](//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,設置不同的過期時間,讓緩存失效的時間點盡量均勻