redis學習筆記(詳細)——高級篇

redis配置文件介紹

linux環境下配置大於編程

redis 的配置文件位於 Redis 安裝目錄下,文件名為 redis.conf。一般情況下,會單獨拷貝出來一份進行操作。來保證初始文件的安全

config get * # 獲取全部的配置

include部分

組合多個配置。和Spring配置文件類似,可以通過includes包含,redis.conf 作為總文件,可以包含其他配置文件!

network網絡部分

網絡相關配置

bind 127.0.0.1 # 綁定的ip
protected-mode yes # 保護模式
port 6379 # 默認端口

General部分

序號 配置項 說明
1 daemonize no Redis 默認不是以守護進程的方式運行,可以通過該配置項修改,
使用 yes 啟用守護進程(Windows 不支持守護線程的配置為 no )
2 tcp-backlog 設置tcp的backlog, backlog其實是一一個連接隊列,
backlog隊列總和 = 未完成三次握手隊列+已經完成三次握手隊列。
注意Linux內核會將這個值減小到/ proc/sys/ net/ core/somaxconn的值,
所以需要確認增大somaxconn和tcp_ max_ syn backlog兩個值
5 timeout 300 當客戶端閑置多少秒後關閉連接,如果指定為 0 ,表示關閉該功能
6 Tcp-keepalive 0 檢測連接是否中斷,設置為0時表示禁用該服務
7 loglevel notice 日誌級別,Redis 總共支持四個級別:debug、verbose、notice、warning,
級別逐漸增高,打印的信息隨着級別的變高而減少,默認為 notice
8 syslog-enabled no 是否打印日誌到syslog中,默認為no
9 syslog-ident redis 指定syslog中的日誌標誌
10 databases 16 設置數據庫的數量,默認數據庫為0,可以使用SELECT 命令連接指定數據庫id
11 logfile “” 日誌文件的位置,當指定為空字符串時,為標準輸出

SNAPSHOTTING部分

快照,持久化規則

AOF

# 900秒(15分鐘)內至少1個key值改變(則進行數據庫保存--持久化)
save 900 1
# 300秒(5分鐘)內至少10個key值改變(則進行數據庫保存--持久化)
save 300 10
# 60秒(1分鐘)內至少10000個key值改變(則進行數據庫保存--持久化)
save 60 10000

RGB

stop-writes-on-bgsave-error yes # 持久化出現錯誤後,是否依然進行繼續進行工作

rdbcompression yes # 使用壓縮rdb文件 yes:壓縮,但是需要一些cpu的消耗。no:不壓縮,需要更多的磁盤空間

rdbchecksum yes # 是否校驗rdb文件,更有利於文件的容錯性,但是在保存rdb文件的時候,會有大概10%的性能損耗

dbfilename dump.rdb # dbfilenamerdb文件名稱

dir ./ # dir 數據目錄,數據庫的寫入會在這個目錄。rdb、aof文件也會寫在這個目錄

REPLICATION主從複製

後續主從複製部分詳細說明

SECURITY部分

# 啟動redis
# 連接客戶端

# 獲得和設置密碼
config get requirepass
config set requirepass "123456"
#密碼置空:
config set requirepass  ''

#測試ping,發現需要驗證
127.0.0.1:6379> ping
NOAUTH Authentication required.
# 驗證: auth 密碼
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> ping
PONG

客戶端連接相關

maxclients 10000  最大客戶端數量
maxmemory <bytes> 最大內存限制
maxmemory-policy noeviction # 內存達到限制值的處理策略

maxmemory-policy 六種方式

  • volatile-lru:利用LRU算法移除設置過過期時間的key。

  • allkeys-lru :用lru算法刪除lkey

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

  • allkeys-random:隨機刪除

  • volatile-ttl :刪除即將過期的

  • noeviction :不移除任何key,只是返回一個寫錯誤。

redis 中的默認的過期策略是 volatile-lru

設置方式

config set maxmemory-policy volatile-lru 

append only mode 部分

AOF相關部分

appendonly no #默認是不開啟AOF模式的,而是使用RGB方式持久化,大多數情況下RGB完全夠用
appendfilename "appendonly.aof"	#持久化文件名
appendfsync everysec # appendfsync aof持久化策略的配置
        # no表示不執行fsync,由操作系統保證數據同步到磁盤,速度最快。
        # always表示每次寫入都執行fsync,以保證數據同步到磁盤。
        # everysec表示每秒執行一次fsync,可能會導致丟失這1s數據。

