Reids持久化和高可用
Redis持久化
- 持久化:將書籍從掉電易失的內存存放到能夠永久存儲的設備上
- Redis服務是使用內存來存儲數據,如果掉電、服務崩潰都會導致Redis中數據丟失,如有必要,可以持久化數據。
- Redis持久化方式:RDB(Redis DB)、AOF(AppendOnlyFile)
RDB
-
在默認情況下,Redis將某時間點的數據快照保存在名字爲dump.rdb的二進制文件中
-
策略
- 自動:按照配置文件中的條件滿足就執行BGSAVE
- 手動:客戶端發起SAVE、BGSAVE命令
-
配置
/etc/redis/redis.config
配置文件。注意這裏是我自己安裝時修改了配置文件路徑。具體配置文件請查找redis配置文件
save 900 1 #如果900秒內,有一次更新,或者增加過,會保持落地數據一次 save 300 10 # 如果在300秒內,有10次以上的改動,會自動保存落地數據一次 save 60 10000 # 如果在60秒有10000次改動,或10000次以上的改動,就自動保存落地數據一次 #數據文件名稱 dbfilename dump.rdb #數據文件存放目錄 dir /var/lib/redis/6379
-
save 60 1000,Redis要滿足在60秒內至少有1000個鍵被改動,會自動保存一次,只要滿足上面3個條件之一,就自動執行快照。
- 執行完成後,時間計數器和次數計數器都會歸零重新計數。這多個條件不是疊加效果
- SAVE命令:阻塞式命令,執行期間不響應客戶端請求
- BGSAVE:非阻塞命令,執行期間還可以接受並處理請求,會folk一個子進程創建RDB文件
127.0.0.1:6379> SAVE 127.0.0.1:6379> BGSAVE
-
優點
- 完全備份,不同時機的數據集備份可以做到多版本恢復
- 緊湊的單一文件,方便網絡傳輸,適合災難恢復
- 快照文件直接恢復,大數據集速度比AOF快些
-
缺點
- 會丟失最近寫入、修改的而未能持久化的數據
- folk過程較耗時,會造成毫秒級不能響應客戶端請求
-
RDB備份策略
- 創建一個定時任務cron job,每小時或者每天將dump.rdb複製到指定目錄
- 確保備份文件名稱帶有日期時間信息,便於管理和還原對應的時間點的快照版本
- 啓用定時任務刪除過期的備份
- 如果有必要,跨物理主機、跨機架、異地備份
AOF
- Append only file,採用追加的方式保存,默認文件appendonly.aof。
- AOF實質是記錄所有的寫操作命令,在服務啓動的時候使用這些命令就可以還原數據庫
AOF寫入機制
-
AOF方式不能保證絕對不丟失數據
-
目前常見的操作系統中,執行系統調用write函數,將一些內容寫入到某個文件裏面時,爲了提高效率,系統通常不會直接將內容寫入硬盤裏面,而是先將內容放入一個內存緩衝區(buffer)裏面,等到緩衝區被填滿,或者用戶執行fsync調用fdatasync調用時纔將存儲在緩衝區裏面的內容真正的寫入到硬盤裏,未寫入磁盤之前,數據可能會丟失
-
寫入磁盤的策略
-
appendfsync選項,這個選項的值可以是always、everysec或者no
- Always:服務器每寫入一個命令,就調用一次fdatasync,將緩衝區裏面的命令寫入到磁盤。這種模式下,服務器出現故障,也不會丟失任何已經成功執行的命令數據
- Everysec(默認): 服務器每一秒重調用一次fdatasync,將緩衝區裏面的命令寫入到磁盤。這種模式下,服務器出現故障,最多隻丟失一秒鐘內的執行的命令數據
- No:服務器不主動調用fdatasync,由操作系統決定何時將緩衝區裏面的命令寫入到磁盤。這種模式下,服務器遭遇意外停機時,丟失命令的數量是不確定的
-
運行速度:always的速度慢,everysec和no都很快
- AOF重寫機制
- 寫操作越來越多的被記錄,AOF文件會很大。Redis會合並寫操作,以壓縮AOF文件。合併重複的寫操作,AOF會使用盡可能少的命令來記錄。
- 重寫過程
- folk一個子進程負者重寫AOF文件
- 子進程會創建一個臨時文件寫入AOF信息
- 父進程會開闢一個內存緩衝區接受新的寫命令
- 子進程重寫完成後,父進程會獲得一個信號,將父進程接受到的新的寫操作由子進程寫入到臨時文件中
- 新文件替代舊文件
- 注意:如果寫入操作的時候出現故障導致命令寫半截,可以使用redis-check-aof工具修修復
- AOF文件重寫簡單模擬示例:
- AOF重寫觸發
- 手動:客戶端向服務器發送BGREWRITEAOF命令
- 自動:配置文件中的選項,自動執行BGREWRITEAOF命令
auto-aof-rewrite-min-size <size>
,觸發AOF重寫所需要的最小體積:只要在AOF文件的體積大於等於size時,纔會考慮是否需要進行AOF重寫,這個選項用於避免對體積過小的AOF文件進行重寫auto-aof-rewrite-percentage <percent>
,指定觸發重寫所需要的AOF文件體積百分比:當AOF文件的體積大於auto-aof-rewrite-min-size指定的體積,並且超過上一次重寫之後的AOF文件體積的percent%時,就會觸發AOF重寫。(如果服務器剛剛啓動不久,還沒有進行過AOF重寫,那麼使用服務器啓動時載入的AOF文件的體積類作爲基準值)。將這個值設置爲0表示關閉自動AOF重寫- 重寫配置舉例:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
當ADF文件大於64MB時候,可以考慮重寫AOF文件。
如果當AOF文件的增量相當於上一次重寫之後的體積size增大了100%以上時(自上次重寫後文件大小翻了一倍),啓動重寫,執行BGRWRITEAOF命令
appendonly yes
默認關閉,如需要AOF,使用yes開啓
- 優點
- 寫入機制,默認fysnc每秒執行,性能很好不阻塞服務,最多丟失一秒的數據
- 重寫機制,可以優化AOF文件體積
- 如果誤操作了(FLUSHALL等),只要AOF未被重寫,停止服務移除AOF文件尾部FLUSHALL命令,重啓Redis,可以將數據集恢復到FLUSHALL執行之前的狀態
- 缺點
- 相同數據集,AOF文件體積較RDB大了很多
- 恢復數據速度較RDB慢(文本文件,命令重演)
- 選擇
- 一般來講,選擇RDB。如果同時開啓,優先使用AOF,因爲它的數據更新
Redis集羣
- Redis集羣分爲:
- 主從複製Replication
- 高可用Sentinel
- 集羣Cluster
主從複製
-
典型的主從模型,主Redis服務稱爲Master,從Redis服務稱爲Slave。
-
一主可用多從。
-
Master會一直將自己的數據更新同步到Slave,以保持主從數據同步。
-
只有Master可用執行讀寫操作,Slave只能執行讀操作。客戶端可用鏈接到任一Slave執行讀操作,來降低Master的讀取壓力。
-
創建主從複製
-
命令創建
redis-server --slaveof <master-ip> <master-port>
- 配置當前服務稱爲某Redis服務的Slave
- redis-server --port 6380 --slaveof 127.0.0.1 6379
-
指令創建
- SLAVEOF host port命令,將當前服務器狀態從Master修改爲別的服務器的Slave
redis>SLAVEOF 192.168.1.1 6379 #將服務器轉換爲Slave redis>SLAVEOF NO ONE #將服務器重新恢復到Master,不會丟棄已同步數據
-
配置方式
- 啓動時,服務器讀取配置文件,並自動成爲指定服務器的從服務器
slaveof <masterip> <masterport>
- slaveof 127.0.0.1 6379
-
-
主從實驗
- Master 192.168.140.135 6379
- Slave 192.168.140.140 6379
# redis-cli -h 192.168.142.140 -p 6379 slave> Set testkey abc slave> KEYS * slave> SLAVEOF 192.168.142.135 6379 slave> KEYS * #看看是否反生改變 slave> set slavekey 123 (error) READONLY You can't write against a read only slave. master> SET masterkey 123 slave> GET masterkey slave> SLAVEOF NO ONE #解除從 slave> KEYS * slave> SET slavekey1 abc #發現可以寫了 slave> KEYS *
- 採用上面的多種方式都可以實現主從模式,一般來說,主從服務器都是固定的,採用配置文件方式。
-
主從複製問題
- 一個Master可以有多個Slaves。如果Slave下線,只是讀請求的處理能力下降。但Master下線,寫請求無法執行。
- 當Master下線,其中一臺Slave使用SLAVEOF no one命令成爲Master,其他Slave執行SLAVEOF命令指向這個新的Master,從它這裏同步數據。
- 這個主從轉移的過程手動的,如果要實現自動故障轉移,這就需要Sentinel哨兵,實現故障轉移Fallover操作
高可用Sentinel
- Redis官方的高可用方案,可用用它管理多個Redis服務實例。
- Redis Sentinel是一個分佈式系統,可以在一個架構中運行多個Sentinel進程
- 使用編譯時產生的redis-sentinel文件,在新的版本中,它就是redis-server的軟鏈接。
- Sentinel啓動會啓動一個運行在Sentinel模式下的Redis服務實例
- 推薦使用第一種
redis-sentinel /path/to/sentinel.conf
redis-server /path/to/sentinel.conf --sentinel
- Sentinel原理
- Sentinel會監控Master、Slave是否正常,可以監控多個Master、Slave。
- Sentinel網絡:監控同一個Master的Sentinel會自動連接,組成分佈式的Sentinel網絡,相互通信並交換監控信息。
- 服務器下線
- 當一個sentinel認爲被監視的服務器已經下線時,它會向網絡中的其他Sentinel進行確認,判斷該服務器是否真的已經下線。
- 如果下線的服務器爲主服務器,那麼sentinel網絡將對下線主服務器進行自動故障轉移,通過將下線服務器的某個服務器提升爲新的主服務器,並讓其從服務器轉爲複製新的主服務器,以此來讓系統重新回到上線的狀態。
- 如果原來的組服務器恢復,只能成爲一臺Slave服務器。
-
主觀下線sdown:單個Sentinel認爲服務器下線
-
客觀下線odown:多個Sentinel通信後做出了服務器下線的判斷
-
Sentinel網絡模型:
-
配置
- 至少包含一個監控配置選項,用於指定被監控Master的相關信息
Sentinel monitor <name><ip><port><quorum>
,例如sentinel monitor mymaster 127.0.0.1 6379 2
監視mymaster主服務器,服務器ip和端口,將這個主服務器判斷未下線失效至少需要2個Sentinel同意,如果多數Sentinel同意纔會執行故障轉移 - Sentinel會根據Master的配置自動發現Master的Slaves
-
sentinel down-after-milliseconds mymaster 60000
認爲服務器下線的毫秒數。Sentinel在指定的毫秒數內沒有返回給Sentinel的Ping回覆,視爲主觀下線Sdown。 -
sentinel failover-timeout mymaster 180000
若sentinel在該配置值內未能完成failover操作(即故障時主從自動切換),則認爲本次failover失敗 -
sentinel parallel-syncs mymaster 1
在執行故障轉移時,最多可以有多少個服務器同時對新的主服務器進行同步。1表示只能有1臺從服務器從新主服務器同步數據,以便其他從服務器繼續提供客戶端服務的響應。 -
port 26379
Sentinel默認端口號爲26379
Sentinel實驗
- Master 192.168.140.135 6379
- slave 192.168.140.140 6379
- 先啓動主從2個Redis服務
- 提供Sentinel配置文件
sentinel1.conf文件內容如下
port 26379
sentinel monitor s1 192.168.142.135 6379 1
sentinel down-after-milliseconds s1 6000
sentinel failover-timeout s1 10000
sentinel parallel-syncs s1 1
-
啓動Sentinel
redis-sentinel sentinel.conf
-
從服務器的配置中增加
slaveof 192.168.142.135 6379
,並重啓該服務
-
模擬Master下線
# ps aux | grep redis-server
root 4588 0.1 0.9 38736 9752 ? Ssl 14:44 0:34 /magedu/redis/bin/redis-server 192.168.142.135:6379
root 4754 0.0 0.0 103244 852 pts/2 S+ 20:23 0:00 grep redis-server
# kill -9 4588
- Master下線後,開始投票,決議通過後,提升爲新主
- Master再次上線
- 原來的主上線後,被迫轉換爲從。
Redis Cluster分佈式集羣
- 從3.0開始,Redis支持分佈式集羣
- Redis集羣採用無中心節點設計,每一個Redis節點互相通信。
- 客戶端可用鏈接任意一個集羣的節點。
- Redis集羣節點複製
- redis集羣的每個結點都有兩種角色可選:主節點master node、從節點slave node。其中主節點用於存儲數據,而從節點則是某個主節點的複製品
- 當用戶需要處理更多讀請求的時候,添加從節點可以擴展系統的讀性能,因爲Redis集羣重用了單機Redis複製特性的代碼,所以集羣的複製行爲和我們之前介紹的單機複製特性的行爲是完全一樣的
- Redis集羣故障轉移
- Redis集羣的主節點內置了類似Redis Sentinel的結點故障轉移能力,當集羣中的某個主節點下線時,集羣中的其他在線主節點會注意到這一點,並對已下線的主節點進行故障轉移
- 集羣進行故障轉移的方法和Redis Sentinel進行故障轉移的方法基本一樣,不同的是,在集羣裏面,故障轉移是由集羣中其他在線的主節點負責進行的,所以集羣不必另外使用Redis Sentinel
- Redis集羣分片
- 集羣將整個數據庫分爲16384個槽位slot,所有key的數據都是這些slot中的一個,key的槽位計算公式爲:
slot_number = crc16(key)%16384
,其中crc16爲16位的循環冗餘效驗和函數 - 集羣中的每個主節點都可以處理0個至16383個槽位的訪問請求,當16384個槽都有某個節點在負責處理時,集羣進入上線狀態,並開始處理客戶端發送的數據命令請求
- 舉例
- 三個主節點7000、7001、7002平均分配16384個slot槽位
- 節點7000指派的槽位爲0到5460
- 節點7001指派的槽位爲5461到10922
- 節點7002指派的槽位爲10923到16383
- Redis集羣Redirect轉向
- 由於Redis集羣無中心節點,請求會發給任意主節點
- 主節點只會處理自己負者槽位的命令請求,其他槽位的命令請求,該主節點會返回客戶端一個轉向錯誤。
- 客戶端會根據錯誤中包含的地址和端口,重新向正確的負責的主節點發起命令請求
- Redis集羣總結
- Redis集羣是一個由多個節點組成的分佈式服務集羣,它具有複製、高可用和分片特性
- Redis的集羣沒有中心節點,並且帶有複製和故障轉移特性,這可用避免單個結點成爲性能瓶頸,或者因爲某個結點下線而導致整個集羣下線
- 集羣中的主節點負者處理槽(存儲數據),而從節點則是主節點的複製品
- Redis集羣將整個數據庫分爲16384個槽,數據庫中的每個鍵都屬於16384個槽中的其中一個
- 集羣中的每個主節點都可以管理槽,當16384個槽都有結點在負責時,集羣進入上線狀態,可以執行客戶端發送的數據命令
- 主節點只會執行和自己負責的槽有關的命令,當節點接受到不屬於自己處理的槽的命令時,它將會把處理指定槽位的結點的地址返回給客戶端,而客戶端會向正確的結點重新發送