redis(2)
二、redis持久化
Redis 雖然是一個內存級別的緩存程序,也就是redis 是使用內存進行數據的緩存的,但是其可以將內存的數據按照一定的策略保存到硬盤上,從而實現數據持久保存的目的,目前redis支持兩種不同方式的數據持久化保存機制,分別是RDB和AOF。
2.1:RDB模式
RDB(Redis DataBase):基于時間的快照,其默認只保留當前最新的一次快照,特點是執行速度比較快,缺點是可能會丟失從上次快照到當前時間點之間未做快照的數據。

RDB實現的具體過程Redis從主進程先fork出一個子進程,使用寫時復制機制,子進程將內存的數據保存為一個臨時文件,比如dump.rdb.temp,當數據保存完成之后再將上一次保存的RDB文件替換掉,然后關閉子進程,這樣可以保存每一次做RDB快照的時候保存的數據都是完整的,因為直接替換RDB文件的時候可能會出現突然斷電等問題而導致RDB文件還沒有保存完整就突然關機停止保存而導致數據丟失的情況,可以手動將每次生成的RDB文件進程備份,這樣可以最大化保存歷史數據。

2.1.1:RDB文件的保存與加載
有兩個 Redis 命令可以用于生成 RDB 文件,一個是 SAVE,另一個是 BGSAVE
SAVE 命令會阻塞 Redis 服務器進程,直到 RDB 文件創建完畢為止,在服務器進程阻塞期間,服務器不能處理任何命令請求,BGSAVE 命令會派生出一個子進程,然后由子進程負責創建 RDB 文件,父進程繼續處理命令請求。
RDB 文件的載入工作是在服務啟動時自動執行的,所以 Redis 并沒有專門用于載入 RDB 文件的命令,只要 Redis 服務器在啟動時檢測到 RDB 文件存在(放入配置文件指定的目錄),它就會自動載入 RDB 文件。
2.1.2:RDB模式的優缺點
優點: RDB快照保存了某個時間點的數據,可以通過腳本執行bgsave(非阻塞)或者save(阻塞)命令自定義時間點備份,可以保留多個備份,當出現問題可以恢復到不同時間點的版本。 可以最大化IO 的性能,因為父進程在保存RDB 文件的時候唯一要做的是fork出一個子進程,然后的-操作都會有這個子進程操作,父進程無需任何的IO操作RDB在大量數據比如幾個G的數據,恢復的速度比AOF的快。
缺點: 不能實時的保存數據,會丟失自上一次執行RDB備份到當前的內存數據,數據量非常大的時候,從父進程fork的時候需要一點時間,可能是毫秒或者秒或者分鐘,取決于磁盤IO性能。
2.2:AOF模式
AOF:按照操作順序依次將操作添加到指定的日志文件當中,特點是數據安全性相對較高,缺點是即使有些操作是重復的也會全部記錄。
AOF和RDB一樣使用了寫時復制機制,AOF默認為每秒鐘fsync一次,即將執行的命令保存到AOF文件當中,這樣即使redis服務器發生故障的話頂多也就丟失1秒鐘之內的數據,也可以設置不同的fsync策略,或者設置每次執行命令的時候執行fsync,fsync會在后臺執行線程,所以主線程可以繼續處理用戶的正常請求而不受到寫入AOF文件的IO影響。AOF文件是一個進行追加操作的日志文件(append only log),即操作的命令都會被追加到文件的末尾,如果因為磁盤滿、突然停機等問題導致寫入了不完整的命令,可以通過redis自帶的命令redis-check-aof命令輕易的修復AOF文件。
redis-check-aof /app/redis/appendonly.aof
AOF模式優缺點
AOF的文件大小要大于RDB格式的文件。
根據所使用的fsync策略(fsync是同步內存中redis所有已經修改的文件到存儲設備),默認是appendfsync everysec即每秒執行一次fsync。
redis可以在AOF文件變得過大的時候自帶在后臺對文件進行重寫,重寫后的新APF文件保存了恢復的時候需要的最新數據和最小的命令集合,這個操作是絕對安全的,因為redis 在創建新AOF文件的過程中會繼續將命令追加到之前的AOF文件,這樣即使服務器宕機也不會影響到當前redis 使用的AOF文件,而一旦新的AOF文件創建完成,redis就會從舊AOF文件切換到新的AOF文件,并將命令追加到新的AOF文件。
AOF文件按照命令的執行順序保存了對redis 的所以操作,使用的是redis協議,因此可以對AOF文件進行讀取和分析,也可以導出,假如不小心執行了一個FLUSHALL命令,但是只要AOF文件還沒有被重寫可以立即停止服務器,然后刪除AOF文件末尾的FLUSHALL命令并重啟redis,即將可以將數恢復到FLUSHALL命令之前的數據狀態。

