要保證Redis不會掛掉,也就是提高Redis的高可用性,可以從這麼幾個方面考慮。

集羣式部署方式
  • Redis單副本:也就是隻部署一臺Redis,不需要節點之間的數據同步,架構簡單,部署方便;但是單臺機器畢竟是有風險的,按照題目中【海量數據】的場景,是不能達到高可用要求的。

  • Redis主從:主從實例可以部署在不同的物理伺服器上,充分利用多臺伺服器的資源,在主庫發生故障的時候,可以進行主備切換,從而保證系統的穩定運行,甚至可以做到讀寫分離,主庫專門用作寫操作,一臺或多臺備庫進行讀操作;但是當主庫發生故障的時候(如果沒有HA方案的話),是需要手動進行主備切換的。

  • Redis Sentinel:部署架構分為兩部分【Sentinel集羣】和【數據集羣】;Sentinel集羣是由多個Sentinel節點組成的分散式集羣,通常是2N+1臺伺服器,可以實現故障發現和轉移、客戶端通知等功能;數據集羣用於存儲數據;它能夠解決主從模式下的自動切換問題,並且數據集羣是可以橫向擴展的;當然這個架構實現和部署起來,也更為複雜一些;並且這個架構不能做到讀寫分離。

  • Redis Cluster:Redis 3.0集羣,是分散式集羣解決方案之一,物理架構中配置2N個節點(主從一一對應),主節點提供讀寫操作,從節點作為備份;數據分佈保存在多個節點上,是一種無中心的架構,如果有部分節點發生故障,能夠實現故障自動轉移和切換,用投票機制完成備庫升級為主庫(下文的Redis分片章節,還會介紹到Redis Cluster)。

Redis分片

Redis在3.0之前只支持單實例,在此之前,在數據量比較大的情況,通常有幾種方案可以做到把數據分片保存到多臺伺服器上。

  • 客戶端分片:分片邏輯被放到了客戶端上,由客戶端根據路由規則,把數據保存不同的Redis實例中,讀取的時候也是根據規則,去對應的實例上讀取數據;但是當Redis實例數量發生變化的時候(增加實例或減少實例),需要手動地調整分片的規則程序;並且這種部署方式,也增加了運維的成本。

  • Redis代理組件:在這種架構中,客戶端不再直接訪問Redis實例,而是訪問代理組件,由它管理路由的規則;客戶端不需要關心有幾個Redis實例,數據被路由到哪個實例上;但是由於在客戶端和Redis之間增加了一層代理,多多少少也會產生一些性能上的損耗。

  • Redis Cluster:上文中提到的Redis 3.0集羣,這裡對數據的存儲和路由方式,再介紹幾句:Redis把所有的Key分成了16384個slot,每個Redis實例負責其中一部分slot;每個Redis都知道每個slot在哪個節點上存儲(實例節點定期做數據交換);當客戶端訪問到一個Redis實例的時候,如果數據不在這個實例上,那麼會通過重定向命令引導客戶端訪問數據所在的實例。

熱點數據挑戰單節點的極限

雖然我們已經把數據分散保存到多臺Redis實例上了,但是如果有一個熱點數據被頻繁訪問,超過了單實例的伺服器極限,那麼該如何解決呢?通常的手段就是做讀寫分離,部署多臺只讀節點,對外提供服務。

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。


海量數據下正確的訪問redis要注意的事情有很多,基本上可以從服務治理,數據,redis正確使用三個方面來講。

  • 服務治理

既然是海量數據,那麼服務肯定要拆分成多個服務,最常見的採用「大中臺,小前臺」的概念,中臺分各個服務中心,各個中心去維護自己中心負責的服務,向上遊前臺提供數據和服務。比如一個做內容付費的公司可以有內容中心、商品中心、交易中心

用戶中心、促銷中心、基礎中心、開放平臺等,中心之間採用RPC通信或者數據共享。

  • 數據劃分

在服務治理的基礎上,各個中心負責維護自己的數據,那麼數據的存儲有MySQL、MongoDB(存儲非結構化數據)、Redis,這些數據存儲介質都做成獨立實例,互不影響。那麼海量數據分散到各個中心了,壓力也會相對少一些,做到每個中心都有自己獨立的一個或多個資料庫實例、Redis實例。每個中心再根據自己中心的數據做好分庫分表、緩存同步等工作。下圖是一張資料庫和redis緩存同步的方案,通過實時刷新+定時任務同步補償機制,將大部分熱點業務數據實時同步至redis。

  • redis的正確使用

在做好服務治理和數據劃分的基礎上,這個時候就是重點講如何正確使用redis的時候了,個人列舉了部分細則僅供大家參考:

  1. 熟練使用五種數據結構(String、Set|、Hash、List、ZSet)以及每種數據結構的適用場景和注意事項;

  2. 防止緩存雪崩,即避免大批量緩存同一時間段集中過期,導致大量請求都懟到資料庫上,導致資料庫連接數爆滿、宕機;

  3. 防止緩存穿透,避免redis中熱點key存入了null或者不存在,導致大量請求繞過redis請求資料庫去了;

  4. 避免大key的存在:比如一個redis集羣是16G,共8個節點,每個節點平均分配2G的內存,這時候如果有一個大的hash key佔用內存超過2G了,這個時候儘管集羣還有剩餘的空間,這個大key的寫入依舊會失敗,單個key是無法做到集羣的,另外再想想如果一個hash存儲了大量的數據,考慮一下性能問題?

  5. 禁止使用keys、flushall、flushdb等,運維同學通過redis的rename機制禁掉命令,或者使用scan的方式漸進式處理;

  6. 批量讀寫redis請採用pipeline管道的方式;

  7. 在代碼中採用線程連接池的方式定義每一個redis bean

  8. 這裡和大家一起溫習一下redis過期策略和內存淘汰機制:redis採用的是惰性刪除和定期刪除的過期策略,內存淘汰機制有:

volatile-lru :在設置了過期時間的鍵空間中,移除最近最少使用的key。

allkeys-lru : 移除最近最少使用的key (推薦)

volatile-random : 在設置了過期時間的鍵空間中,隨機移除一個鍵,不推薦

allkeys-random : 直接在鍵空間中隨機移除一個鍵,沒人用

volatile-ttl : 在設置了過期時間的鍵空間中,有更早過期時間的key優先移除 不推薦

noeviction : 不做過鍵處理,只返回一個寫操作錯誤。 不推薦

如果是你,你會使用哪種過期策略?

所以,個人認為redis用好並不難,難的是把服務治理好,redis跟著服務走就可以了。

以上,是個人對redis使用的一些認識和看法,大家還有什麼好的使用建議和想法,歡迎下方留言討論,共同成長~


掛掉?一般都是配置不足,如果你伺服器和redis在同同一機器,機器內存和伺服器內存 幾乎佔了機器的全部內存,這時候你訪問取一個比較大的數據肯定會掛的。加錢吧??


推薦閱讀:
相關文章