主頁 >  其他 > Redis常見問題和性能監控

Redis常見問題和性能監控

2022-10-18 07:28:31 其他

1 Redis常見面試問題

1.1 Redis是單執行緒還是多執行緒

Redis不同版本之間采用的執行緒模型是不一樣的,在Redis4.0版本之前使用的是單執行緒模型,在4.0版本之后增加了多執行緒的支持,

4.0之前雖然說Redis是單執行緒,也只是說它的網路I/O執行緒以及SetGet操作是由一個執行緒完成的,但是Redis持久化集群同步還是使用其他執行緒來完成,

4.0之后添加了多執行緒的支持,主要是體現在大資料的異步洗掉功能上,例如 unlink key、flushdb async、flushall async

1.2 使用單執行緒原因

那為什么Redis在4.0之前會選擇使用單執行緒?而且使用單執行緒還那么快?

選擇單執行緒主要是使用簡單,不存在鎖競爭,可以在無鎖的情況下完成所有操作,不存在死鎖和執行緒切換帶來的性能和時間上的開銷,但同時單執行緒也不能完全發揮出多核CPU性能

為什么單執行緒那么快主要有以下幾個原因:

Redis的大部分操作都在記憶體中完成,記憶體中的執行效率本身就很快,并且采用了高效的資料結構,比如哈希表和跳表,
使用單執行緒避免了多執行緒的競爭,省去了多執行緒切換帶來的時間和性能開銷,并且不會出現死鎖,
采用I/O 多路復用機制處理大量客戶端的Socket請求,因為這是基于非阻塞的 I/O 模型,這就讓Redis可以高效地進行網路通信,I/O的讀寫流程也不再阻塞,

1.3 Redis持久化

Redis資料是存盤在記憶體中的,為了保證Redis資料不丟失,那就要把資料從記憶體存盤到磁盤上,以便在服務器重啟后還能夠從磁盤中恢復原有資料,這就是Redis的資料持久化,
Redis資料持久化有三種方式:

  • AOF 日志(Append Only File,檔案追加方式):記錄所有的操作命令,并以文本的形式追加到檔案中,
  • RDB快照(Redis DataBase):將某一個時刻的記憶體資料,以二進制的方式寫入磁盤,
  • 混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDBAOF 的優點,

1.3.1 AOF

AOF采用的是寫后日志的方式,Redis先執行命令把資料寫入記憶體,然后再記錄日志到檔案中,AOF日志記錄的是操作命令,不是實際的資料,如果采用AOF方法做故障恢復時需要將全量日志都執行一遍,
在這里插入圖片描述
AOF采用的是寫后日志的方式,我們平時用的MySQL則采用的是 寫前日志,那 Redis為什么要先執行命令,再把資料寫入日志呢?

這個主要是由于Redis在寫入日志之前,不對命令進行語法檢查,所以只記錄執行成功的命令,避免出現記錄錯誤命令的情況,而且在命令執行后再寫日志不會阻塞當前的寫操作

后寫日志的風險:

  • 資料可能會丟失:如果 Redis 剛執行完命令,此時發生故障宕機,會導致這條命令存在丟失的風險,
  • 可能阻塞其他操作:AOF 日志其實也是在主執行緒中執行,所以當 Redis 把日志檔案寫入磁盤的時候,還是會阻塞后續的操作無法執行,

1.3.2 RDB

RDB采用的是記憶體快照的方式,它記錄的是某一時刻的資料,而不是操作,所以采用RDB方法做故障恢復時只需要直接把RDB檔案讀入記憶體即可,實作快速恢復,

Redis 提供了兩個命令來生成 RDB 快照檔案,分別是 savebgsavesave 命令在主執行緒中執行,會導致阻塞,而 bgsave 命令則會創建一個子行程,用于寫入 RDB 檔案的操作,避免了對主執行緒的阻塞,這也是 Redis RDB 的默認配置,
save是同步的會阻塞客戶端命令,bgsave是在同步期間的時候是可以修改資料,

Redis是怎么解決在bgsave做快照的時候允許資料修改呢

這里主要是利用bgsave的子執行緒實作的,具體操作如下:
如果主執行緒執行讀操作,則主執行緒和 bgsave 子行程互相不影響;
如果主執行緒執行寫操作,則被修改的資料會復制一份副本,然后 bgsave子行程會把該副本資料寫入 RDB 檔案,在這個程序中,主執行緒仍然可以直接修改原來的資料,
在這里插入圖片描述

