面試官:Redis中的緩衝區瞭解嗎

七淅在學Java發表於2022-03-26

hello 大家好,我是七淅(xī)。

Redis 大家肯定不陌生,但在使用層面看不到的地方,就容易被忽略。今天想和大家分享的內容是 Redis 各個緩衝區的作用、溢位的後果及優化方向

在開始正文前,想多叨叨幾句。不管是 Redis 還是其他中介軟體,底層很多原理都是相似的,設計思想都是通用的。

大家以後如果在學什麼新框架/元件,可以儘量和已經學過的知識點進行聯想,這樣會更容易理解點的,不至於說死記硬背。

比如現在說到的緩衝區,它的目的是什麼呢?

無它,為了效能。

要麼快取資料,提高響應速度。比如 MySQL 中有個 change buffer

要麼擔心消費者速度跟不上生產,怕資料丟失。所以需要把生產資料先暫存起來。Redis 的緩衝區就是這個作用。

另外,消費者速度跟不上,如果是同步處理的話,那是不是也會拖慢生產者,所以這裡其實也是在保證生產者的速度。

可能有的讀者會說:扯淡,消費者都跟不上了,生產者再快有什麼用?

其實有沒有一種可能,生產者根本不關心消費者什麼時候用呢?前者是負責把後者需要的東西處理好給它就完事了。生產者很忙,還有其他一大堆資料要處理,不能慢慢等消費者同步消費完才去做其他事情。

好像開頭擴充套件得有點多,我收一收,下面會詳細說到。有疑問的小夥伴請上車,七淅正式發車了。

1. 各緩衝區

首先 Redis 有什麼緩衝區呢?

一共 4 個:

  • 客戶端輸入緩衝區
  • 客戶端輸出緩衝區
  • 複製緩衝區
  • 複製積壓緩衝區

2. 客戶端輸入緩衝區

伺服器端會給每個連線的客戶端都設定了一個輸入緩衝區。

2.1 作用

暫存請求資料。

輸入緩衝區會先把客戶端傳送過來的命令暫存起來,Redis 主執行緒再從輸入緩衝區中讀取命令,進行處理。

為了避免客戶端和伺服器端的請求傳送和處理速度不匹配,這點和等下要說的輸出緩衝區是一樣的。

2.2 溢位場景

首先緩衝區是一塊固定大小的記憶體區域,如果要把這個地方填滿的話,那 Redis 會直接把客戶端連線關閉。

保護自己嘛,你客戶端掛了總比我服務端掛了好,服務端一掛就是所有客戶端都沒用了。

那填滿緩衝區就有 2 個情況了:

  1. 要麼一下子填滿
  2. 要麼生產速度大於消費速度,慢慢被填滿

那麼把上述原理對應到 Redis 的場景。

一下子填滿的情況可以是往 Redis 裡寫大量資料,百萬千萬數量級那種。

另一個情況可以是 Redis 服務端因執行耗時操作,阻塞住了,導致沒法消費輸入緩衝區資料。

2.3 優化

對應上面 2 個溢位場景,優化方向很自然就有了。

一下子填滿的情況,是不是可以考慮不要一下子寫這麼多資料,能否拆下資料(其實一下子寫大量資料本身就不合理哈)

另外,是否可以調高緩衝區大小呢?

這個其實是不行的哈,因為沒有可以設定的地方,目前服務端預設為每個客戶端輸入緩衝區分配的大小是 1GB。

那輪到第 2 個溢位場景:兩邊處理速度不一致。

正常來說,服務端不應該出現長時間阻塞,所以需要看看是什麼原因導致的阻塞,解決到就好了。

3. 客戶端輸出緩衝區

同輸入緩衝區,伺服器端也會給每個連線的客戶端都設定了一個輸出緩衝區。

3.1 作用

同上,也是暫存請求資料。

這個地方其實我在文章開頭說的,生產者不關心消費者什麼時候用,只負責把消費者之前請求的東西處理好就完事了。

可能有點抽象,我是這麼理解的,如果有不妥的地方可以留言糾正我一下

服務端一般都會和多個客戶端連線,加上 redis 網路通訊模組是單執行緒的(即使是新版本支援多執行緒也一樣)