LIMITS部分

  • maxclients :設置同一時間最大客戶端連接數,默認無限制,Redis 可以同時打開的客戶端連接數為 Redis 進程可以打開的最大文件描述符數,如果設置 maxclients 0,表示不作限制。當客戶端連接數到達限制時,Redis 會關閉新的連接並向客戶端返回 max number of clients reached 錯誤信息
  • maxmemory-policy 數據清除策
    • volatile-lru: 設置了過期時間的數據採取LRU(近期最少使用)算法.如果對key使用”expire”指令指定了過期時間,那麼此key將會被添加到”過期集合”中。將已經過期/LRU的數據優先移除.如果”過期集合”中全部移除仍不能滿足內存需求,將OOM。
    • allkeys-lru:對所有的數據,採用LRU算法
    • volatile-random:對設置了過期時間的數據採取”隨即選取”算法,並移除選中的K-V,直到”內存足夠”為止。如果”過期集合”中全部移除全部移除仍不能滿足,將OOM
    • allkeys-random:對所有的數據,採取”隨機選取”算法,並移除選中的K-V,直到”內存足夠”為止
    • volatile-ttl:對設置了過期時間的數據採取TTL算法(最小存活時間),移除即將過期的數據。
    • noeviction:不做任何干擾操作,直接返回OOM異常,也是默認選項,實際開發不要用該選項
  • # maxmemory-samples 3:上面LRU和最小TTL策略並非嚴謹的策略,而是大約估算的方式,因此可以選擇取樣值以便檢查,默認值3

redis持久化

傳送門:redis——持久化

redis訂閱發佈

簡介

Redis 發佈訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

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

訂閱/發佈消息圖:

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

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

命令

下表列出了 redis 發佈訂閱常用命令:

序號 命令及描述
1 PSUBSCRIBE pattern [pattern …]
訂閱一個或多個符合給定模式的頻道。
2 PUBSUB subcommand [argument [argument …]]
查看訂閱與發佈系統狀態。
3 PUBLISH channel message
將信息發送到指定的頻道。
4 PUNSUBSCRIBE [pattern [pattern …]]
退訂所有給定模式的頻道。
5 SUBSCRIBE channel [channel …]]
訂閱給定的一個或多個頻道的信息。
6 UNSUBSCRIBE [channel [channel …]]
指退訂給定的頻道。

測試

我們先打開兩個 redis-cli 客戶端

在第一個 redis-cli 客戶端作為訂閱客戶端,創建訂閱頻道名為 redisChat,輸入SUBSCRIBE redisChat

redis 127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1 

打開第二個客戶端作為發送端,在指定頻道上發佈兩次消息,訂閱者就能接收 到消息。

redis 127.0.0.1:6379> PUBLISH redisChat "Hello,Redis"
(integer) 1
redis 127.0.0.1:6379> PUBLISH redisChat "Hello,java"
(integer) 1

訂閱者的客戶端會顯示如下消息

1. "message"
2. "redisChat"
3. "Hello,Redis"

1. "message"
2. "redisChat"
3. "Hello,java"

總結

Redis是使用C實現的,通過分析 Redis 源碼里的 pubsub.c 文件,了解發佈和訂閱機制的底層實現,來加深對 Redis 的理解。

Redis 通過 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令實現發佈和訂閱功能。

通過 SUBSCRIBE 命令訂閱某頻道後,redis-server 里維護了一個字典,字典的鍵就是一個個 channel ,而字典的值則是一個鏈表,鏈表中保存了所有訂閱這個 channel 的客戶端。SUBSCRIBE 命令的關鍵,就是將客戶端添加到給定 channel 的訂閱鏈表中。

通過 PUBLISH 命令向訂閱者發送消息,redis-server 會使用給定的頻道作為鍵,在它所維護的 channel 字典中查找記錄了訂閱這個頻道的所有客戶端的鏈表,遍歷這個鏈表,將消息發佈給所有訂閱者。

Pub/Sub 從字面上理解就是發佈(Publish)與訂閱(Subscribe),在Redis中,你可以設定對某一個 key值進行消息發佈及消息訂閱,當一個key值上進行了消息發佈後,所有訂閱它的客戶端都會收到相應的消息。這一功能最明顯的用法就是用作實時消息系統,比如普通的即時聊天,群聊等功能。

使用場景:Redis的Pub/Sub系統可以構建實時的消息系統,比如很多用Pub/Sub構建的實時聊天系統的例子

集群環境搭建

Redis集群詳解

Redis支持三種集群方案

  • 主從複製模式
  • Sentinel(哨兵)模式
  • Cluster模式

主從複製

傳送門:redis集群之主從複製 – 至安 – 博客園 (cnblogs.com)

哨兵模式

解決什麼問題

哨兵模式之前主從切換的方法是當主服務器宕機後,需要手動把一台從服務器切換為主服務器,這就需要人工干預,費事費力,還會造成一段時間內服務不可用。這不是一種推薦的方式,更多時候,我們優先考慮哨兵模式。Redis從2.8開始正式提供了Sentinel(哨兵) 架構來解決這個問題。

謀朝篡位的自動版,能夠後台監控主機是否故障,如果故障了根據投票數自動將從庫轉換為主庫。

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

這裡的哨兵有兩個作用

  • 通過發送命令,讓Redis服務器返回監控其運行狀態,包括主服務器和從服務器。
  • 當哨兵監測到master宕機,會自動將slave切換成master,然後通過發佈訂閱模式通知其他的從服務器,修改配置文件,讓它們切換主機。

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

