Redis 實戰 —— 13. 擴充套件 Redis

滿賦諸機發表於2021-02-02

簡介

當資料量增大或者讀寫請求增多後,一臺 Redis 伺服器可能沒辦法再儲存所有資料或者處理所有讀寫請求,那麼就需要對 Redis 進行擴充套件,保證 Redis 在能儲存所有資料對情況下,同時能正常處理讀寫請求。 P227

擴充套件讀效能 P227

提高效能的幾個途徑 P228
  • 使用短結構:確保壓縮列表的最大長度不會太大
  • 根據查詢型別選擇結構
    • 不要把列表當作集合使用
    • 不要獲取整個雜湊,然後再客戶端裡面進行排序,而應使用有序集合
  • 大體積物件儲存前進行壓縮:減少讀寫所需的網路頻寬。對比 lz4, gzip 和 bzip2 等壓縮演算法,選擇對儲存資料壓縮效果和效能最好對壓縮演算法
  • 流水線和連線池:複製、處理故障、事務及效能優化 中介紹過流水線

擴充套件讀效能最簡單的方法就是新增只讀伺服器(複製、處理故障、事務及效能優化 中介紹過通過複製 (replication) 讓一個 Redis 伺服器成為從伺服器及運作原理和管理方法),並只對主伺服器進行寫入(預設情況下,嘗試對一個從伺服器進行寫入將引發一個錯誤,即使它是其他從伺服器的主伺服器)。 P228

新增從伺服器 P228
  • 在配置檔案中加上: slaveof <master-host> <master-port>
  • 向正在執行對 Redis 伺服器傳送: SLAVEOF <master-host> <master-port>

可以通向從伺服器傳送 SLAVEOF NO ONE 命令讓其與主伺服器斷開。 P228

當一個主伺服器有大量從伺服器時,那麼它們以前同步時就會耗盡大部分頻寬,導致主伺服器延遲變高,甚至導致主伺服器斷開和從伺服器的連線。 P229

解決從伺服器重同步 (resync) 問題的方法 P229

  • 構建樹狀的從伺服器群組:通過構建二級從伺服器降低主伺服器需要傳遞給從伺服器的資料量
  • 對網路連線進行壓縮:使用帶壓縮帶 SSH 隧道 (tunnel) 進行連線可以明顯地降低頻寬(注意使用 SSH 提供的選項讓 SSH 連線在斷線後自動連線)
故障轉移 P230

Redis Sentinel 可以配合 Redis 的複製功能使用,並對下線的主伺服器進行故障轉移。 Redis Sentinel 是執行在特殊模式下的 Redis 伺服器,它會監視一系列主伺服器以及它們的從伺服器,通過向主伺服器傳送 PUBLISH 命令和 SUBSCRIBE 命令,並向主伺服器和從伺服器傳送 PING 命令,各個 Sentinel 程式可以自主識別可用的從伺服器和其他 Sentinel 。當主伺服器失效時,監視這個主伺服器的所有 Sentinel 就會基於彼此共有的資訊選出一個 Sentinel ,並從現有的從伺服器中選擇一個新的主伺服器。然後被選中的 Sentinel 就會讓剩餘的其他從伺服器去複製這個新的主伺服器(預設設定下, Sentinel 會一個接一個地遷移從伺服器,但這個數量可以通過配置選項進行修改)。 P230

Redis Sentinel 還提供了可選的故障轉移通知功能,這個功能可以通過呼叫使用者提供的指令碼來執行配置更新等操作。 P230

擴充套件寫效能和記憶體容量 P230

降低記憶體佔用,減少需寫入的資料 P231
  • 減少程式需要讀取的資料量
  • 無關功能遷移至其他伺服器
  • 寫入 Redis 前,嘗試記憶體中進行聚合(可以應用於分析和統計計算)
  • 使用鎖或者 Lua 指令碼代替 WATCH/MULTI/EXEC 事務
  • 使用 AOF 持久化會將寫入的所有資料儲存起來,可以考慮配置重寫 AOF 或使用 RDB