需要注意,RedisRDB 的執行頻率非常重要,因為這會影響快照資料的完整性以及 Redis 的穩定性,所以在 Redis 4.0 后,增加了 AOFRDB 混合的資料持久化機制: 把資料以 RDB 的方式寫入檔案,再將后續的操作命令以 AOF 的格式存入檔案,既保證了 Redis 重啟速度,又降低資料丟失風險,

1.4 Redis高可用

Redis實作高可用主要有三種方式:主從復制哨兵模式,以及 Redis 集群

1.4.1 主從復制

將從前的一臺 Redis 服務器,同步資料到多臺從 Redis 服務器上,即一主多從的模式,這個跟MySQL主從復制的原理一樣,
在這里插入圖片描述

1.4.2 哨兵模式

使用 Redis 主從復制的時候,會有一個問題,就是當 Redis 的主從服務器出現故障宕機時,需要手動進行恢復,為了解決這個問題,Redis 增加了哨兵模式(因為哨兵模式做到了可以監控主從服務器,并且提供自動容災恢復的功能),

圖片

1.4.3 Redis Cluster(集群)

Redis Cluster 是一種分布式去中心化的運行模式,是在 Redis 3.0 版本中推出的 Redis 集群方案,它將資料分布在不同的服務器上,以此來降低系統對單主節點的依賴,從而提高 Redis 服務的讀寫性能,

圖片

使用哨兵模式在資料上有副本資料做保證,在可用性上又有哨兵監控,一旦master宕機會選舉salve節點為master節點,那為什么還需要使用集群模式呢?
哨兵模式歸根節點還是主從模式,在主從模式下我們可以通過增加salve節點來擴展讀并發能力,但是沒辦法擴展寫能力和存盤能力,存盤能力只能是master節點能夠承載的上限,所以為了擴展寫能力和存盤能力,我們就需要引入集群模式,

集群中那么多Master節點,redis cluster在存盤的時候如何確定選擇哪個節點呢?
Redis Cluster采用的是類一致性哈希演算法實作節點選擇的

Redis Cluster將自己分成了16384個Slot(槽位),哈希槽類似于資料磁區,每個鍵值對都會根據它的 key,被映射到一個哈希槽中,具體執行程序分為兩大步:

  • 根據鍵值對的 key,按照 CRC16 演算法計算一個 16 bit 的值,
  • 再用 16bit 值對 16384 取模,得到 0~16383 范圍內的模數,每個模數代表一個相應編號的哈希槽,

每個Redis節點負責處理一部分槽位,假入有三個master節點 ABC,每個節點負責的槽位如下:

節點 處理槽位
A 0-5000
B 5001 - 10000
C 10001 - 16383

Redis集群搭建

1.5 Redis記憶體(資料)淘汰策略

redis中,我們是可以去設定最大使用記憶體大小server.maxmemory的,當redis記憶體資料集大小上升到一定程度的時候,就會施行資料淘汰機制,
Redis提供了幾種資料淘汰策略?該怎么選擇?

  • volatile-lru:從已經設定過期時間的資料集中,挑選最近最少使用的資料淘汰,
  • volatile-ttl:從已經設定過期時間的資料集中,挑選即將要過期的資料淘汰,
  • volatile-random:從已經設定過期時間的資料集中,隨機挑選資料淘汰,
  • volatile-lfu:從已經設定過期時間的資料集中,會使用LFU演算法選擇設定了過期時間的鍵值對,
  • allkeys-lru:從所有的資料集中,挑選最近最少使用的資料淘汰,
  • allkeys-random:從所有的資料集中,隨機挑選資料淘汰,
  • no-enviction:禁止淘汰資料,如果redis寫滿了將不提供寫請求,直接回傳錯誤

附錄:LRULFU是不同的:

  • LRU是最近最少使用頁面置換演算法(Least Recently Used),也就是首先淘汰最長時間未被使用的頁面!
  • LFU是最近最不常用頁面置換演算法(Least Frequently Used),也就是淘汰一定時期內被訪問次數最少的頁

使用策略規則:

  • 如果資料呈現冪律分布,也就是一部分資料訪問頻率高,一部分資料訪問頻率低,則使用allkeys-lru
  • 如果資料呈現平等分布,也就是所有的資料訪問頻率都相同,則使用allkeys-random

1.6 Redis過期鍵洗掉策略