2.3:redis常用命令
2.3.1:CONFIG
config 命令用于查看當前redis配置、以及不重啟更改redis配置等
127.0.0.1:6379> CONFIG get maxmemory #更改最大內存 1) "maxmemory" 2) "0" 127.0.0.1:6379> CONFIG set maxmemory 8589934592 OK 127.0.0.1:6379> 127.0.0.1:6379> 127.0.0.1:6379> 127.0.0.1:6379> CONFIG get maxmemory 1) "maxmemory" 2) "8589934592" 127.0.0.1:6379> CONFIG SET requirepass 123456 #設置連接密碼 OK 127.0.0.1:6379> CONFIG get requirepass (error) NOAUTH Authentication required. 127.0.0.1:6379> auth 123456 OK 127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "123456" 127.0.0.1:6379> config get * #獲取當前配置 1) "dbfilename" 2) "dump.rdb" 3) "requirepass" 4) "123456" 5) "masterauth" 6) "" 7) "cluster-announce-ip" 8) "" 9) "unixsocket" 10) "" 127.0.0.1:6379> info #顯示當前節點redis運行狀態信息 # Server redis_version:4.0.14 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:385503b4d6b148b0 redis_mode:standalone os:Linux 3.10.0-862.el7.x86_64 x86_64 arch_bits:64 127.0.0.1:6379> keys * #查看當前庫下的所有key 1) "key-2996" 2) "key-5127" 3) "key-115" 4) "key-2154" 127.0.0.1:6379> bgsave #手動在后臺執行RDB持久化操作 Background saving started 127.0.0.1:6379> DBSIZE #返回當前庫下的所有key 數量 (integer) 7616 FLUSHDB #強制清空當前庫中的所有key FLUSHALL #強制清空當前redis服務器所有數據庫中的所有key,即刪除所有數據 127.0.0.1:6379> select 1 #切換數據庫,等于MySQL的use DBNAME指令。 OK
三、redis 高可用與集群
3.1:配置reids 主從
主備模式,可以實現Redis數據的跨主機備份。
程序端連接到高可用負載的VIP,然后連接到負載服務器設置的Redis后端real server,此模式不需要在程序里面配置Redis服務器的真實IP地址,當后期Redis服務器IP地址發生變更只需要更改redis 相應的后端real server即可,可避免更改程序中的IP地址設置。
3.1.1:Slave主要配置
Redis Slave 也要開啟持久化并設置和master同樣的連接密碼,因為后期slave會有提升為master的可能,Slave端切換master同步后,其他slave會丟失之前的所有數據。
一旦某個Slave成為一個master的slave,Redis Slave服務會清空當前redis服務器上的所有數據并將master的數據導入到自己的內存,但是斷開同步關系后不會刪除當前已經同步過的數據。
3.1.1.1:修改配置文件
當前狀態為master,需要轉換為slave角色并指向master服務器的IP+PORT+Password
slaveof 192.168.235.145 6379 masterauth 123456 ##master如果密碼需要設置
3.1.1.2:master和slave 狀態
master節點:

master日志:

當前slave狀態:

slave節點日志

測試:
在master上添加一個key ,觀察slave節點是否同步到。
master節點:

slave節點

3.1.1.3:主從復制過程
Redis支持主從復制分為全量同步和增量同步,首次同步是全量同步,主從同步可以讓從服務器從主服務器備份數據,而且從服務器還可與有從服務器,即另外一臺redis服務器可以從一臺從服務器進行數據同步,redis 的主從同步是非阻塞的,master收到從服務器的sync(2.8版本之前是PSYNC)命令會fork一個子進程在后臺執行bgsave命
令,并將新寫入的數據寫入到一個緩沖區里面,bgsave執行完成之后并生成的將RDB文件發送給客戶端,客戶端將收到后的RDB文件載入自己的內存,然后redis master再將緩沖區的內容在全部發送給redis slave,之后的同步slave服務器會發送一個offset的位置(等同于MySQL的binlog的位置)給主服務器,主服務器檢查后位置沒有錯誤將此位置之后的數據包括寫在緩沖區的積壓數據發送給redis從服務器,從服務器將主服務器發送的擠壓數據寫入內存,這樣一次完整的數據同步,再之后再同步的時候從服務器只要發送當前的offset位 置給主服務器,然后主服務器根據相應的位置將之后的數據發送給從服務器保存到其內存即可。

