日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本文介紹了redis緩存原理、詳細解析了緩存模型、緩存一致性和緩存異常場景。

盡管(關系型)數據庫系統 (SQL) 帶來了許多出色的屬性,例如 ACID,但為了保持這些屬性,數據庫的性能在“ 3 高” 條件環境下下往往顯得捉襟見肘、蒼白無力 。

為了解決這個問題,我們往往需要在應用層(即處理業務邏輯的后端代碼)和存儲層(即 SQL 數據庫)之間增加一個緩存層。該緩存層通常使用內存緩存來實現,畢竟,傳統 SQL 數據庫的性能瓶頸通常發生在二級存儲(即硬盤)的 I/O 層面。隨著主內存 (RAM) 的價格在過去十年中下降,故將(至少部分)數據存儲在主內存中以提高性能便是一種性價比較高的解決方案。基于當前的技術發展現狀,Redis 便成為當下一種較為流行的選擇。

當然,大多數系統只將所謂的“熱數據”存儲在緩存層(即主內存)中。基于帕累托原理(也稱為 80/20 法則),對于大多數事件,大約 80% 的影響來自 20% 的原因。為了節省成本,我們只需要將這 20% 存儲在緩存層中。為了識別“熱數據”,我們可以指定驅逐策略(例如 LFU 或 LRU )來確定哪些數據將過期。

緩存概述

緩存是一種“預熱”技術,用于將經常訪問的數據存儲在臨時存儲器(稱為緩存)中,以減少硬盤驅動器的讀/寫。緩存無處不在,基于此技術可以大大地提高 Web 應用程序的性能。

通常,在最初的單體架構模型,當用戶向我們的服務發送一個消息請求時,Web 服務器首先會讀取或寫入數據庫再返回響應。在緩存的情況下,服務器首先檢查緩存副本是否存在,如果存在則從緩存返回數據而不是詢問數據庫。它節省了時間和數據庫的計算工作量。

下面簡要介紹一下應用程序如何請求 Redis ,此處主要基于 Master-Slave-Sentinel 模式的集群,App 通過調用 Redis Client ,例如,Jedis、Lettuce 及 Redisson 等來與 Redis Sentinel 通信,當 Redis Master 切換至 Slave 時,Application 依舊能夠正常工作,如下為詳細的時序圖:

緩存模型

在分布式系統中,基于 CAP 定理指導,根據業務需求和上下文選擇這些策略,通??蓪⑵鋭澐譃槌R幠J胶?Cache-Aside 模式。在開始之前,讓我們通過刷新緩存的方式來了解常用的緩存模式,具體如下所 示:

寫模型

1、Write Through:即“直寫”。此模型為同步寫入數據庫后再緩存。這是安全的,因為它首先寫入數據庫,但比后寫慢。與寫無效相比,它為先寫后讀場景提供了更好的性能。在這種寫入策略中,數據首先寫入緩存,然后寫入數據庫。緩存與數據庫串聯,寫入總是通過緩存到主數據庫。

直寫模式的算法是:

1)對于不可變操作(讀?。?/p>

此策略不處理不可變操作。它應該與通讀模式相結合。

2)對于可變操作(創建、更新、刪除):

客戶端只需要在 Redis 中創建、更新或刪除條目。緩存層必須以原子方式將此更改同步到 MySQL。

直寫模式的缺點也很明顯。首先,許多緩存層本身并不支持這一點。其次,Redis 是緩存而不是 RDBMS。它的設計并非具有彈性。因此,更改在復制到 MySQL 之前可能會丟失。即使 Redis 現在已經支持 RDB 和 AOF 等持久化技術,但仍然不推薦這種方式。

就其本身而言,直寫緩存似乎沒有太大作用,實際上,它們會引入額外的寫入延遲,因為數據先寫入緩存,然后再寫入主數據庫。但是當與通讀緩存配對時,我們可以獲得通讀的所有好處,并且我們還可以獲得數據一致性保證,使我們免于使用緩存失效技術。

DynamoDB Accelerator (DAX) 是讀取/寫入緩存的一個很好的例子。它與 DynamoDB 和應用程序內聯。可以通過 DAX 對 DynamoDB 進行讀取和寫入。

2、Write Behind:即“后寫或回寫”?;诖瞬呗?,應用程序將數據寫入緩存,緩存會立即確認,并在延遲一段時間后將數據寫回數據庫 。這對于寫入速度非???,如果將同一鍵上的多個寫入合并為一次對數據庫的寫入,則速度會更快。但是數據庫長時間與緩存不一致,如果在數據刷新到數據庫之前進程崩潰,可能會丟失數據。RAID 卡是這種模式的一個很好的例子,為了避免數據丟失,通常需要 RAID 卡上的電池備份單元將數據保存在緩存中,但尚未登陸到磁盤。