假如沒有輸出緩衝區會發生什麼事呢?

服務端處理了很多客戶端 A 的請求,需要經過網路這一耗時操作,返回給客戶端 A。在這個過程中,客戶端 B 的請求一直得不到服務端處理和響應,這樣吞吐量就上不去了。

有了緩衝區之後,至少能解放服務端,讓它去處理客戶端 B 的請求。

3.2 溢位場景

這裡也是同輸入緩衝區,我就不囉嗦了,溢位的話服務端也會關閉客戶端連線。

  1. 伺服器端返回了大量資料,一下子填滿了
  2. 返回資料的速度太快,比如執行 MONITOR 命令,它會持續輸出監測到的各個命令操作
  3. 緩衝區大小設定得不合理。

3.3 優化

類似的,不要一下子讀大量資料;不持續線上上執行 MONITOR 命令。

而輸出緩衝區的大小是可以通過 client-output-buffer-limit 來設定的。

但是一般來說,我們都不用改,因為預設情況就夠了,這裡瞭解下就好。

值得說一點的是,Redis 釋出訂閱的訊息也是在該緩衝區中,可以用 client-output-buffer-limit pubsub 8mb 2mb 60 來限制大小。

  • pubsub 表示對訂閱客戶端進行設定。換成 normal 則表示當前設定的是普通客戶端
  • 整個配置的含義是:實際佔用的緩衝區大小要超過 8MB,或者連續 60 秒內對輸出緩衝區的寫入量超過 2MB 的話,服務端就會關閉客戶端連線。

4. 複製緩衝區

溫馨提示下,如果對 Redis 同步/複製不瞭解的讀者,比如不知道全量/增量複製,建議可以看下我這篇文章:一文讓你明白Redis主從同步

下面回到正題哈。

有複製肯定有主從,而主從間的資料複製包括全量複製和增量複製兩種。

全量複製是同步所有資料,而增量複製只會把主從庫網路斷連期間主庫收到的命令,同步給從庫。

4.1 作用

暫存資料。

主節點上會為每個從節點都維護一個複製緩衝區。

在全量複製時,主節點在向從節點傳輸 RDB 檔案的同時,會繼續接收客戶端傳送的寫命令請求,並儲存在複製緩衝區中,等 RDB 檔案傳輸完成後,再傳送給從節點去執行。

4.2 溢位場景

從節點接收和載入 RDB 較慢,同時主節點接收到了大量的寫命令,寫命令在複製緩衝區中就會越積越多,最後就會溢位。

一旦溢位,主節點會直接關閉和從節點進行復制操作的連線,導致全量複製失敗

4.3 優化

可以控制主節點資料量在 2~4GB(僅供參考),這樣可以讓全量同步執行得更快些,避免複製緩衝區累積過多命令

也可以調整緩衝區大小,還是之前的 client-output-buffer-limit 引數。

比如: config set client-output-buffer-limit slave 512mb 128mb 60

  • slave 參數列明該配置項是針對複製緩衝區的.
  • 整個配置的含義是:實際佔用的緩衝區大小要超過 512MB,或者連續 60 秒內對輸出緩衝區的寫入量超過 128MB 的話,服務端就會關閉同步連線。

5. 複製積壓緩衝區

這個是在新增複製用到的緩衝區。

具體介紹還是推薦看上面提到的文章哈,寫到這裡也 2k+ 字了,頂不住啦。

5.1 作用

暫存資料。

從節點意外斷開連線後重連,可從該緩衝區同步期間沒同步到的資料。

5.2 溢位場景

不會溢位。(想不到吧.jpg)

該緩衝區本質是一個固定長度,先進先出的佇列,預設 1MB。

所以當佇列被佔滿,不是報錯,也不像上面幾個緩衝區直接關閉連線。而是覆蓋最早進入佇列的資料。

因此,如果有從節點還沒有同步這些舊命令資料,就會導致主從節點重新進行全量複製,而不是增量複製。

PS:全量複製效能開銷遠大於增量複製

5.3 優化

調整複製積壓緩衝區的大小,引數是:repl_backlog_size

原創不易,如果覺得文章不錯,希望能關注下我

相關文章