Redis過期鍵洗掉策略:

  • 定時洗掉:在設定鍵的過期時間的同時,創建一個timer,讓定時器在鍵的過期時間到達時,立即執行對鍵的洗掉操作,(主動洗掉)
    對記憶體友好,但是對cpu時間不友好,有較多過期鍵的而情況下,洗掉過期鍵會占用相當一部分cpu時間,
  • 惰性洗掉:放任過期鍵不管,但是每次從鍵空間中獲取鍵時,都檢查取到的鍵是否過去,如果過期就洗掉,如果沒過期就回傳該鍵,(被動洗掉)
    cpu時間友好,程式只會在取出鍵的時候才會對鍵進行過期檢查,這不會在洗掉其他無關過期鍵上花費任何cpu時間,但是如果一個鍵已經過期,而這個鍵又保留在資料庫中,那么只要這個過期鍵不被洗掉,他所占用的記憶體就不會釋放,對記憶體不友好,
  • 定期洗掉:每隔一段時間就對資料庫進行一次檢查,洗掉里面的過期鍵,(主動洗掉)采用對記憶體cpu時間折中的方法,每隔一段時間就對一些 key 進行采樣檢查,檢查是否過期,如果過期就進行洗掉
    1、采樣一定個數的key,采樣的個數可以進行配置,并將其中過期的 key 全部洗掉;
    2、如果過期 key 的占比超過可接受的過期 key 的百分比,則重復洗掉的程序,直到過期key的比例降至可接受的過期 key 的百分比以下

1.7 Redis的key和value可以存盤的最大值分別是多少

雖然Key的大小上限為512M,但是一般建議key的大小不要超過1KB,這樣既可以節約存盤空間,又有利于Redis進行檢索,
value的最大值也是512M,對于String型別的value值上限為512M,而集合、鏈表、哈希等key型別,單個元素的value上限也為512M

1.8 Redis實作資料的去重

  • Redisset:它可以去除重復元素,也可以快速判斷某一個元素是否存在于集合中,如果元素很多(比如上億的計數),占用記憶體很大,
  • Redisbit:它可以用來實作比set記憶體高度壓縮的計數,它通過一個bit設定為1或者0,表示存盤某個元素是否存在資訊,例如網站唯一訪客計數,可以把user_id作為 bit的偏移量 offset,如設定為1表示有訪問,使用1 MB的空間就可以存放800多萬用戶的一天訪問計數情況,
  • HyperLogLog:實作超大資料量精確的唯一計數都是比較困難的,HyperLogLog可以僅僅使用 12 k左右的記憶體,實作上億的唯一計數,而且誤差控制在百分之一左右,
  • bloomfilter布隆過濾器:布隆過濾器是一種占用空間很小的資料結構,它由一個很長的二進制向量和一組Hash映射函陣列成,它用于檢索一個元素是否在一個集合中

1.9 Redis序列化

Redis什么時候需要序列化?

  • 序列化:將 Java 物件轉換成位元組流的程序,
  • 反序列化:將位元組流轉換成 Java 物件的程序,
    圖片
    為什么需要序列化呢?
    打個比喻:作為大城市漂泊的碼農,搬家是常態,當我們搬書桌時,桌子太大了就通不過比較小的門,因此我們需要把它拆開再搬過去,這個拆桌子的程序就是序列化,而我們把書桌復原回來(安裝)的程序就是反序列化啦,

比如想把記憶體中的物件狀態保存到一個檔案中或者資料庫中的時候(最常用,如保存到redis);再比喻想用套接字在網路上傳送物件的時候,都需要序列化,
RedisSerializer介面 是 Redis 序列化介面,用于 Redis KEYVALUE 的序列化,有如下序列化方式:

  • JDK 序列化方式 (默認)
  • String 序列化方式
  • JSON 序列化方式
  • XML 序列化方式

2 Redis監控

2.1 Redis監控指標

監控指標

  • 性能指標:Performance
  • 記憶體指標: Memory
  • 基本活動指標:Basic activity
  • 持久性指標: Persistence
  • 錯誤指標:Error

2.1.1 性能指標: Performance