Write Behind 模式的算法是:

1)對于不可變操作(讀?。?/p>

此策略不處理不可變操作。它應該與通讀模式相結合。

2)對于可變操作(創建、更新、刪除):

客戶端只需要在 Redis 中創建、更新或刪除條目。緩存層將更改保存到消息隊列中并向客戶端返回成功。更改會異步復制到 MySQL,并且可能在 Redis 向客戶端發送成功響應后發生。

后寫模式與直寫不同,因為它異步地將更改復制到 MySQL。它提高了吞吐量,因為客戶端不必等待復制發生。具有高持久性的消息隊列可能是一種可能的實現。Redis 流(自 Redis 5.0 起受支持)可能是一個不錯的選擇。為了進一步提高性能,可以結合更改并批量更新 MySQL(以節省查詢次數)。

Write Behind 模式的缺點是相似的。首先,許多緩存層本身并不支持這一點。其次,使用的消息隊列必須是 FIFO(先進先出)。否則,對 MySQL 的更新可能會亂序,因此最終結果可能不正確。

回寫緩存提高了寫入性能,適用于寫入繁重的工作負載。與通讀結合使用時,它適用于混合工作負載,其中最近更新和訪問的數據始終在緩存中可用。

它對數據庫故障具有彈性,并且可以容忍一些數據庫停機時間。如果支持批處理或合并,它可以減少對數據庫的總體寫入,從而減少負載并降低成本,如果數據庫提供程序按請求數量收費,例如動態數據庫。請記住,DAX 是直寫的,因此如果應用程序寫入繁重,則不會看到任何成本降低。

一些開發人員將 Redis 用于緩存和回寫,以更好地吸收峰值負載期間的峰值。主要缺點是如果緩存失敗,數據可能會永久丟失。

大多數關系數據庫存儲引擎(即 InnoDB)在其內部默認啟用回寫緩存。查詢首先寫入內存并最終刷新到磁盤。

3、Write invalidate:類似于直寫,先寫入數據庫,然后使緩存無效。在并發更新的情況下,這簡化了緩存和數據庫之間的一致性處理。我們不需要復雜的同步,權衡是命中率較低,因為我們總是使緩存無效并且下一次讀取將始終未命中。

讀模型

Read Through:即“ 通讀 ”。當讀取未命中時,需要從數據庫中加載并保存到緩存中。這種模式的主要問題是基于某些特定的場景有時需要預熱緩存。通讀緩存與數據庫保持一致。當緩存未命中時,它會從數據庫中加載丟失的數據,填充緩存并將其返回給應用程序。

通讀模式的算法是:

1、對于不可變操作(讀?。?/p>

客戶端將始終簡單地從緩存中讀取。緩存命中或緩存未命中對客戶端是透明的。如果是緩存未命中,緩存應該具有自動從數據庫中獲取的能力。

2、對于可變操作(創建、更新、刪除):

此策略不處理可變操作。它應該與直寫(或后寫)模式結合使用。

通讀模式的一個主要缺點是許多緩存層可能不支持它。例如,Redis 將無法自動從 MySQL 獲取(除非為 Redis 編寫插件)。

Cache-Aside 和 Read-Through 策略都是延遲加載數據,即僅在第一次讀取時加載。其適用 用例場景如下所示:

雖然 Read- Through 和 Cache-Aside 非常相似,但至少有兩個關鍵區別:

在緩存側,應用程序負責從數據庫中獲取數據并填充緩存。在通讀中,此邏輯通常由庫或獨立緩存提供程序支持。

與 Cache-Aside 不同,Read-Through Cache 中的數據模型不能與數據庫的數據模型不同。

當多次請求相同的數據時,通讀緩存最適合讀取繁重的工作負載。例如,一個新聞故事。缺點是當第一次請求數據時,總是會導致緩存未命中,并招致將數據加載到緩存中的額外懲罰。開發人員通過手動發出查詢來“加熱”或“預熱”緩存來處理這個問題。就像 cache-aside 一樣,緩存和數據庫之間的數據也有可能不一致,解決方法在于寫入策略,我們將在下面看到。

不讀或不寫模型

Refresh ahead:預測熱點數據并自動刷新數據庫中的緩存,永不阻塞讀取,最適合小型只讀數據集,例如郵政編碼列表緩存,我們可以定期刷新整個緩存,因為它很小并且是只讀的。如果能夠可以準確地預測最常讀取哪些鍵,那么,還可以在此模式中預熱這些鍵。最后,如果數據在系統之外更新而系統無法收到通知,可能必須使用此模式。

在大多數場景下,我們通常使用通讀和直寫/后寫/寫無效等模型。針對 Refresh-ahead 模型,其可以單獨使用,也可以作為一種優化來預測和預熱讀取以進行通讀。由誰負責緩存維護,調用者或專用層有兩種實現模式。

1、Cache-Facade:緩存層是一個庫或服務委托寫入數據庫,我們只與緩存層交談。然后數據庫對我們的應用程序是透明的。緩存層可以處理一致性和故障轉移。例如,許多數據庫都有自己的緩存,這是緩存外觀的一個很好的例子。我們還可以編寫一些進程內 DAO 層來讀取/寫入具有嵌入式緩存層的實體,從調用者的角度來看,這個小層也是一個緩存門面。

2、Cache-Aside:我們的應用程序保持緩存一致性,這意味著應用程序代碼更復雜,但這提供了更大的靈活性。例如,像數據庫查詢緩存這樣的緩存外觀模式只能緩存行,如果想緩存帶有行的 JAVA POJO 或 Kotlin 數據類,則將緩存放在一邊要容易得多。但是它仍然可以使用緩存門面,例如,將 Spring 緩存作為門面庫來緩存 POJO,并在后臺自動處理數據庫中的 POJO。

當緩存不支持原生的讀通和寫通操作,并且資源需求不可預測時,我們使用這種緩存側模式。

1)讀?。簢L試命中緩存。如果沒有命中,則從數據庫中讀取,然后更新緩存。