3.2:redis 集群
上一個步驟的主從架構無法實現master和slave角色的自動切換,即當master出現redis服務異常、主機斷電、磁盤損壞等問題導致master無法使用,而redis高可用無法實現自故障轉移(將slave提升為master),需要手動改環境配置才能切換到slave redis服務器,另外也無法橫向擴展Redis服務的并行寫入性能,當單臺Redis服務器性能無法滿足業務寫入需求的時候就必須需要一種方式解決以上的兩個核心問題,即:1.master和slave角色的無縫切換,讓業務無感知從而不影響業務使用 2.可以橫向動態擴展Redis服務器,從而實現多臺服務器并行寫入以實現更高并發的目的。
3.2.1:Sentinel(哨兵):
Sentinel 進程是用于監控redis集群中Master主服務器工作的狀態,在Master主服務器發生故障的時候,可以實現Master和Slave服務器的切換,保證系統的高可用,其已經被集成在redis2.6+的版本中,Redis的哨兵模式到了2.8版本之后就穩定了下來。一般在生產環境也建議使用Redis的2.8版本的以后版本。哨兵(Sentinel) 是一個分布式系統,可以在一個架構中運行多個哨兵(sentinel) 進程,這些進程使用流言協議(gossip protocols)來接收關于Master主服務器是否下線的信息,并使用投票協議(Agreement Protocols)來決定是否執行自動故障遷移,以及選擇哪個Slave作為新的Master。每個哨兵(Sentinel)進程會向其它哨兵(Sentinel)、Master、Slave定時發送消息,以確認對方是否”活”著,如果發現對方在指定配置時間(可配置的)內未得到回應,則暫時認為對方已掉線,也就是所謂的”主觀認為宕機” ,主觀是每個成員都具有的獨自的而且可能相同也可能不同的意識,英文名稱:Subjective Down,簡稱SDOWN。有主觀宕機,肯定就有客觀宕機。當“哨兵群”中的多數Sentinel進程在對Master主服務器做出SDOWN 的判斷,并且通過 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下線判斷,這種方式就是“客觀宕機”,客觀是不依賴于某種意識而已經實際存在的一切事物,英文名稱是:ObjectivelyDown, 簡稱 ODOWN。通過一定的vote算法,從剩下的slave從服務器節點中,選一臺提升為Master服務器節點,然后自動修改相關配置,并開啟故障轉移(failover)。
Sentinel 機制可以解決master和slave角色的切換問題。
3.2.1.1:手動配置master
需要手動先指定某一臺Redis服務器為master,然后將其他slave服務器使用命令配置為master服務器的slave,哨兵的前提是已經手動實現了一個redis master-slave的運行環境。
實現一個一主兩從基于哨兵的高可用redis架構。
在主從基礎之上添加一臺虛擬機
master節點:

應用程序如何連接redis
Redis 官方客戶端:https://redis.io/clients
Redis為了保障高可用,服務一般都是Sentinel部署方式,當Redis服務中的主服務掛掉之后,會仲裁出另外一臺Slaves服務充當Master。這個時候,我們的應用即使使用了Jedis 連接池,Master服務掛了,我們的應用將還是無法連接新的Master服務,為了解決這個問題, Jedis也提供了相應的Sentinel實現,能夠在Redis Sentinel主從切換時候,通知我們的應用,把我們的應用連接到新的Master服務。
Redis Sentinel的使用也是十分簡單的,只是在JedisPool中添加了Sentinel和MasterName參數,JRedis Sentinel底層基于Redis訂閱實現Redis主從服務的切換通知,當Redis發生主從切換時,Sentinel會發送通知主動通知Redis進行連接的切換,JedisSentinelPool在每次從連接池中獲取鏈接對象的時候,都要對連接對象進行檢測,如果此鏈接和Sentinel的Master服務連接參數不一致,則會關閉此連接,重新獲取新的Jedis連接對象。
3.2.1.2:編輯配置文件sentinel.conf
Server1 配置,其他兩個server配置一樣
bind 0.0.0.0 port 26379 daemonize yes pidfile "redis-sentinel.pid" logfile "sentinel_26379.log" dir "/app/redis/logs" sentinel monitor mymaster 192.168.235.145 6379 2 #法定人數限制(quorum),即有幾個slave認為master down了就進行故障轉移 sentinel auth-pass mymaster 123456 sentinel down-after-milliseconds mymaster 30000 #(SDOWN)主觀下線的時間 sentinel parallel-syncs mymaster 1 #發生故障轉移時候同時向新master同步數據的slave數量,數字越小總 同步時間越長 sentinel failover-timeout mymaster 180000 #所有slaves指向新的master所需的超時時間 sentinel deny-scripts-reconfig yes #禁止修改腳本
3.2.1.3:啟動哨兵
三臺哨兵都要啟動
redis-sentinel /app/redis/etc/sentinel.conf redis-sentinel /app/redis/etc/sentinel.conf redis-sentinel /app/redis/etc/sentinel.conf
端口驗證:

哨兵日志:

當前redis master狀態
127.0.0.1:6379> info Replication # Replication role:master connected_slaves:2 slave0:ip=192.168.235.144,port=6379,state=online,offset=202315,lag=1 slave1:ip=192.168.235.143,port=6379,state=online,offset=202605,lag=0 master_replid:05d221bf791e79cf89a95fc9a5e07a2008e52ed1 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:202750 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:536870912 repl_backlog_first_byte_offset:1 repl_backlog_histlen:202750
當前sentinel狀態
在sentinel狀態中尤其是最后一行,涉及到masterIP是多少,有幾個slave,有幾個sentinels,必須是符合全部服務器數量的。
[root@localhost etc]# redis-cli -h 192.168.134.143 -p 26379 192.168.134.143:26379> info Sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=192.168.235.145:6379,slaves=2,sentinels=3
3.2.1.4:停止Redis Master測試故障轉移
故障轉移時sentinel的信息

故障轉移后redis.conf中的replicaof行的master IP會被修改,sentinel.conf中的sentinel monitor IP會被修改。

浙公網安備 33010602011771號