當使用上述方法無法繼續降低記憶體並提升效能之後,就說明已經遇到了只使用一臺機器帶來的瓶頸,那麼就需要將資料分片到多臺機器上面。我們介紹使用固定分片數量的方法,使得分片方案能夠滿足未來幾年的預期,假設分片為 256 片。那麼前期在資料量非常小的情況下沒必要每個 Redis 伺服器都使用獨立的機器,可以多個 Redis 伺服器共用一臺機器,或者每個 Redis 伺服器使用多個 Redis 資料庫。 (注意:每臺機器上執行多個 Redis 伺服器時,確保監聽不同的埠,並確保伺服器寫入的都是不同的快照檔案/ AOF 檔案。)P231

分片方法可以直接採用 降低記憶體佔用 中提到的先使用雜湊函式計算出一個數字雜湊值,然後使用分片數量計算出當前採用哪個連線即可,即不再對 key 進行分片,而是轉換為對連線進行分片。 P234

如果執行復雜查詢時,感覺效能受到了 Redis 單執行緒設計的限制,並且機器有更多的計算核心、更多的通訊網路資源,以及更多用於儲存快照檔案和 AOF 檔案的磁碟 I/O ,那麼可以考慮在單臺機器上面執行多個 Redis 伺服器。(當然也需要注意:確保一臺機器上的多個 Redis 伺服器監聽不同的埠,並確保伺服器寫入的都是不同的快照檔案/ AOF 檔案。) P234

所思

如果網路 I/O 成為瓶頸的話,那麼也可以考慮 Redis 6.0 的多執行緒特性。多執行緒特性主要是改進讀寫緩衝區的效能,因為這部分時間佔比較大,而命令執行部分仍然使用單執行緒處理。這樣既能提高整體效能,又可以保持設計簡單,也不會引入新的併發問題。

對於一些全域性唯一的資料,例如:唯一訪問計數器等,可以額外使用一個連線專門儲存類似的資料。

擴充套件複雜查詢 P234
擴充套件搜尋查詢量 P235

實現內容搜尋、定向廣告和職位搜尋 中提到的各種搜尋方法都使用了類似 SUNIONSTORE, SINTERSTORE, SDIFFSTORE, ZINTERSTORE, ZUNIONSTORE 等命令,而這些命令都需要對 Redis 進行寫入,所以前面介紹的只讀從伺服器將無法處理這些搜尋。 P235

為了執行上述搜尋,需要開啟對從伺服器對寫入功能。 Redis 對配置檔案中, slave-read-only 選項控制能否對從伺服器進行寫入,預設值為 yes 。所以只要將 slave-read-only 設定為 no 並重啟從伺服器,上述搜尋即可正常執行。 P235

當機器擁有足夠多的記憶體,並且它執行的都是隻讀操作(或者說這些操作不會修改其他查詢所使用的底層資料)的時候,新增從伺服器能夠幫助我們實現橫向擴充套件 (scale out) 。

擴充套件搜尋索引大小 P235

為了對搜尋查詢進行連線分片,我們必須先對搜尋索引進行連線分片,確保對於每個被索引的文件來說,同一個文件的所有資料都會被儲存到同一個連線分片裡面。 P236

分片搜尋實際流程大致分為以下三個操作:

  • 編寫能夠在單個分片上面執行對查詢程式,讓它進行搜尋並獲取待排序對搜尋結果
  • 在所有分片執行上面提到的查詢程式
  • 對各個分片對查詢結果進行合併,然後選出想要的那部分結果

注意:由於無法確定分頁結果中的每條資料分別來自哪個分片,所以為了確保返回的資料在 [start, start + num] 內,程式需要從每個分片獲取 [0, start + num] 內的資料,然後在記憶體中選出最終結果。 P236

所思

分片其實也就兩種形式:

  • 對鍵進行分片:適用於大量類似鍵,但每個鍵對應的資料量不大的情況
  • 對資料進行分片:適用於每個鍵對應對資料量很大的情況

對鍵進行分片基本和連線分片繫結了,因為大量鍵只有在多連線對情況下分片才有用;而對資料進行分片既可以在單個連線中變成多個鍵,也可以轉化成連線分片。

本文首發於公眾號:滿賦諸機(點選檢視原文) 開源在 GitHub :reading-notes/redis-in-action

相關文章