2)寫入:先寫入數據庫,然后刪除緩存條目。這里一個常見的陷阱是人們錯誤地用值更新了緩存,高并發環境下的雙寫會使緩存變臟。

在這種模式下,仍然有可能出現臟緩存。在滿足這兩種情況時會發生上述情況:讀取數據庫并更新緩存、 更新數據庫并刪除緩存。

緩存一致性

緩存一致性模型(參考)圖

如何保障緩存(Redis)與 數據存儲(數據庫)之間的數據一致性,通常 有多種 設計實現策略,本文重點針對 Cache Aside Pattern(旁路緩存模式) 進行簡要解析,此模型也是在實際的業務場景中使用較為廣泛的。具體如下。

在 Cache Aside Pattern 模型中,通常寫請求場景基本流程主要為:先更新 DB,然后直接刪除 Cache 。

在業務場景實現中,如果更新數據庫成功,而進行緩存刪除操作時出現失敗的情況下,簡單地說,通常主要有以下兩個解決方案:

1、縮短 Cache 失效時間:我們讓緩存數據的過期時間變短,這樣的話緩存就會從數據庫中加載數據。另外,這種解決辦法對于先操作緩存后操作數據庫的場景不適用。此方案在實際的業務場景中通常 不推薦,本質上治標不治本。

2、增加 Cache 更新重試機制:如果 Cache 服務當前不可用導致緩存刪除失敗的話,我們就隔一段時間進行重試,重試次數可以自己定。如果多次重試還是失敗的話,我們可以把當前更新失敗的 Key 存入隊列中,等緩存服務可用之后,再將緩存中對應的 Key 刪除即可??煽紤]使用消息隊列。此方案算是一種 常用的解決策略,能夠滿足絕大多數業務場景需要。

其實,從本質上而言,緩存方案的規劃設計往往依賴于實際的業務場景需求,畢竟,技術是為業務服務的??赡苡袝r我們引入緩存之后,為了解決短期內的不一致性問題,選擇讓系統設計變得更加復雜的話,完全沒必要。

緩存異常場景

緩存場景模型圖

其實。在實際的場景中,考慮到各種應用異常和業務故障,通常不可能完全使用分布式緩存和數據庫系統來實現線性一致性模型。每一種緩存模式都有其自身的局限性,在某些情況下我們無法獲得順序一致性,或者有時會在緩存和數據庫之間獲得意外延遲。對于筆者在本文中展示的所有的解決方案,依據不同的業務需求總是會遇到高并發的極端情況。因此,對此沒有靈丹妙藥,在選擇解決方案之前了解限制并定義特定的一致性要求。

如果想要實現線性一致性和容錯性,建議最好不要使用緩存策略,可考慮其他的方案。以上為 Redis 緩存系統相關解析,希望對大家有用。

作者:李杰

來源:twt社區

分享到:
標簽:Redis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定