簡介
當數據量增大或者讀寫請求增多后,一台 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