Redis 實戰 —— 07. 複製、處理故障、事務及性能優化

複製簡介 P61

關係型數據庫一般會使用一個主服務器 (master) 向多個從服務器 (slave) 發送更新,並使用從服務器來處理全部讀請求。 Redis 也採用了一樣的方法實現本身的複製特性,並將其用做擴展性能的一種手段。 P69node

在接收到主服務器發送的數據初始副本 (initial copy of the data) 以後,客戶端每次向主服務器進行寫入時,從服務器都會實時地獲得更新。 P69git

複製 P62

對於一個正在運行的 Redis 服務器,用戶能夠經過發送 SLAVEOF NO ONE 命令來讓服務器終止複製操做,再也不接受主服務器的數據更新;也能夠經過發送 SLAVEOF host port 命令來讓服務器開始複製一個新的主服務器。 P69github

配置選項
# 設置本機爲指定服務器的從服務器
#
# slaveof <master-host> <master-port>

# 當主服務器設置了密碼保護時(用 requirepass 指定的密碼)
# 從服務器服務鏈接主服務器須要設置相應的密碼
#
# masterauth <master-password>


# 當從服務器 與主服務器失去鏈接 或者 正在進行復制 時
# yes: 從服務器會繼續響應客戶端的請求(默認 yes)
# no: 除了 INFO 和 SLAVOF 命令以外的任何請求都會
#     返回一個錯誤 "SYNC with master in progress"
#
slave-serve-stale-data yes

# 從服務器每隔必定時間會向主服務器發送 ping
# 默認 10 秒
#
# repl-ping-slave-period 10

# ping 回覆 或 主服務器批量數據傳輸 超時時長
# 默認 60 秒
# 確保 repl-timeout 大於 repl-ping-slave-period
#
# repl-timeout 60
從服務器鏈接主服務器時的步驟 P70
步驟 主服務器操做 從服務器操做
1 (等待命令進入) 鏈接(或者重連)主服務器,發送 SYNC 命令
2 開始執行 BGSAVE ,並使用緩衝區記錄 BGSAVE 以後執行全部寫命令 根據配置選項 (slave-serve-stale-data) 來決定是繼續使用現有的數據(若是有的話)來處理客戶端的命令請求,仍是向客戶端返回錯誤
3 BGSAVE 執行完畢,向從服務器發送快照文件,並在發送期間繼續使用緩衝區記錄被執行的寫命令 丟棄全部舊數據(若是有的話),開始載入主服務器發來的快照文件
4 快照文件發送完畢,開始向從服務器發送存儲在緩衝區裏面的寫命令 完成對快照文件的解釋操做,像往常同樣開始接受命令請求
5 緩衝區存儲的寫命令發送完畢;從如今開始,每執行一個寫命令,就向從服務器發送相同的寫命令 執行主服務器發來的全部存儲在緩衝區裏面的寫命令;並從如今開始,接受並執行主服務器傳來的每一個寫命令

在實際中最好讓主服務器只使用 50% ~ 65% 的內存,留下 30% ~ 45% 的內存用於執行 BGSAVE 命令和建立記錄寫命令的緩衝區。 P70redis

從服務器在進行同步時,會清空本身的全部數據。 P70數據庫

Redis 不支持主主複製 (master-master replication) P71性能優化

當一個從服務器鏈接一個已有的主服務器時,有時能夠重用已有的快照文件: P71服務器

  • 步驟 3 還沒有執行:全部從服務器都會接收到相同的快照文件和相同的緩衝區寫命令
  • 步驟 3 正在執行或已經執行完畢:當主服務器與比較早進行鏈接的從服務器執行完複製所需的 5 個步驟以後,主服務器會與新鏈接的從服務器執行一次新的步驟 1 至步驟 5
主從鏈 P71

Redis 的主服務器和從服務器沒有什麼特別不一樣的地方,因此從服務器也能夠擁有本身的從服務器,並由此造成主從鏈 (master/slave chaining) 。 P71網絡

不過,若是從服務器 X 擁有從服務器 Y ,那麼當從服務器 X 在執行步驟 4 時,它將斷開與從服務器 Y 的鏈接,致使從服務器 Y 須要從新鏈接並從新同步。 P71數據結構

