慢查詢
Pipeline
弱事務性
釋出跟訂閱
Redis持久化原理剖析
RDB持久化
CopyOnWrite
AOF持久化
RDB和AOF恢複順序
主從複制
一主一從:
一主多從:
樹狀主從:
複制原理
哨兵機制
Redis Sentinel
哨兵選舉規則
故障轉移流程
故障轉移流程A
故障轉移流程B
故障轉移流程C
故障轉移後的拓撲結構圖D
故障轉移大緻流程
部署建議
叢集
Redis分布式概念:
分區規則
虛拟槽分區
叢集缺陷
叢集通訊Gossip協定
叢集重定向
參考
Redis查詢指令過程一般如下:

在Redis中當執行時間超過閥值,會将發生時間 耗時 指令記錄,此時的慢查詢指的是第三階段執行指令時期。關于慢查詢的配置記錄可參考慢查詢設定,
PS:項目部署前對伺服器對redis性能測試很有必要,好好利用redis-benchmark
該指令出現的背景:redis用戶端執行一條指令分4個過程:
發送指令-〉指令排隊-〉指令執行-〉傳回結果
這個過程稱為Round trip time(簡稱RTT, 往返時間),mget mset有效節約了RTT,但大部分指令(如hgetall,并沒有mhgetall)不支援批量操作,需要消耗N次RTT ,這個時候需要pipeline來解決這個問題
未使用pipeline執行N條指令
使用了pipeline執行N條指令 jedis.pipeline,此處可以懂了RESP手動實作執行流程就很簡單了,
性能測試結果:
結論:使用Pipeline執行速度與逐條執行要快,特别是用戶端與服務端的
網絡延遲越大,性能體能越明顯。但是使用pipeline組裝的指令個數不能太多,不然資料量過大,增加用戶端的等待時間,還可能造成網絡阻塞,可以将大量指令的拆分多個小的pipeline指令完成。
mysql資料倒入到Redis
order.sql
在Redis中要記住 Redis中原生批指令是原子性,pipeline是非原子性,
原生批指令是服務端實作,而pipeline需要服務端與用戶端共同完成。
Redis簡單事務:将一組需要一起執行的指令放到multi和exec兩個指令之間,其中multi代表事務開始,exec代表事務結束。使用watch後, multi失效,事務失效。
弱事務性測試:
結論:Redis自帶的事務性賊雞肋,用好Redis必須用好Lua。
redis提供了“釋出、訂閱”模式的消息機制,其中消息訂閱者與釋出者不直
接通信,釋出者向指定的頻道(channel)釋出消息,訂閱該頻道的每個客
戶端都可以接收到消息。不過比專業的MQ(RabbitMQ RocketMQ ActiveMQ Kafka)相比不值一提,這個功能就别用了。。。
redis是一個支援持久化的記憶體資料庫,也就是說redis需要經常将記憶體中的資料同步到磁盤來保證持久化,持久化可以避免因程序退出而造成資料丢失。
RDB:把目前程序資料生成快照(.rdb)檔案儲存到硬碟的過程。
手動觸發有save和bgsave兩指令
save指令:阻塞目前Redis,直到RDB持久化過程完成為止,若記憶體執行個體比較大會造成長時間阻塞,線上環境不建議用它
bgsave指令:redis程序執行fork操作建立子線程,由子線程完成持久化,阻塞時間很短(微秒級),是save的優化,在執行redis-cli shutdown關閉redis服務時,如果沒有開啟AOF持久化,自動執行bgsave;
自動觸發就是在redis配置檔案中
那麼隻要滿足以下三個條件中的任意一個,BGSAVE 指令就會被執行:
伺服器在 900 秒之内,對資料庫進行了至少 1 次修改 伺服器在 300 秒之内,對資料庫進行了至少 10 次修改 伺服器在 60 秒之内,對資料庫進行了至少 10000 次修改
優點:
壓縮後的二進制文,适用于備份、全量複制,用于災難恢複 加載RDB恢複資料遠快于AOF方式
缺點:
無法做到實時持久化,每次都要建立子程序,頻繁操作成本過高 儲存後的二進制檔案,存在老版本不相容新版本rdb檔案的問題
Redis的執行bgsave生成dump.rdb是根據CopyOnWrite來玩的。如果有多個調用者(callers)同時請求相同資源(如記憶體或磁盤上的資料存儲),他們會共同擷取相同的指針指向相同的資源,直到某個調用者試圖修改資源的内容時,系統才會真正複制一份專用副本(private copy)給該調用者,而其他調用者所見到的最初的資源仍然保持不變。優點是如果調用者沒有修改該資源,就不會有副本(private copy)被建立,是以多個調用者隻是讀取操作時可以共享同一份資源。
CopyOnWrite就是不同的線程操作不同的資源,最後再整合,是以是線程安全的,但不能保證強一緻性
比如我現在資料 1234 我要插入5
那麼原來的線程看到的資料是 1234 我新開的線程看到的資料是 12345
并且CopyOnWriteList中的set和add 方法都是加鎖了的,是以至多有一份拷貝。當這份拷貝資源執行完後,才會釋放鎖,進行下次的set或add方法
redis 針對RDB不适合實時持久化,redis提供了AOF持久化方式來解決,底層原理就是将所有涉及到增删到RESP指令全部寫到<code>appendonly.aof</code>檔案中,恢複到時候将全部指令執行一遍。
開啟:redis.conf設定:appendonly yes (預設不開啟,為no) 預設檔案名:appendfilename “appendonly.aof”
AOF流程:
所有的寫入指令(set hset)會append追加到aof_buf緩沖區中 AOF緩沖區向硬碟做sync同步 随着AOF檔案越來越大,需定期對AOF檔案rewrite重寫,達到壓 當redis服務重新開機,可load加載AOF檔案進行恢複
重要指令詳解
appendonly yes //啟用aof持久化方式 appendfsync always //每收到寫指令就立即強制寫入磁盤,最慢的,但是保證完全的持久化,不推薦使用 appendfsync everysec //每秒強制寫入磁盤一次,性能和持久化方面做了折中,推薦 appendfsync no //完全依賴os,性能最好,持久化沒保證(作業系統自身的同步) no-appendfsync-on-rewrite yes //正在導出rdb快照的過程中,要不要停止同步aof auto-aof-rewrite-percentage 100 //aof檔案大小比起上次重寫時的大小,增長率100%時,重寫 auto-aof-rewrite-min-size 64mb //aof檔案,至少超過64M時,重寫
AOF持久化方式相比于RDB來說,可讀性高(儲存的是代碼,可讀性好),适合儲存增量資料,資料不易丢失。 ps:為什麼資料不容易丢失?因為資料被儲存在記憶體中的AOF緩沖區中,資料不易丢失。
儲存基本上所有redis除讀之外的代碼,儲存的檔案大,恢複資料需要重寫執行所有的代碼,恢複的時間長
redis重新開機恢複資料時流程如下:
當AOF和RDB檔案同時存在時,優先加載AOF 若關閉了AOF,加載RDB檔案 加載AOF/RDB成功,redis重新開機成功 AOF/RDB存在錯誤,啟動失敗列印錯誤資訊
和Mysql主從複制的原因一樣,Redis雖然讀取寫入的速度都特别快,但是也會産生讀壓力特别大的情況。為了分擔讀壓力,Redis支援主從複制,Redis的主從結構可以采用一主多從或者級聯結構,Redis主從複制可以根據是否是全量分為全量同步和增量同步,一般主節點負責寫資料,從節點負責讀資料。
整體圖如下:
注意傳輸延遲性,主從一般部署在不同機器上,複制時存在網絡延時問題,redis提供repl-disable-tcp-nodelay參數決定是否關閉TCP_NODELAY,預設為關閉
參數關閉時:無論大小都會及時釋出到從節點,占帶寬,适用于主從網絡好的場景, 參數啟用時:主節點合并所有資料成TCP包節省帶寬,預設為40毫秒發一次,取決于核心,主從的同步延遲40毫秒,适用于網絡環境複雜或帶寬緊張,如跨機房
用于主節點故障轉移從節點,當主節點的且需要持久化寫指令并發高,可以隻在從節點開啟AOF(主節點不需要)![]()
【Redis】進階特性 (性能分析,持久化,主從,哨兵,叢集)
針對讀較多的場景,“讀”由多個從節點來分擔,但節點越多,主節點同步到多節點的次數也越多,影響帶寬,也加重主節點的穩定。![]()
【Redis】進階特性 (性能分析,持久化,主從,哨兵,叢集)
一主多從的缺點(主節點推送次數多壓力大)可用些方案解決,主節點隻推送一次資料到從節點B,再由從節點B推送到D和E,減輕主節點推送的壓力![]()
【Redis】進階特性 (性能分析,持久化,主從,哨兵,叢集)
先啟動master然後啟動若幹slave,可以用info replication 檢視主從及同步資訊。
redis 2.8版本以上使用psync指令完成同步,過程分“全量”與“部分”複制
全量複制:
一般用于初次複制場景(第一次建立SLAVE後全量)
部分複制:
網絡出現問題,從節點再次連主時,主節點補發缺少的資料,每次資料增加同步
心跳:
主從有長連接配接心跳,主節點預設每10S向從節點發ping指令,repl-ping-slave-period控制發送頻率
背景同步原理:
儲存主節點資訊 主從建立socket連接配接 發送ping指令 權限驗證 同步資料集 指令持續複制
前面的主從複用配置檔案啟動很簡單,問題是如何實作高可用,master 停止後可自動切換到slave節點。
高可用:當主節點出現故障時,由Redis Sentinel自動完成故障發現和轉移,并通知應用方,實作高可用性。
哨兵有三個定時監控任務完成對各節點的發現和監控,主要是循環性到監控master跟slave
下線的時候分為主觀下線和客觀下線。
主觀下線:單獨一個哨兵發現master故障了。
客觀下線:多個哨兵進行抉擇發現達到quorum數時候開始進行切換。
大部分情況下都是那個哨兵發現master了就會成為上司者負責節點切換工作。
sentinel會向master發送心跳PING來确認master是否存活,如果master在“一定時間範圍”内不回應PONG 或者是回複了一個錯誤消息,那麼這個sentinel會主觀地(單方面地)認為這個master已經不可用了。
當主節點出現故障,此時假設3個Sentinel節點共同選舉了Sentinel3節點為上司者sentinel,負載處理主節點的故障轉移。
由Sentinel3上司者節點執行故障轉移,過程和主從複制一樣,但是自動執行。
sentinel節點應部署在多台實體機(線上環境) 至少三個且奇數個sentinel節點 三個sentinel可同時監控一個主節點或多個主節點,當監聽N個主節點較多時,如果sentinel出現異常,會對多個主節點有影響,同時還會造成sentinel節點産生過多的網絡連接配接,一般線上建議還是, 3個sentinel監聽一個主節點
最後用戶端通過JedisSentinelPool 來操作即可啦。。。
RedisCluster是Redis的分布式解決方案,在3.0版本後推出的方案,有效地解決了Redis分布式的需求,當遇到單機記憶體、并發等瓶頸時,可使用此方案來解決這些問題,關于叢集的搭建也推薦看下此文。
比如我們庫有900條使用者資料,有3個redis節點,将900條分成3份,分别存入到3個redis節點
常見的分區規則
節點取餘:hash(key) % N 一緻性哈希: 一緻性哈希環 虛拟槽哈希:CRC16[key]&16383
RedisCluster采用了哈希分區的“虛拟槽分區”方式(哈希分區分節點取餘、一緻性哈希分區和虛拟槽分區)
槽:slot,RedisCluster采用此分區,所有的鍵根據哈希函數(CRC16[key]&16383)映射到0-16383槽内,共16384個槽位,每個節點維護部分槽及槽所映射的鍵值資料。
哈希函數:
Hash()=CRC16[key]&16383
此時KV存儲規則如下:
鍵的批量操作支援有限,比如mset, mget。 鍵事務支援有限,當多個鍵分布在不同節點時無法使用事務,同一節點是支援事務 鍵是資料分區的最小粒度,不能将一個很大的鍵值對映射到不同的節點 不支援多資料庫,隻有0,select 0 複制結構隻支援單層結構,不支援樹型結構。
關于叢集的建立 百度上搜尋即可。按照教程來不難。
Gossip協定的主要職責就是資訊交換,資訊交換的載體就是節點之間彼此發送的Gossip消息,常用的Gossip消息有ping消息、pong消息、meet消息、fail消息
meet消息:用于通知新節點加入,消息發送者通知接收者加入到目前叢集,meet消息通信完後,接收節點會加入到叢集中,并進行周期性ping pong交換 ping消息:叢集内交換最頻繁的消息,叢集内每個節點每秒向其它節點發ping消息,用于檢測節點是在線上和狀态資訊,ping消息發送封裝自身節點和其他節點的狀态資料; pong消息,當接收到ping meet消息時,作為響應消息傳回給發送方,用來确認正常通信,pong消息也封閉了自身狀态資料; fail消息:當節點判定叢集内的另一節點下線時,會向叢集内廣播一個fail消息
不難了解:redis通過叢集的搭建實作了多個master 的共同工作,然後在不同的master 下面還建立了slave節點來實作叢集的高可用,當有某個主節點故障後會有節點迅速補上來。并且可以實作動态的增删master。
最後 Java操作redis叢集的時候通過JedisPool 來操作rediscluster池就OK咯哦!不過在SpringBoot中底層都已經幫我們封裝好咯。我們簡單設定幾步就OK了,看參考文檔即可。
rdb持久化
主從筆記
主從,持久化,哨兵
java用戶端Jedis操作Redis Sentinel 連接配接池
一緻性哈希
rediscluster下叢集應用-rediscluster連接配接池實作
springBoot整合redisCluster
windows上Redis叢集搭建