Name Description
latency Redis回應一個請求的時間
instantaneous_ops_per_sec 平均每秒處理請求總數
hi rate(calculated)` 快取命中率(計算出來的

2.1.2 記憶體指標: Memory

Name Description
used_memory 已使用記憶體
mem_fragmentation_ratio 記憶體碎片率
evicted_keys 由于最大記憶體限制被移除的key的數量
blocked_clients 由于BLPOP,BRPOP,or BRPOPLPUSH而備阻塞的客戶端

2.1.3 基本活動指標:Basic activity

Name Description
connected_clients 客戶端連接數
conected_laves slave數量
master_last_io_seconds_ago 最近一次主從互動之后的秒數
keyspace 資料庫中的key值總數

2.1.4 持久性指標: Persistence

Name Description
rdb_last_save_time 最后一次持久化保存磁盤的時間戳
rdb_changes_sice_last_save 自最后一次持久化以來資料庫的更改數

2.1.5 錯誤指標:Error

Name Description
rejected_connections 由于達到maxclient限制而被拒絕的連接數
keyspace_misses key 值查找失敗(沒有命中)次數
master_link_down_since_seconds 主從斷開的持續時間(以秒為單位)

2.2 監控方式

Redis監控方式:

  • redis-benchmark
  • redis-stat
  • redis-faina
  • redislive
  • redis-cli
  • monitor
  • showlog
    get:獲取慢查詢日志
    len:獲取慢查詢日志條目數
    reset:重置慢查詢日志

相關配置:

slowlog-log-slower-than 1000# 設定慢查詢的時間下線,單位:微秒
slowlog-max-len 100 # 設定慢查詢命令對應的日志顯示長度,單位:命令數

2.2.1 info

info(可以一次性獲取所有的資訊,也可以按塊獲取資訊)

  1. server:服務器運行的環境引數
  2. clients:客戶端相關資訊
  3. memory:服務器運行記憶體統計資料
  4. persistence:持久化資訊
  5. stats:通用統計資料
  6. Replication:主從復制相關資訊
  7. CPU:CPU使用情況
  8. cluster:集群資訊
  9. Keypass:鍵值對統計數量資訊

終端info命令使用

./redis-cli info 按塊獲取資訊 | grep 需要過濾的引數
./redis-cli info stats | grep ops

互動式info命令使用

./redis-cli > info server

2.2.2 性能監控:

redis-cli info | grep ops # 每秒運算元

在這里插入圖片描述

2.2.3 記憶體監控

記憶體監控

./redis-cli info | grep used | grep human
used_memory_human:2.99M #記憶體分配器從作業系統分配的記憶體總量
used_memory_rss_human:8.04M #作業系統看到的記憶體占用,top命令看到的記憶體
used_memory_peak_human:7.77M # redis記憶體消耗的峰值
used_memory_lua_human:37.00K # lua腳本引擎占用的記憶體大小

由于BLPOP,BRPOP,or BRPOPLPUSH而備阻塞的客戶端,使用如下命令:

./redis-cli info | grep
blocked_clientsblocked_clients:0

由于最大記憶體限制被移除的key的數量

./redis-cli info | grep
evicted_keysevicted_keys:0 #

記憶體碎片率

./redis-cli info | grep
mem_fragmentation_ratiomem_fragmentation_ratio:2.74

已使用記憶體

./redis-cli info | grep
used_memory:used_memory:3133624

2.2.4 基本活動指標

redis連接了多少客戶端 通過觀察其數量可以確認是否存在意料之外的連接,如果發現數量不對勁,就可以使用lcient list指令列出所有的客戶端鏈接地址來確定源頭,

[root@CombCloud-2020110836 src]# ./redis-cli info | grep connected_clientsconnected_clients:1

[root@CombCloud-2020110836 src]# ./redis-cli info | grep connectedconnected_clients:1 # 客戶端連接數量connected_slaves:1 # slave連接數量

2.2.5 持久性指標

持久性指標

[root@CombCloud-2020110836 src]# ./redis-cli info | grep rdb_last_save_timerdb_last_save_time:1591876204 # 最后一次持久化保存磁盤的時間戳
[root@CombCloud-2020110836 src]# ./redis-cli info | grep rdb_changes_since_last_saverdb_changes_since_last_save:0 # 自最后一次持久化以來資料庫的更改數

2.2.6 錯誤指標

由于超出最大連接數限制而被拒絕的客戶端連接次數,如果這個數字很大,則意味著服務器的最大連接數設定得過低,需要調整maxclients

[root@CombCloud-2020110836 src]# ./redis-cli info | grep
connected_clientsconnected_clients:1

key值查找失敗(沒有命中)次數,出現多次可能是被hei ke gongjji

[root@CombCloud-2020110836 src]# ./redis-cli info | grep
keyspacekeyspace_misses:0

主從斷開的持續時間(以秒為單位)

[root@CombCloud-2020110836 src]# ./redis-cli info | grep
rdb_changes_since_last_saverdb_changes_since_last_save:0

復制積壓緩沖區如果設定得太小,會導致里面的指令被覆寫掉找不到偏移量,從而觸發全量同步

[root@CombCloud-2020110836 src]# ./redis-cli info | grep
backlog_sizerepl_backlog_size:1048576

通過查看sync_partial_err變數的次數來決定是否需要擴大積壓緩沖區,它表示主從半同步復制失敗的次數

[root@CombCloud-2020110836 src]# ./redis-cli info | grep sync_partial_errsync_partial_err:1

2.3 redis性能測驗命令

./redis-benchmark -c 100 -n 5000
說明:100個連接,5000次請求對應的性能

在這里插入圖片描述

2.4 Redis回應慢

一旦 Redis 請求延遲增加,可能就會導致業務系統雪崩

2.4.1 延遲基線測量

redis-cli 命令提供了--intrinsic-latency 選項,用來監測和統計測驗期間內的最大延遲(以毫秒為單位),這個延遲可以作為 Redis 的基線性能,

redis-cli --latency -h host -p port

比如執行如下指令:

redis-cli --intrinsic-latency 100
Max latency so far: 4 microseconds.
Max latency so far: 18 microseconds.
Max latency so far: 41 microseconds.
Max latency so far: 57 microseconds.
Max latency so far: 78 microseconds.
Max latency so far: 170 microseconds.
Max latency so far: 342 microseconds.
Max latency so far: 3079 microseconds.

45026981 total runs (avg latency: 2.2209 microseconds / 2220.89 nanoseconds per run).
Worst run took 1386x longer than the average latency.

注意:引數100是測驗將執行的秒數,我們運行測驗的時間越長,我們就越有可能發現延遲峰值,
通常運行 100 秒通常是合適的,足以發現延遲問題了,當然我們可以選擇不同時間運行幾次,避免誤差,

此次運行的最大延遲是 3079 微秒,所以基線性能是 3079 (3 毫秒)微秒,

需要注意的是,我們要在 Redis 的服務端運行,而不是客戶端,這樣,可以避免網路對基線性能的影響,

可以通過 -h host -p port 來連接服務端,如果想監測網路對 Redis 的性能影響,可以使用 Iperf 測量客戶端到服務端的網路延遲,

如果網路延遲幾百毫秒,說明網路可能有其他大流量的程式在運行導致網路擁塞,需要找運維協調網路的流量分配,

2.4.2 慢指令監控

如何判斷是否是慢指令呢?
看操作復雜度是否是O(N),官方檔案對每個命令的復雜度都有介紹,盡可能使用O(1)O(log N)命令,

涉及到集合操作的復雜度一般為O(N),比如集合全量查詢HGETALL、SMEMBERS,以及集合的聚合操作:SORT、LREM、 SUNION等,

那么有監控資料可以觀測呢?代碼不是我寫的,不知道有沒有人用了慢指令,
有兩種方式可以排查到:

  • 使用 Redis 慢日志功能查出慢命令;
  • latency-monitor(延遲監控)工具,

此外,可以使用自己(top、htop、prstat 等)快速檢查 Redis 主行程的 CPU消耗,如果 CPU 使用率很高而流量不高,通常表明使用了慢速命令,

2.4.2.1 慢日志功能

Redis 中的 slowlog 命令可以讓我們快速定位到那些超出指定執行時間的慢命令,默認情況下命令若是執行時間超過 10ms 就會被記錄到日志,

slowlog 只會記錄其命令執行的時間,不包含 io 往返操作,也不記錄單由網路延遲引起的回應慢,

我們可以根據基線性能來自定義慢命令的標準(配置成基線性能最大延遲的 2 倍),調整觸發記錄慢命令的閾值,

可以在 redis-cli中輸入以下命令配置記錄 6 毫秒以上的指令:

redis-cli CONFIG SET slowlog-log-slower-than 6000

也可以在 Redis.config 組態檔中設定,以微秒為單位,

想要查看所有執行時間比較慢的命令,可以通過使用 Redis-cli 工具,輸入 slowlog get 命令查看,回傳結果的第三個欄位以微秒位單位顯示命令的執行時間,

假如只需要查看最后 2 個慢命令,輸入 slowlog get 2 即可,
示例:獲取最近2個慢查詢命令

127.0.0.1:6381> SLOWLOG get 2
1) 1) (integer) 6
   2) (integer) 1458734263
   3) (integer) 74372
   4) 1) "hgetall"
      2) "max.dsp.blacklist"
2) 1) (integer) 5
   2) (integer) 1458734258
   3) (integer) 5411075
   4) 1) "keys"
      2) "max.dsp.blacklist"

以第一個 HGET 命令為例分析,每個 slowlog 物體共 4 個欄位:

  • 欄位 1:1 個整數,表示這個 slowlog 出現的序號,server 啟動后遞增,當前為 6,
  • 欄位 2:表示查詢執行時的Unix時間戳,
  • 欄位 3:表示查詢執行微秒數,當前是 74372 微秒,約 74ms,
  • 欄位 4: 表示查詢的命令引數,如果引數很多或很大,只會顯示部分引數個數,當前命令是hgetall max.dsp.blacklist,

2.4.2.2 Latency Monitoring

Redis2.8.13 版本引入了 Latency Monitoring 功能,用于以秒為粒度監控各種事件的發生頻率,

啟用延遲監視器的第一步是設定延遲閾值(單位毫秒),只有超過該閾值的時間才會被記錄,比如我們根據基線性能(3ms)的 3 倍設定閾值為 9 ms,

可以用 redis-cli 設定也可以在 Redis.config 中設定;

CONFIG SET latency-monitor-threshold 9

工具記錄的相關事件的詳情可查看官方檔案:https://redis.io/topics/latency-monitor

如獲取最近的 latency

127.0.0.1:6379> debug sleep 2
OK
(2.00s)
127.0.0.1:6379> latency latest
1) 1) "command"
   2) (integer) 1645330616
   3) (integer) 2003
   4) (integer) 2003

以上欄位說明:

  1. 事件的名稱;
  2. 事件發生的最新延遲的 Unix 時間戳;
  3. 毫秒為單位的時間延遲;
  4. 該事件的最大延遲,

2.4.3 如何解決 Redis 變慢

Redis 的資料讀寫由單執行緒執行,如果主執行緒執行的操作時間太長,就會導致主執行緒阻塞,
那么分析下都有哪些操作會阻塞主執行緒,我們又該如何解決?

2.4.3.1 網路通信導致的延遲

客戶端使用 TCP/IP 連接或 Unix 域連接連接到 Redis1 Gbit/s 網路的典型延遲約為 200 us

redis 客戶端執行一條命令分 4 個程序:

發送命令-〉 命令排隊 -〉 命令執行-〉 回傳結果

這個程序稱為 Round trip time(簡稱 RTT, 往返時間),mget mset 有效節約了 RTT,但大部分命令(如 hgetall,并沒有 mhgetall)不支持批量操作,需要消耗 NRTT ,這個時候需要 pipeline來解決這個問題,

Redis pipeline 將多個命令連接在一起來減少網路回應往返次數,

在這里插入圖片描述

2.4.3.2 慢指令導致的延遲

根據上文的慢指令監控查詢檔案,查詢到慢查詢指令,可以通過以下兩種方式解決:

  • Cluster 集群中,將聚合運算等 O(N) 操作運行在 slave 上,或者在客戶端完成,
  • 使用高效的命令代替,使用增量迭代的方式,避免一次查詢大量資料,具體請查看SCAN、SSCAN、HSCAN和ZSCAN命令,

除此之外,生產中禁用KEYS 命令,它只適用于除錯,因為它會遍歷所有的鍵值對,所以操作延時高,

2.4.3.3 Fork生成 RDB導致的延遲

生成 RDB 快照,Redis 必須 fork 后臺行程,fork 操作(在主執行緒中運行)本身會導致延遲
Redis 使用作業系統的多行程寫時復制技術 COW(Copy On Write)來實作快照持久化,減少記憶體占用,

在這里插入圖片描述

fork 會涉及到復制大量鏈接物件,一個24 GB 的大型 Redis 實體需要 24 GB / 4 kB * 8 = 48 MB 的頁表,
執行 bgsave 時,這將涉及分配和復制 48 MB 記憶體,

此外,從庫加載 RDB 期間無法提供讀寫服務,所以主庫的資料量大小控制在 2~4G 左右,讓從庫快速的加載完成,

2.4.3.4 記憶體大頁(transparent huge pages)

常規的記憶體頁是按照 4 KB 來分配,Linux 內核從 2.6.38 開始支持記憶體大頁機制,該機制支持 2MB 大小的記憶體頁分配,

Redis 使用了 fork 生成 RDB 做持久化提供了資料可靠性保證,

當生成 RDB 快照的程序中,Redis 采用 寫時復制 技術使得主執行緒依然可以接收客戶端的寫請求,

也就是當資料被修改的時候,Redis 會復制一份這個資料,再進行修改,

采用了記憶體大頁,生成 RDB 期間,即使客戶端修改的資料只有 50B 的資料,Redis 需要復制 2MB 的大頁,當寫的指令比較多的時候就會導致大量的拷貝,導致性能變慢,

使用以下指令禁用 Linux 記憶體大頁即可:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

2.4.3.5 swap:作業系統分頁

當物理記憶體(記憶體條)不夠用的時候,將部分記憶體上的資料交換到 swap 空間上,以便讓系統不會因記憶體不夠用而導致 oom 或者更致命的情況出現,

當某行程向 OS 請求記憶體發現不足時,OS 會把記憶體中暫時不用的資料交換出去,放在 SWAP 磁區中,這個程序稱為 SWAP OUT

當某行程又需要這些資料且 OS 發現還有空閑物理記憶體時,又會把 SWAP 磁區中的資料交換回物理記憶體中,這個程序稱為 SWAP IN
記憶體 swap 是作業系統里將記憶體資料在記憶體磁盤間來回換入和換出的機制,涉及到磁盤的讀寫,

觸發 swap 的情況有哪些呢?
對于 Redis 而言,有兩種常見的情況:

  • Redis 使用了比可用記憶體更多的記憶體;
  • Redis 在同一機器運行的其他行程在執行大量的檔案讀寫 I/O 操作(包括生成大檔案的 RDB 檔案和 AOF 后臺執行緒),檔案讀寫占用記憶體,導致 Redis 獲得的記憶體減少,觸發了 swap

那么如何排查是否因為 swap 導致的性能變慢呢?

Linux 提供了很好的工具來排查這個問題,所以當懷疑由于交換導致的延遲時,只需按照以下步驟排查,

2.4.3.5.1 獲取 Redis 實體 pid
$ redis-cli info | grep process_id
process_id:13160

進入此行程的 /proc 檔案系統目錄:

cd /proc/13160

在這里有一個 smaps 的檔案,該檔案描述了 Redis 行程的記憶體布局,運行以下指令,用 grep 查找所有檔案中的 Swap 欄位,

$ cat smaps | egrep '^(Swap|Size)'
Size:                316 kB
Swap:                  0 kB
Size:                  4 kB
Swap:                  0 kB
Size:                  8 kB
Swap:                  0 kB
Size:                 40 kB
Swap:                  0 kB
Size:                132 kB
Swap:                  0 kB
Size:             720896 kB
Swap:                 12 kB

每行 Size 表示 Redis 實體所用的一塊記憶體大小,和 Size 下方的 Swap 對應這塊 Size 大小的記憶體區域有多少資料已經被換出到磁盤上了,
如果 Size == Swap 則說明資料被完全換出了,

可以看到有一個 720896 kB 的記憶體大小有 12 kb 被換出到了磁盤上(僅交換了 12 kB),這就沒什么問題,

Redis 本身會使用很多大小不一的記憶體塊,所以,你可以看到有很多 Size行,有的很小,就是 4KB,而有的很大,例如 720896KB,不同記憶體塊被換出到磁盤上的大小也不一樣,

注意 : 如果 Swap 一切都是 0 kb,或者零星的 4k ,那么一切正常,
當出現百 MB,甚至 GB 級別的 swap 大小時,就表明,此時,Redis 實體的記憶體壓力很大,很有可能會變慢,

2.4.3.5.2 解決方案
  1. 增加機器記憶體;
  2. Redis 放在單獨的機器上運行,避免在同一機器上運行需要大量記憶體的行程,從而滿足 Redis 的記憶體需求;
  3. 增加Cluster集群的數量分擔資料量,減少每個實體所需的記憶體,

2.4.3.6 AOF 和磁盤 I/O 導致的延遲

為了保證資料可靠性,Redis 使用 AOFRDB 快照實作快速恢復和持久化,
可以使用 appendfsync 配置將 AOF 配置為以三種不同的方式在磁盤上執行 write 或者 fsync (可以在運行時使用 CONFIG SET命令修改此設定,比如:redis-cli CONFIG SET appendfsync no),

  • noRedis 不執行 fsync,唯一的延遲來自于 write 呼叫,write 只需要把日志記錄寫到內核緩沖區就可以回傳,
  • everysecRedis 每秒執行一次 fsync,使用后臺子執行緒異步完成 fsync 操作,最多丟失 1s 的資料,
  • always:每次寫入操作都會執行 fsync,然后用 OK 代碼回復客戶端(實際上 Redis 會嘗試將同時執行的許多命令聚集到單個 fsync 中),沒有資料丟失,在這種模式下,性能通常非常低,強烈建議使用快速磁盤和可以在短時間內執行 fsync 的檔案系統實作,

我們通常將 Redis 用于快取,資料丟失完全可以從資料獲取,并不需要很高的資料可靠性,建議設定成 no 或者 everysec

除此之外,避免 AOF 檔案過大, Redis 會進行 AOF 重寫,生成縮小的 AOF 檔案,

可以把配置項 no-appendfsync-on-rewrite設定為 yes,表示在 AOF 重寫時,不進行 fsync 操作,也就是說,Redis 實體把寫命令寫到記憶體后,不呼叫后臺執行緒進行 fsync 操作,就直接回傳了,

2.4.3.7 expires淘汰過期資料

Redis 有兩種方式淘汰過期資料:

  • 惰性洗掉:當接收請求的時候發現 key 已經過期,才執行洗掉;
  • 定時洗掉:每 100 毫秒洗掉一些過期的 key

定時洗掉的演算法如下:

  1. 隨機采樣 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP個數的 key,洗掉所有過期的 key
  2. 如果發現還有超過 25%key 已過期,則執行步驟一,

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP默認設定為 20,每秒執行 10次,洗掉 200key 問題不大,

如果觸發了第二條,就會導致 Redis 一致在洗掉過期資料去釋放記憶體,而洗掉是阻塞的

那么觸發條件是什么

就是大量的 key 設定了相同的時間引數,同一秒內,大量 key 過期,需要重復洗掉多次才能降低到 25% 以下,

簡而言之:大量同時到期的 key 可能會導致性能波動,

2.4.3.7.1 解決方案

如果一批 key 的確是同時過期,可以在 EXPIREATEXPIRE 的過期時間引數上,加上一個一定大小范圍內的亂數,這樣,既保證了 key 在一個鄰近時間范圍內被洗掉,又避免了同時過期造成的壓力,

2.4.3.8 bigkey

通常我們會將含有較大資料或含有大量成員、串列數的 Key 稱之為大 Key,下面我們將用幾個實際的例子對大 Key 的特征進行描述:

  • 一個 STRING 型別的 Key,它的值為 5MB(資料過大)
  • 一個 LIST 型別的 Key,它的串列數量為 10000個(串列數量過多)
  • 一個 ZSET 型別的 Key,它的成員數量為 10000 個(成員數量過多)
  • 一個 HASH格式的 Key,它的成員數量雖然只有 1000 個但這些成員的 value 總大小為 10MB(成員體積過大)

bigkey 帶來問題如下:

  1. Redis 記憶體不斷變大引發 OOM,或者達到 maxmemory 設定值引發寫阻塞或重要 Key 被逐出;
  2. Redis Cluster 中的某個 node 記憶體遠超其余 node,但因 Redis Cluster的資料遷移最小粒度為 Key 而無法將 node 上的記憶體均衡化;
  3. bigkey 的讀請求占用過大帶寬,自身變慢的同時影響到該服務器上的其它服務;
  4. 洗掉一個 bigkey 造成主庫較長時間的阻塞并引發同步中斷或主從切換;
2.4.3.8.1 查找bigkey

使用 redis-rdb-tools 工具以定制化方式找出大 Key

2.4.3.8.2 解決方案
  1. 對大 key 拆分
    如將一個含有數萬成員的HASH Key 拆分為多個 HASH Key,并確保每個 Key 的成員數量在合理范圍,在 Redis Cluster 結構中,大 Key 的拆分對 node 間的記憶體平衡能夠起到顯著作用,

  2. 異步清理大key
    Redis 自 4.0 起提供了 UNLINK 命令,該命令能夠以非阻塞的方式緩慢逐步的清理傳入的 Key,通過 UNLINK,可以安全的洗掉大Key甚至特大 Key

    轉載:https://mp.weixin.qq.com/s/qvXm1pU8T_2mCZCjkTR7QA

本文來自博客園,作者:xiao智,轉載請注明原文鏈接:https://www.cnblogs.com/yuwen01/p/16800702.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/516404.html

標籤:其他

上一篇:Dubbo2.7原始碼詳解

下一篇:mac上的類xshell的工具termius功能研究測驗,附mac上安裝brew并解壓asar檔案

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more