當讀請求比寫請求重要,且讀請求的數量遠遠超過一臺 Redis 服務器能夠處理的範圍時,就須要添加新的從服務器來處理讀請求。隨着負載不斷上升,主服務器可能會沒法快速地更新全部從服務器,或者由於從新鏈接和從新同步從服務器而致使系統超載。爲了緩解這個問題,能夠建立一個由 Redis 主從節點 (master/slave node) 組成的中間層來分擔主服務器的複製工做。 P71 併發

經過同時使用複製和 AOF 持久化,用戶能夠加強 Redis 對於系統崩潰的抵抗能力。 P73

處理系統故障

驗證快照文件和 AOF 文件

redis-check-aof [--fix] <file.aof> 能夠檢查 AOF 文件,而且能夠進行修復:將第一個出錯命令(大部分狀況下在文件末尾)及以後的全部命令刪除。 P74

redis-check-dump <dump.rdb> 能夠檢查快照文件。快照文件目前沒法進行修復,由於快照文件自己進行了壓縮。 P74

事務

Redis 事務的做用: P76

  • 防止數據出錯
  • 在某些狀況下提高性能。利用事務一次性發送多個命令,而後等待全部回覆出現實現流水線 (pipeline)。經過減小客戶端與 Redis 服務器之間的網絡通訊次數來提高 Redis 在執行多個命令時的性能。

關係數據庫事務與 Redis 事務的區別: P76

  • 關係數據庫:先向數據庫服務器發送 BEGIN ,而後執行各個相互一致 (consistent) 的讀寫操做,最後能夠選擇發送 COMMIT 來確認以前的修改,或者發送 ROLLBACK 來放棄以前的修改。
  • Redis :以特殊命令 MULTI 開始,而後傳入多個命令,最後以 EXEC 結束,並依次執行傳入的命令。Redis 事務不能以一致的形式讀取數據,使得某一類型的問題難以解決,且沒法實現二階段提交。

經過使用 WATCH, MULTI/EXEC, UNWATCH/DISCARD 等命令,程序能夠在執行某些重要操做時,經過確保本身正在使用的數據沒有發生變化來避免出錯。 P78

  • WATCH: 使用 WATCh 對鍵進行監視以後,直到用戶執行 EXEC 的這段時間裏面,若是有其餘客戶端搶先對任何被監視的鍵進行了替換、更新或刪除等操做,那麼當用戶嘗試執行 EXEC 時,事務將失敗並返回一個錯誤。(以後用戶可選擇重試事務或者放棄事務)
  • UNWATCH: 能夠在 WATCH 執行以後、 MULTI 執行以前對鏈接進行重置 (reset)
  • DISCARD: 能夠在 MULTI 執行以後、 EXEC 執行以前對鏈接進行重置,即取消 WATCH 並清空全部已入隊命令

爲何 Redis 沒有實現典型的加鎖功能? P82

  • 加鎖是悲觀鎖,持有鎖的客戶端運行越慢,等待解鎖的客戶端被阻塞的時間越長
  • WATCH 是樂觀鎖,客戶端沒必要等待取得鎖,只須要在事務執行失敗時重試便可,樂觀鎖能夠提升併發能力

非事務型流水線 (non-transactional pipeline)

對於無需事務的大量操做可使用非事務型流水線,能夠避免事務消耗資源。

Python 中經過修改入參便可將事務改成非事務型流水線,而 Go 中根據具體框架的不一樣,可能須要手動封裝流水線的處理邏輯。

性能優化

要對 Redis 的性能進行優化,首先須要弄清楚各類類型的 Redis 命令能跑多塊,而這一點能夠經過調用 Redis 附帶的性能測試程序 redis-benchmark 得知。 P85

切記不要將輸出結果看做是應用程序的實際性能,由於 redis-benchmark 不會處理執行命令所得到的命令回覆,因此它節約了大量用於對命令回覆進行語法分析的時間。 P86

可能影響性能的緣由 P86
  • 未使用流水線:可視狀況適當使用流水線
  • 對於每一個命令或每組命令都建立了新的鏈接:使用鏈接池重用 Redis 鏈接
  • Redis 的數據結構或命令不合理(value 很是大,使用 keys, hgetall 等):優化數據結構和命令
本文首發於公衆號:滿賦諸機( 點擊查看原文) 開源在 GitHub : reading-notes/redis-in-action
相關文章
相關標籤/搜索