前言:
一.為什么要使用redis
1,解決應用服務器的cpu和內存壓力
2,減少io的讀操作,減輕io的壓力(內存中讀取)
3,關系型數據庫擴展性,不強,難以改變表的結構
二.優點
1,nosql數據庫沒有關聯關系,數據結構簡單,擴展容易
2,數據讀寫快,能夠每秒勝任幾十萬的並發,處理速度快
三.使用場景
1,數據高並發讀寫
2,海量數據讀寫
3,對不規則數據也就是擴展性要求高的數據
四.不適合場景
1,需要事務支持,雖然它也有事務但是沒有關系型數據庫的那么成熟吧
2,基於sql進行操作
五.集群模式分類
1,主從復制
2,哨兵模式
3,Redis官方提供的Cluster集群模式(服務端)
4,Jedis sharding集群(客戶端sharding)
5,利用中間件代理,比如豌豆莢的codis等
主從復制(Master-Slave Replication):
實現主從復制(Master-Slave Replication)的工作原理:Slave從節點服務啟動並連接到Master之后,它將主動發送一個SYNC命令。Master服務主節點收到同步命令后將啟動后台存盤進程,同時收集所有接收到的用於修改數據集的命令,在后台進程執行完畢后,Master將傳送整個數據庫文件到Slave,以完成一次完全同步。而Slave從節點服務在接收到數據庫文件數據之后將其存盤並加載到內存中。此后,Master主節點繼續將所有已經收集到的修改命令,和新的修改命令依次傳送給Slaves,Slave將在本次執行這些數據修改命令,從而達到最終的數據同步。
如果Master和Slave之間的鏈接出現斷連現象,Slave可以自動重連Master,但是在連接成功之后,一次完全同步將被自動執行。
主從復制配置
修改從節點的配置文件:slaveof masterip masterport
如果設置了密碼,就要設置:masterauth master-password
主從模式的優缺點
優點:
同一個Master可以同步多個Slaves。
Slave同樣可以接受其它Slaves的連接和同步請求,這樣可以有效的分載Master的同步壓力。因此我們可以將Redis的Replication架構視為圖結構。
Master Server是以非阻塞的方式為Slaves提供服務。所以在Master-Slave同步期間,客戶端仍然可以提交查詢或修改請求。
Slave Server同樣是以非阻塞的方式完成數據同步。在同步期間,如果有客戶端提交查詢請求,Redis則返回同步之前的數據
為了分載Master的讀操作壓力,Slave服務器可以為客戶端提供只讀操作的服務,寫服務仍然必須由Master來完成。即便如此,系統的伸縮性還是得到了很大的提高。
Master可以將數據保存操作交給Slaves完成,從而避免了在Master中要有獨立的進程來完成此操作。
支持主從復制,主機會自動將數據同步到從機,可以進行讀寫分離。
缺點:
Redis不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或者手動切換前端的IP才能恢復。
主機宕機,宕機前有部分數據未能及時同步到從機,切換IP后還會引入數據不一致的問題,降低了系統的可用性。
Redis的主從復制采用全量復制,復制過程中主機會fork出一個子進程對內存做一份快照,並將子進程的內存快照保存為文件發送給從機,這一過程需要確保主機有足夠多的空余內存。若快照文件較大,對集群的服務能力會產生較大的影響,而且復制過程是在從機新加入集群或者從機和主機網絡斷開重連時都會進行,也就是網絡波動都會造成主機和從機間的一次全量的數據復制,這對實際的系統運營造成了不小的麻煩。
Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。為避免這一問題,運維人員在系統上線時必須確保有足夠的空間,這對資源造成了很大的浪費。
建議:
其實redis的主從模式很簡單,在實際的生產環境中是很少使用的,也不建議在實際的生產環境中使用主從模式來提供系統的高可用性,之所以不建議使用都是由它的缺點造成的,在數據量非常大的情況,或者對系統的高可用性要求很高的情況下,主從模式也是不穩定的。
哨兵模式:
該模式是從Redis的2.6版本開始提供的,但是當時這個版本的模式是不穩定的,直到Redis的2.8版本以后,這個哨兵模式才穩定下來,無論是主從模式,還是哨兵模式,這兩個模式都有一個問題,不能水平擴容,並且這兩個模式的高可用特性都會受到Master主節點內存的限制。
Sentinel(哨兵)進程是用於監控redis集群中Master主服務器工作的狀態,在Master主服務器發生故障的時候,可以實現Master和Slave服務器的切換,保證系統的高可用。
Sentinel(哨兵)進程的作用
監控(Monitoring): 哨兵(sentinel) 會不斷地檢查你的Master和Slave是否運作正常。
提醒(Notification):當被監控的某個Redis節點出現問題時, 哨兵(sentinel) 可以通過 API 向管理員或者其他應用程序發送通知。
自動故障遷移(Automatic failover):當一個Master不能正常工作時,哨兵(sentinel) 會開始一次自動故障遷移操作,它會將失效Master的其中一個Slave升級為新的Master, 並讓失效Master的其他Slave改為復制新的Master;當客戶端試圖連接失效的Master時,集群也會向客戶端返回新Master的地址,使得集群可以使用現在的Master替換失效Master。Master和Slave服務器切換后,Master的redis.conf、Slave的redis.conf和sentinel.conf的配置文件的內容都會發生相應的改變,即,Master主服務器的redis.conf配置文件中會多一行slaveof的配置,sentinel.conf的監控目標會隨之調換。
Sentinel(哨兵)進程的工作方式
每個Sentinel(哨兵)進程以每秒鍾一次的頻率向整個集群中的Master主服務器,Slave從服務器以及其他Sentinel(哨兵)進程發送一個 PING 命令。
如果一個實例(instance)距離最后一次有效回復 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel(哨兵)進程標記為主觀下線(SDOWN)
如果一個Master主服務器被標記為主觀下線(SDOWN),則正在監視這個Master主服務器的所有 Sentinel(哨兵)進程要以每秒一次的頻率確認Master主服務器的確進入了主觀下線狀態
當有足夠數量的 Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間范圍內確認Master主服務器進入了主觀下線狀態(SDOWN), 則Master主服務器會被標記為客觀下線(ODOWN)
在一般情況下, 每個 Sentinel(哨兵)進程會以每 10 秒一次的頻率向集群中的所有Master主服務器、Slave從服務器發送 INFO 命令。
當Master主服務器被 Sentinel(哨兵)進程標記為客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的 Master主服務器的所有 Slave從服務器發送 INFO 命令的頻率會從 10 秒一次改為每秒一次。
若沒有足夠數量的 Sentinel(哨兵)進程同意 Master主服務器下線, Master主服務器的客觀下線狀態就會被移除。若 Master主服務器重新向 Sentinel(哨兵)進程發送 PING 命令返回有效回復,Master主服務器的主觀下線狀態就會被移除。
哨兵模式的優缺點
優點:
哨兵集群模式是基於主從模式的,所有主從的優點,哨兵模式同樣具有。
主從可以切換,故障可以轉移,系統可用性更好。
哨兵模式是主從模式的升級,系統更健壯,可用性更高。
缺點:
Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。為避免這一問題,運維人員在系統上線時必須確保有足夠的空間,這對資源造成了很大的浪費。
配置復雜
Redis官方 Cluster集群模式
Redis Cluster是一種服務器Sharding技術,3.0版本開始正式提供。
在這個圖中,每一個藍色的圈都代表着一個redis的服務器節點。它們任何兩個節點之間都是相互連通的。客戶端可以與任何一個節點相連接,然后就可以訪問集群中的任何一個節點。對其進行存取和其他操作。
Redis集群數據分片
在redis的每一個節點上,都有這么兩個東西,一個是插槽(slot)可以理解為是一個可以存儲兩個數值的一個變量這個變量的取值范圍是:0-16383。還有一個就是cluster我個人把這個cluster理解為是一個集群管理的插件。當我們的存取的key到達的時候,redis會根據crc16的算法得出一個結果,然后把結果對 16384 求余數,這樣每個 key 都會對應一個編號在 0-16383 之間的哈希槽,通過這個值,去找到對應的插槽所對應的節點,然后直接自動跳轉到這個對應的節點上進行存取操作。
還有就是因為如果集群的話,是有好多個redis一起工作的,那么,就需要這個集群不是那么容易掛掉,所以呢,理論上就應該給集群中的每個節點至少一個備用的redis服務。這個備用的redis稱為從節點(slave)。那么這個集群是如何判斷是否有某個節點掛掉了呢?
首先要說的是,每一個節點都存有這個集群所有主節點以及從節點的信息。
它們之間通過互相的ping-pong判斷是否節點可以連接上。如果有一半以上的節點去ping一個節點的時候沒有回應,集群就認為這個節點宕機了,然后去連接它的備用節點。如果某個節點和所有從節點全部掛掉,我們集群就進入faill狀態。還有就是如果有一半以上的主節點宕機,那么我們集群同樣進入發力了狀態。這就是我們的redis的投票機制,具體原理如下圖所示:
投票過程是集群中所有master參與,如果半數以上master節點與master節點通信超時(cluster-node-timeout),認為當前master節點掛掉.
什么時候整個集群不可用(cluster_state:fail)?
如果集群任意master掛掉,且當前master沒有slave.集群進入fail狀態,也可以理解成集群的slot映射[0-16383]不完整時進入fail狀態. ps : redis-3.0.0.rc1加入cluster-require-full-coverage參數,默認關閉,打開集群兼容部分失敗.
如果集群任意master掛掉,且當前master沒有slave.集群進入fail狀態,也可以理解成集群的slot映射[0-16383]不完整時進入fail狀態. ps : redis-3.0.0.rc1加入cluster-require-full-coverage參數,默認關閉,打開集群兼容部分失敗.
Redis 3.0的集群方案有以下兩個問題。
一個Redis實例具備了“數據存儲”和“路由重定向”,完全去中心化的設計。這帶來的好處是部署非常簡單,直接部署Redis就行,不像Codis有那么多的組件和依賴。但帶來的問題是很難對業務進行無痛的升級,如果哪天Redis集群出了什么嚴重的Bug,就只能回滾整個Redis集群。
對協議進行了較大的修改,對應的Redis客戶端也需要升級。升級Redis客戶端后誰能確保沒有Bug?而且對於線上已經大規模運行的業務,升級代碼中的Redis客戶端也是一個很麻煩的事情。
Redis Cluster是Redis 3.0以后才正式推出,時間較晚,目前能證明在大規模生產環境下成功的案例還不是很多,需要時間檢驗。
jedis sharding集群
Redis Sharding可以說是在Redis cluster出來之前業界普遍的采用方式,其主要思想是采用hash算法將存儲數據的key進行hash散列,這樣特定的key會被定為到特定的節點上。
慶幸的是,Java Redis客戶端驅動Jedis已支持Redis Sharding功能,即ShardedJedis以及結合緩存池的ShardedJedisPool
Jedis的Redis Sharding實現具有如下特點:
采用一致性哈希算法,將key和節點name同時hashing,然后進行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用簡單類似哈希求模映射的主要原因是當增加或減少節點時,不會產生由於重新匹配造成的rehashing。一致性哈希只影響相鄰節點key分配,影響量小。
為了避免一致性哈希只影響相鄰節點造成節點分配壓力,ShardedJedis會對每個Redis節點根據名字(沒有,Jedis會賦予缺省名字)會虛擬化出160個虛擬節點進行散列。根據權重weight,也可虛擬化出160倍數的虛擬節點。用虛擬節點做映射匹配,可以在增加或減少Redis節點時,key在各Redis節點移動再分配更均勻,而不是只有相鄰節點受影響。
ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,這樣通過合理命名key,可以將一組相關聯的key放入同一個Redis節點,這在避免跨節點訪問相關數據時很重要。
當然,Redis Sharding這種輕量靈活方式必然在集群其它能力方面做出妥協。比如擴容,當想要增加Redis節點時,盡管采用一致性哈希,畢竟還是會有key匹配不到而丟失,這時需要鍵值遷移。
作為輕量級客戶端sharding,處理Redis鍵值遷移是不現實的,這就要求應用層面允許Redis中數據丟失或從后端數據庫重新加載數據。但有些時候,擊穿緩存層,直接訪問數據庫層,會對系統訪問造成很大壓力。
利用中間件代理
中間件的作用是將我們需要存入redis中的數據的key通過一套算法計算得出一個值。然后根據這個值找到對應的redis節點,將這些數據存在這個redis的節點中。
常用的中間件有這幾種
Twemproxy
Codis
nginx
具體用法就不贅述了,可以自行百度。
總結
客戶端分片(sharding)需要客戶端維護分片算法,這是一種靜態的分片方案,需要增加或者減少Redis實例的數量,需要手工調整分片的程序。
利用中間件的情況則會影響到redis的性能,具體看中間件而定,畢竟所有請求都要經過中間件一層過濾
官方提供方案,現時點成功案例不多。