image-20210409150717930

假設主服務器宕機,哨兵1先檢測到這個結果,系統並不會馬上進行failover過程,僅僅是哨兵1主觀的認 為主服務器不可用,這個現象成為主觀下線。當後面的哨兵也檢測到主服務器不可用,並且數量達到一 定值時,那麼哨兵之間就會進行一次投票,投票的結果由一個哨兵發起,進行failover[故障轉移]操作。 切換成功後,就會通過發佈訂閱模式,讓各個哨兵把自己監控的從服務器實現切換主機,這個過程稱為 客觀下線

相關配置

模式配置文件 sentinel.conf

# 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

實戰測試

1 – 調整結構,6379帶着80、81

2 – 在redis.conf同級目錄下新建 sentinel.conf 文件,文件名固定

3 – 配置哨兵,填寫內容

#sentinel monitor 被監控主機名字 127.0.0.1 6379 n
例如:sentinel monitor mymaster 127.0.0.1 6379 1,

上面最後一個數字n,表示得票數,主機掛掉後從機投票接替成為主機,得票數到n的從機接替成為主機

4 – 啟動哨兵

Redis-sentinel myconfig/sentinel.conf

上述目錄依照各自的實際情況配置,可能目錄不同

成功啟動哨兵模式

在這裡插入圖片描述

此時哨兵監視着我們的主機6379,當我們斷開主機後:

在這裡插入圖片描述

哨兵模式的優缺點

優點

  1. 哨兵集群,基於主從複製模式,所有主從複製的優點,它都有
  2. 主從可以切換,故障可以轉移,系統的可用性更好
  3. 哨兵模式是主從模式的升級,手動到自動,更加健壯

缺點:

  1. Redis不好在線擴容,集群容量一旦達到上限,在線擴容就十分麻煩
  2. 實現哨兵模式的配置其實是很麻煩的,裏面有很多配置項

cluster模式

Redis Cluster日常操作命令梳理 – 散盡浮華 – 博客園 (cnblogs.com)

緩存穿透和雪崩

緩存穿透(查不到)

在默認情況下,用戶請求數據時,會先在緩存(Redis)中查找,若沒找到即緩存未命中,再在數據庫中進行查找,數量少可能問題不大,可是一旦大量的請求數據(例如秒殺場景)在緩存中都沒有命中的話,就會全部轉移到數據庫上,造成數據庫極大的壓力,可能導致數據庫崩潰。網絡安全中也有人惡意使用這種手段進行攻擊被稱為洪水攻擊。

解決方案

布隆過濾器

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

在這裡插入圖片描述

緩存空對象

一次請求若在緩存和數據庫中都沒找到,就在緩存中方一個空對象用於處理後續這個請求。

在這裡插入圖片描述

這樣做有一個缺陷:存儲空對象也需要空間,大量的空對象會耗費一定的空間,存儲效率並不高。解決這個缺陷的方式就是設置較短過期時間。即使對空值設置了過期時間,還是會存在緩存層和存儲層的數據會有一段時間窗口的不一致,這對於需要保持一致性的業務會有影響

緩存擊穿(量太大,緩存過期)

相較於緩存穿透,緩存擊穿的目的性更強,緩存中原本存在的key在過期的一刻,同時有大量的請求,這些請求都會擊穿到數據庫,造成瞬時DB請求量大、壓力驟增。這就是緩存被擊穿,只是針對其中某個key的緩存不可用而導致擊穿,但是其他的key依然可以使用緩存響應。

比如熱搜排行上,一個熱點新聞被同時大量訪問就可能導致緩存擊穿。

解決方案

  1. 設置熱點數據永不過期

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

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

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

緩存雪崩

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

比如馬上就要到雙十一零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了緩存,假設緩存一個小時。那麼到了凌晨一點鐘的時候,這批商品的緩存就都過期了。而對這批商品的訪問查詢,都落到了數據庫上,對於數據庫而言,就會產生周期性的壓力波峰。於是所有的請求都會達到存儲層,存儲層的調用量會暴增,造成存儲層也會掛掉的情況。

在這裡插入圖片描述

其實集中過期,倒不是非常致命,比較致命的緩存雪崩,是緩存服務器某個節點宕機或斷網。因為自然 形成的緩存雪崩,一定是在某個時間段集中創建緩存,這個時候,數據庫也是可以頂住壓力的。無非就 是對數據庫產生周期性的壓力而已。而緩存服務節點的宕機,對數據庫服務器造成的壓力是不可預知 的,很有可能瞬間就把數據庫壓垮。

解決方案

  • redis高可用

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

  • 限流降級

    這個解決方案的思想是,在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。

  • 數據預熱

    數據加熱的含義就是在正式部署之前,我先把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數據就會加載到緩存中。在即將發生大並發訪問前手動觸發加載緩存不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻。

Tags: