當前位置:首頁 » 硬碟大全 » 一致性緩存圖片
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

一致性緩存圖片

發布時間: 2023-01-14 04:08:23

Ⅰ SpringCache優化、緩存一致性、多級緩存

先記錄一些綱要

1、SpringCache是寫庫之後更新的策略,對緩存一致性的不太友好

2、繼承RedisCacheManager重寫createRedisCache,繼承RedisCache重寫put

3、緩存一致性有兩個方案,一個是先寫庫再刪除緩存、第二個是先刪除緩存再寫庫。

先寫庫再刪除緩存配合超時時間一般沒啥問題,極端的情況遇到緩存失效,線程讀庫和加緩存之間,完成了一次寫庫和刪緩存的操作,導致加的緩存是舊的。總結就是讀中加入了一次寫。A讀庫 B寫庫 B刪緩存 A加緩存。

先刪緩存再寫庫的話,是寫中加入了一次讀。A刪緩存 B讀庫 B加緩存 A寫庫A。這個概率比上面的大。

這兩種方案的問題的解決方式是一樣的,就是延時雙刪策略。即:

刪緩存 寫庫 延時再次刪除緩存(需超過一次讀庫的時間,可以新啟線程完成)

或者 寫庫 刪緩存 延時再次刪除緩存(需超過一次讀庫的時間,可以新啟線程完成)

如果有主從讀寫分離,需要將延時再加上主從同步的時間。

還有個第二次刪除失敗的問題,這個問題可以通過消息中間件,反復嘗試進行。或者通過訂閱binlog,反復進行。

多級緩存可以參考阿里開源的JetCache的實現

後面會給出demo和源碼解析。

Ⅱ 固態硬碟 (SSD) 有緩存和沒有緩存有什麼區別

1、運行速度不同:帶緩存的比不帶緩存的快很多。緩存越大對速度的改善越快。緩存的意思就是剛用過的數據,馬上再用或短時間內再用,會非常快,基本上就是瞬間讀取數據。

2、價格不同:一般來說硬碟是帶緩存的更快些,帶緩存的同容量硬碟價格也是不同,帶有緩存的硬碟要貴上幾十塊錢,因此可以想像得到速度要快些。

固態硬碟使用注意事項

需要注意固態硬碟有寫入壽命,平均起來約為3000次P/E,1P/E為硬碟存儲上限,相當於只能寫滿3000次。

為了減少固態硬碟的寫入數據量,不要將電腦的虛擬內存放到固態硬碟上。

不要將下載軟體的存儲目錄設置為固態硬碟,尤其是下載電影這類大數據量的文件。

以上內容參考網路-固態硬碟

Ⅲ 緩存一致性協議

鎖緩存行有一套協議叫做 緩存一致性協議 。緩存一致性協議有MSI、MESI、MOSI、Synapse、Firefly以及DragonProtocol等等。

MESI分別代表緩存行數據的4中狀態,通過對這四種狀態的切換,來達到對緩存數據進行管理的目的

假設有三個CPU-A、B、C,對應三個緩存分別是cache-a、b、c。在主內存中定義了x的引用值0

單核讀取

MESI優化和引入的問題:各CPU緩存行的狀態是通過消息傳遞來進行的。如果CPU0要對一個在緩存中共享的變數進行寫入,首先需要發送一個失效的消息給到其他緩存了該數據的CPU,並且要等到他們的確認回執。CPU0在這段時間內都會一直處於阻塞狀態,會導致各種各樣的性能問題和穩定性問題。

為了避免阻塞帶來的資源浪費,在CPU中引入了Store Buffer。

CPU在寫入共享數據時,直接把數據寫入到Store Buffer中,同時發送Invalidate消息,然後繼續去處理其他指令。當收到其他所有CPU發送了Invalidate Acknowledge消息時,再將Store Buffer中的數據存儲到Cache Line中,最後再從Cache Line同步到主內存。

Ⅳ 如何保證資料庫緩存的最終一致性

對於互聯網業務來說,傳統的直接訪問資料庫方式,主要通過數據分片、一主多從等方式來扛住讀寫流量,但隨著數據量的積累和流量的激增,僅依賴資料庫來承接所有流量,不僅成本高、效率低、而且還伴隨著穩定性降低的風險。

鑒於大部分業務通常是讀多寫少(讀取頻率遠遠高於更新頻率),甚至存在讀操作數量高出寫操作多個數量級的情況。因此, 在架構設計中,常採用增加緩存層來提高系統的響應能力 ,提升數據讀寫性能、減少資料庫訪問壓力,從而提升業務的穩定性和訪問體驗。

根據 CAP 原理,分布式系統在可用性、一致性和分區容錯性上無法兼得,通常由於分區容錯無法避免,所以一致性和可用性難以同時成立。對於緩存系統來說, 如何保證其數據一致性是一個在應用緩存的同時不得不解決的問題 。

需要明確的是,緩存系統的數據一致性通常包括持久化層和緩存層的一致性、以及多級緩存之間的一致性,這里我們僅討論前者。持久化層和緩存層的一致性問題也通常被稱為雙寫一致性問題,「雙寫」意為數據既在資料庫中保存一份,也在緩存中保存一份。

對於一致性來說,包含強一致性和弱一致性 ,強一致性保證寫入後立即可以讀取,弱一致性則不保證立即可以讀取寫入後的值,而是盡可能的保證在經過一定時間後可以讀取到,在弱一致性中應用最為廣泛的模型則是最終一致性模型,即保證在一定時間之後寫入和讀取達到一致的狀態。對於應用緩存的大部分場景來說,追求的則是最終一致性,少部分對數據一致性要求極高的場景則會追求強一致性。

為了達到最終一致性,針對不同的場景,業界逐步形成了下面這幾種應用緩存的策略。


1

Cache-Aside


Cache-Aside 意為旁路緩存模式,是應用最為廣泛的一種緩存策略。下面的圖示展示了它的讀寫流程,來看看它是如何保證最終一致性的。在讀請求中,首先請求緩存,若緩存命中(cache hit),則直接返回緩存中的數據;若緩存未命中(cache miss),則查詢資料庫並將查詢結果更新至緩存,然後返回查詢出的數據(demand-filled look-aside )。在寫請求中,先更新資料庫,再刪除緩存(write-invalidate)。


1、為什麼刪除緩存,而不是更新緩存?

在 Cache-Aside 中,對於讀請求的處理比較容易理解,但在寫請求中,可能會有讀者提出疑問,為什麼要刪除緩存,而不是更新緩存?站在符合直覺的角度來看,更新緩存是一個容易被理解的方案,但站在性能和安全的角度,更新緩存則可能會導致一些不好的後果。

首先是性能 ,當該緩存對應的結果需要消耗大量的計算過程才能得到時,比如需要訪問多張資料庫表並聯合計算,那麼在寫操作中更新緩存的動作將會是一筆不小的開銷。同時,當寫操作較多時,可能也會存在剛更新的緩存還沒有被讀取到,又再次被更新的情況(這常被稱為緩存擾動),顯然,這樣的更新是白白消耗機器性能的,會導致緩存利用率不高。

而等到讀請求未命中緩存時再去更新,也符合懶載入的思路,需要時再進行計算。刪除緩存的操作不僅是冪等的,可以在發生異常時重試,而且寫-刪除和讀-更新在語義上更加對稱。

其次是安全 ,在並發場景下,在寫請求中更新緩存可能會引發數據的不一致問題。參考下面的圖示,若存在兩個來自不同線程的寫請求,首先來自線程 1 的寫請求更新了資料庫(step 1),接著來自線程 2 的寫請求再次更新了資料庫(step 3),但由於網路延遲等原因,線程 1 可能會晚於線程 2 更新緩存(step 4 晚於 step 3),那麼這樣便會導致最終寫入資料庫的結果是來自線程 2 的新值,寫入緩存的結果是來自線程 1 的舊值,即緩存落後於資料庫,此時再有讀請求命中緩存(step 5),讀取到的便是舊值。


2、為什麼先更新資料庫,而不是先刪除緩存?

另外,有讀者也會對更新資料庫和刪除緩存的時序產生疑問,那麼為什麼不先刪除緩存,再更新資料庫呢?在單線程下,這種方案看似具有一定合理性,這種合理性體現在刪除緩存成功。

但更新資料庫失敗的場景下,盡管緩存被刪除了,下次讀操作時,仍能將正確的數據寫回緩存,相對於 Cache-Aside 中更新資料庫成功,刪除緩存失敗的場景來說,先刪除緩存的方案似乎更合理一些。那麼,先刪除緩存有什麼問題呢?

問題仍然出現在並發場景下,首先來自線程 1 的寫請求刪除了緩存(step 1),接著來自線程 2 的讀請求由於緩存的刪除導致緩存未命中,根據 Cache-Aside 模式,線程 2 繼而查詢資料庫(step 2),但由於寫請求通常慢於讀請求,線程 1 更新資料庫的操作可能會晚於線程 2 查詢資料庫後更新緩存的操作(step 4 晚於 step 3),那麼這樣便會導致最終寫入緩存的結果是來自線程 2 中查詢到的舊值,而寫入資料庫的結果是來自線程 1 的新值,即緩存落後於資料庫,此時再有讀請求命中緩存( step 5 ),讀取到的便是舊值。


另外,先刪除緩存,由於緩存中數據缺失,加劇資料庫的請求壓力,可能會增大緩存穿透出現的概率。

3、如果選擇先刪除緩存,再更新資料庫,那如何解決一致性問題呢?

為了避免「先刪除緩存,再更新資料庫」這一方案在讀寫並發時可能帶來的緩存臟數據,業界又提出了延時雙刪的策略,即在更新資料庫之後,延遲一段時間再次刪除緩存,為了保證第二次刪除緩存的時間點在讀請求更新緩存之後,這個延遲時間的經驗值通常應稍大於業務中讀請求的耗時。

延遲的實現可以在代碼中 sleep 或採用延遲隊列。顯而易見的是,無論這個值如何預估,都很難和讀請求的完成時間點准確銜接,這也是延時雙刪被詬病的主要原因。


4、那麼 Cache-Aside 存在數據不一致的可能嗎?

在 Cache-Aside 中,也存在數據不一致的可能性。在下面的讀寫並發場景下,首先來自線程 1 的讀請求在未命中緩存的情況下查詢資料庫(step 1),接著來自線程 2 的寫請求更新資料庫(step 2),但由於一些極端原因,線程 1 中讀請求的更新緩存操作晚於線程 2 中寫請求的刪除緩存的操作(step 4 晚於 step 3),那麼這樣便會導致最終寫入緩存中的是來自線程 1 的舊值,而寫入資料庫中的是來自線程 2 的新值,即緩存落後於資料庫,此時再有讀請求命中緩存(step 5),讀取到的便是舊值。

這種場景的出現,不僅需要緩存失效且讀寫並發執行,而且還需要讀請求查詢資料庫的執行早於寫請求更新資料庫,同時讀請求的執行完成晚於寫請求。足以見得,這種 不一致場景產生的條件非常嚴格,在實際的生產中出現的可能性較小 。


除此之外,在並發環境下,Cache-Aside 中也存在讀請求命中緩存的時間點在寫請求更新資料庫之後,刪除緩存之前,這樣也會導致讀請求查詢到的緩存落後於資料庫的情況。


雖然在下一次讀請求中,緩存會被更新,但如果業務層面對這種情況的容忍度較低,那麼可以採用加鎖在寫請求中保證「更新資料庫&刪除緩存」的串列執行為原子性操作(同理也可對讀請求中緩存的更新加鎖)。 加鎖勢必會導致吞吐量的下降,故採取加鎖的方案應該對性能的損耗有所預期。


2

補償機制


我們在上面提到了,在 Cache-Aside 中可能存在更新資料庫成功,但刪除緩存失敗的場景,如果發生這種情況,那麼便會導致緩存中的數據落後於資料庫,產生數據的不一致的問題。

其實,不僅 Cache-Aside 存在這樣的問題,在延時雙刪等策略中也存在這樣的問題。針對可能出現的刪除失敗問題,目前業界主要有以下幾種補償機制。

1、刪除重試機制

由於同步重試刪除在性能上會影響吞吐量,所以常通過引入消息隊列,將刪除失敗的緩存對應的 key 放入消息隊列中,在對應的消費者中獲取刪除失敗的 key ,非同步重試刪除。這種方法在實現上相對簡單,但由於刪除失敗後的邏輯需要基於業務代碼的 trigger 來觸發 ,對業務代碼具有一定入侵性。


鑒於上述方案對業務代碼具有一定入侵性,所以需要一種更加優雅的解決方案,讓緩存刪除失敗的補償機制運行在背後,盡量少的耦合於業務代碼。一個簡單的思路是通過後台任務使用更新時間戳或者版本作為對比獲取資料庫的增量數據更新至緩存中,這種方式在小規模數據的場景可以起到一定作用,但其擴展性、穩定性都有所欠缺。

一個相對成熟的方案是基於 MySQL 資料庫增量日誌進行解析和消費,這里較為流行的是阿里巴巴開源的作為 MySQL binlog 增量獲取和解析的組件 canal(類似的開源組件還有 Maxwell、Databus 等)。

canal sever 模擬 MySQL slave 的交互協議,偽裝為 MySQL slave,向 MySQL master 發送 mp 協議,MySQL master 收到 mp 請求,開始推送 binary log 給 slave (即 canal sever ),canal sever 解析 binary log 對象(原始為 byte 流),可由 canal client 拉取進行消費,同時 canal server 也默認支持將變更記錄投遞到 MQ 系統中,主動推送給其他系統進行消費。

在 ack 機制的加持下,不管是推送還是拉取,都可以有效的保證數據按照預期被消費。當前版本的 canal 支持的 MQ 有 Kafka 或者 RocketMQ。另外, canal 依賴 ZooKeeper 作為分布式協調組件來實現 HA ,canal 的 HA 分為兩個部分:


那麼,針對緩存的刪除操作便可以在 canal client 或 consumer 中編寫相關業務代碼來完成。這樣,結合資料庫日誌增量解析消費的方案以及 Cache-Aside 模型,在讀請求中未命中緩存時更新緩存(通常這里會涉及到復雜的業務邏輯),在寫請求更新資料庫後刪除緩存,並基於日誌增量解析來補償資料庫更新時可能的緩存刪除失敗問題,在絕大多數場景下,可以有效的保證緩存的最終一致性。

另外需要注意的是,還應該隔離事務與緩存,確保資料庫入庫後再進行緩存的刪除操作。 比如考慮到資料庫的主從架構,主從同步及讀從寫主的場景下,可能會造成讀取到從庫的舊數據後便更新了緩存,導致緩存落後於資料庫的問題,這就要求對緩存的刪除應該確保在資料庫操作完成之後。所以,基於 binlog 增量日誌進行數據同步的方案,可以通過選擇解析從節點的 binlog,來避免主從同步下刪除緩存過早的問題。

3、數據傳輸服務 DTS


3

Read-Through


Read-Through 意為讀穿透模式,它的流程和 Cache-Aside 類似,不同點在於 Read-Through 中多了一個訪問控制層,讀請求只和該訪問控制層進行交互,而背後緩存命中與否的邏輯則由訪問控制層與數據源進行交互,業務層的實現會更加簡潔,並且對於緩存層及持久化層交互的封裝程度更高,更易於移植。


4

Write-Through


Write-Through 意為直寫模式,對於 Write-Through 直寫模式來說,它也增加了訪問控制層來提供更高程度的封裝。不同於 Cache-Aside 的是,Write-Through 直寫模式在寫請求更新資料庫之後,並不會刪除緩存,而是更新緩存。


這種方式的 優勢在於讀請求過程簡單 ,不需要查詢資料庫更新緩存等操作。但其劣勢也非常明顯,除了上面我們提到的更新資料庫再更新緩存的弊端之外,這種方案還會造成更新效率低,並且兩個寫操作任何一次寫失敗都會造成數據不一致。

如果要使用這種方案, 最好可以將這兩個操作作為事務處理,可以同時失敗或者同時成功,支持回滾,並且防止並發環境下的不一致 。另外,為了防止緩存擾動的頻發,也可以給緩存增加 TTL 來緩解。

站在可行性的角度,不管是 Write-Through 模式還是 Cache-Aside 模式,理想狀況下都可以通過分布式事務保證緩存層數據與持久化層數據的一致性,但在實際項目中,大多都對一致性的要求存在一些寬容度,所以在方案上往往有所折衷。

Write-Through 直寫模式適合寫操作較多,並且對一致性要求較高的場景,在應用 Write-Through 模式時,也需要通過一定的補償機制來解決它的問題。首先,在並發環境下,我們前面提到了先更新資料庫,再更新緩存會導致緩存和資料庫的不一致,那麼先更新緩存,再更新資料庫呢?

這樣的操作時序仍然會導致下面這樣線程 1 先更新緩存,最後更新資料庫的情況,即由於線程 1 和 線程 2 的執行不確定性導致資料庫和緩存的不一致。這種由於線程競爭導致的緩存不一致,可以通過分布式鎖解決,保證對緩存和資料庫的操作僅能由同一個線程完成。對於沒有拿到鎖的線程,一是通過鎖的 timeout 時間進行控制,二是將請求暫存在消息隊列中順序消費。


在下面這種並發執行場景下,來自線程 1 的寫請求更新了資料庫,接著來自線程 2 的讀請求命中緩存,接著線程 1 才更新緩存,這樣便會導致線程 2 讀取到的緩存落後於資料庫。同理,先更新緩存後更新資料庫在寫請求和讀請求並發時,也會出現類似的問題。面對這種場景,我們也可以加鎖解決。


另在,在 Write-Through 模式下,不管是先更新緩存還是先更新資料庫,都存在更新緩存或者更新資料庫失敗的情況,上面提到的重試機制和補償機制在這里也是奏效的。


5

Write-Behind


Write behind 意為非同步回寫模式,它也具有類似 Read-Through/Write-Through 的訪問控制層,不同的是,Write behind 在處理寫請求時,只更新緩存而不更新資料庫,對於資料庫的更新,則是通過批量非同步更新的方式進行的,批量寫入的時間點可以選在資料庫負載較低的時間進行。

在 Write-Behind 模式下,寫請求延遲較低,減輕了資料庫的壓力,具有較好的吞吐性。但資料庫和緩存的一致性較弱,比如當更新的數據還未被寫入資料庫時,直接從資料庫中查詢數據是落後於緩存的。同時,緩存的負載較大,如果緩存宕機會導致數據丟失,所以需要做好緩存的高可用。顯然,Write behind 模式下適合大量寫操作的場景,常用於電商秒殺場景中庫存的扣減。


6

Write-Around


如果一些非核心業務,對一致性的要求較弱,可以選擇在 cache aside 讀模式下增加一個緩存過期時間,在寫請求中僅僅更新資料庫,不做任何刪除或更新緩存的操作,這樣,緩存僅能通過過期時間失效。這種方案實現簡單,但緩存中的數據和資料庫數據一致性較差,往往會造成用戶的體驗較差,應慎重選擇。


7

總結


在解決緩存一致性的過程中,有多種途徑可以保證緩存的最終一致性,應該根據場景來設計合適的方案,讀多寫少的場景下,可以選擇採用「Cache-Aside 結合消費資料庫日誌做補償」的方案,寫多的場景下,可以選擇採用「Write-Through 結合分布式鎖」的方案 ,寫多的極端場景下,可以選擇採用「Write-Behind」的方案。

Ⅳ 緩存一致性指的是什麼

首先明白什麼是緩存,緩存是介於物理存儲與CPU處理之間的一段內存空間,主要用於存儲從物理存儲讀出、或者要寫入的數據,這需要硬體或者軟體支持。如果讀取或寫入物理存儲中的一個位元組或一段數據,如果沒有緩存,那麼每次的讀寫請求都會直接訪問物理存儲,而物理存儲的速度一般都比較慢,而且物理定位也比較慢,緩存使用後,可以一次性讀出需要的數據相鄰的數據,暫時存儲在緩存中,下面如果還要讀取,而這部分數據已經在緩存了,就不需要再去讀取物理存儲,同樣,如果是寫操作,可以先將需要寫入的數據暫時保存在緩存中,等到緩存過期或者強行清空時,再一次寫入物理存儲。這樣可以把多次的物理存儲訪問,變成一次物理存儲的訪問,提高訪問效率。具體的操作演算法這里不多作闡述。

緩存的一致性就是指緩存中的數據是否和目標存儲中的數據是一樣的,也就是說緩存中已經修改得數據是否已經保存到了物理存儲中,物理存儲中已經被修改得內容,是否與緩存的內容是一樣的。這就是一致性的概念。

Ⅵ chcahe 如何保證分布式緩存數據一致性

VPLEX的技術核心是「分布式緩存一致性」,下圖則是「分布式緩存一致性」技術的工作機制示意:正是因為這項核心技術優勢,使得VPLEX方案和目前所有廠商的虛擬化方案截然不同,並能夠實現異地的數據中心整合。對跨數據中心的所有負載實現跨引擎的平攤或者實時遷移,來自任何一個主機的I/O請求可以通過任何一個引擎得到響應。
緩存一致性的記錄目錄使用少量的元數據,記錄下哪個數據塊屬於哪個引擎更新的,以及在何時更新過,並通過4K大小的數據塊告訴在集群中的所有其他的引擎。在整個過程中實際發生的溝通過程,遠遠比實際上正在更新數據塊少很多。

分布式緩存一致性數據流示意圖:上方是一個目錄,記錄下左側的主機讀取緩存A的操作,並分發給所有引擎,右側主機需要讀取該數據塊時,會先通過目錄查詢,確定該數據塊所屬的引擎位置,讀取請求會直接發送給引擎,並直接從數據塊所在的緩存上讀取。
當一個讀請求進入時,VPLEX會自動檢查目錄,查找該數據塊所屬的引擎,一旦確定該數據塊所屬的引擎位置,讀的請求會直接發送給該引擎。一旦一個寫入動作完成,並且目錄表被修改,這時另一個讀請求從另一個引擎過來,VPLEX會檢查目錄,並且直接從該引擎的緩存上讀取。如果該數據仍然在緩存上,則完全沒必要去磁碟上讀取。
如上圖,來自圖中左側主機的操作,由Cache A服務,會記錄一個更新狀態,並分發給所有所有引擎知道。如果讀取的需求來自最右側的伺服器,首先通過目錄查詢。通過這種技術可以實現所有引擎一致性工作,而且這個技術不僅可以跨引擎還可以跨VPLEX集群,而VPLEX集群可以跨區域,因此緩存一致性也可以跨區域部署。

分布式緩存一致性技術使VPLEX相比傳統的虛擬化方案擁有更高的性能和可靠性,並實現異地數據中心的虛擬化整合
對傳統的虛擬化架構來說,如果虛擬化的I/O集群中有一個節點壞了,那麼性能就會降低一半,而且實際情況降低不止一半。因為壞了一個節點,這個節點緩存一般會被寫進去。因為沒有緩存,操作會直接寫到硬碟里。如果圖中中心這個節點壞掉,那主機所有的可用性都沒有了。而VPLEX如果有一個引擎或者一個控制器壞掉了,那這個引擎的負載會均攤到其他活動引擎上。這樣總體來講用戶可以維持可預知性能,性能降低也不那麼明顯。

Ⅶ 分布式緩存中,哈希取余分區和一致性哈希分區有什麼區別

環割法(一致性 hash)環割法的原理如下:

1. 初始化的時候生成分片數量 X × 環割數量 N 的固定方式編號的字元串,例如 SHARD-1-NODE-1,並計算所有 X×N 個字元串的所有 hash 值。

2. 將所有計算出來的 hash 值放到一個排序的 Map 中,並將其中的所有元素進行排序。

3. 輸入字元串的時候計算輸入字元串的 hash 值,查看 hash 值介於哪兩個元素之間,取小於 hash 值的那個元素對應的分片為數據的分片。

數據比較

下面將通過測試對環割法和跳躍法的性能及均衡性進行對比,說明 DBLE 為何使用跳躍法代替了環割法。

  • 數據源:現場數據 350595 條

  • 測試經過:

    1. 通過各自的測試方法執行對於測試數據的分片任務。

    2. 測試方法:記錄分片結果的方差;記錄從開始分片至分片結束的時間;記錄分片結果與平均數的最大差值。

    3. 由於在求模法 PartitionByString 的方法中要求分片的數量是 1024 的因數,所以測試過程只能使用 2 的指數形式進行測試,並在 PartitionByString 方法進行測試的時候不對於 MAC 地址進行截斷,取全量長度進行測試。

Ⅷ 緩存一致性

在現代的 CPU(大多數)上,所有的內存訪問都需要通過層層的緩存來進行。CPU 的讀 / 寫(以及取指令)單元正常情況下甚至都不能直接訪問內存——這是物理結構決定的;CPU 都沒有管腳直接連到內存。相反,CPU 和一級緩存(L1 Cache)通訊,而一級緩存才能和內存通訊。大約二十年前,一級緩存可以直接和內存傳輸數據。如今,更多級別的緩存加入到設計中,一級緩存已經不能直接和內存通訊了,它和二級緩存通訊——而二級緩存才能和內存通訊。或者還可能有三級緩存。

緩存是分「段」(line)的,一個段對應一塊存儲空間,大小是 32、64或128位元組,每個緩存段知道自己對應什麼范圍的物理內存地址。

當 CPU 看到一條讀內存的指令時,它會把內存地址傳遞給一級數據緩存。一級數據緩存會檢查它是否有這個內存地址對應的緩存段。如果沒有,它會把整個緩存段從內存(或者從更高一級的緩存,如果有的話)中載入進來。是的,一次載入整個緩存段,這是基於這樣一個假設:內存訪問傾向於本地化(localized),如果我們當前需要某個地址的數據,那麼很可能我們馬上要訪問它的鄰近地址。一旦緩存段被載入到緩存中,讀指令就可以正常進行讀取。

如果我們只處理讀操作,那麼事情會很簡單,因為所有級別的緩存都遵守以下規律—— 在任意時刻,任意級別緩存中的緩存段的內容,等同於它對應的內存中的內容。

一旦我們允許寫操作,事情就變得復雜一點了。這里有兩種基本的寫模式:直寫(write-through)和回寫(write-back)。直寫更簡單一點:我們透過本級緩存,直接把數據寫到下一級緩存(或直接到內存)中,如果對應的段被緩存了,我們同時更新緩存中的內容(甚至直接丟棄),就這么簡單。這也遵守前面的定律: 緩存中的段永遠和它對應的內存內容匹配。

回寫模式就有點復雜了。緩存不會立即把寫操作傳遞到下一級,而是僅修改本級緩存中的數據,並且把對應的緩存段標記為「臟」段。臟段會觸發回寫,也就是把裡面的內容寫到對應的內存或下一級緩存中。回寫後,臟段又變「干凈」了。當一個臟段被丟棄的時候,總是先要進行一次回寫。回寫所遵循的規律有點不同。 當所有的臟段被回寫後,任意級別緩存中的緩存段的內容,等同於它對應的內存中的內容。

換句話說,回寫模式的定律中,我們去掉了「在任意時刻」這個修飾語,代之以弱化一點的條件:要麼緩存段的內容和內存一致(如果緩存段是干凈的話),要麼緩存段中的內容最終要回寫到內存中(對於臟緩存段來說)。

只要系統只有一個 CPU 核在工作,一切都沒問題。如果有多個核,每個核又都有自己的緩存,那麼我們就遇到問題了,因為如果一個 CPU 緩存了某塊內存,那麼在其他 CPU 修改這塊內存的時候,我們希望得到通知。系統的內存在各個 CPU 之間無法做到與生俱來的同步,我們需要一個大家都能遵守的方法來達到同步的目的。

緩存一致性協議有多種,但是日常處理的大多數計算機設備使用的都屬於「窺探(snooping)」協議。

窺探」背後的基本思想是,所有內存傳輸都發生在一條共享的匯流排上,而所有的處理器都能看到這條匯流排:緩存本身是獨立的,但是內存是共享資源,所有的內存訪問都要經過仲裁(arbitrate):同一個指令周期中,只有一個緩存可以讀寫內存。窺探協議的思想是,緩存不僅僅在做內存傳輸的時候才和匯流排打交道,而是不停地在窺探匯流排上發生的數據交換,跟蹤其他緩存在做什麼。所以當一個緩存代表它所屬的處理器去讀寫內存時,其他處理器都會得到通知,它們以此來使自己的緩存保持同步。只要某個處理器一寫內存,其他處理器馬上就知道這塊內存在它們自己的緩存中對應的段已經失效。

在直寫模式下,這是很直接的,因為寫操作一旦發生,它的效果馬上會被「公布」出去。但是如果混著回寫模式,就有問題了。因為有可能在寫指令執行過後很久,數據才會被真正回寫到物理內存中——在這段時間內,其他處理器的緩存也可能會傻乎乎地去寫同一塊內存地址,導致沖突。在回寫模型中,簡單把內存寫操作的信息廣播給其他處理器是不夠的,我們需要做的是,在修改本地緩存之前,就要告知其他處理器。

MESI 是四種緩存段狀態的首字母縮寫,任何多核系統中的緩存段都處於這四種狀態之一。

從CPU讀寫角度來說:

上圖的切換解釋:

緩存的一致性消息傳遞是要時間的,這就使其切換時會產生延遲。當一個緩存被切換狀態時其他緩存收到消息完成各自的切換並且發出回應消息這么一長串的時間中CPU都會等待所有緩存響應完成。可能出現的阻塞都會導致各種各樣的性能問題和穩定性問題。

比如你需要修改本地緩存中的一條信息,那麼你必須將I(無效)狀態通知到其他擁有該緩存數據的CPU緩存中,並且等待確認。等待確認的過程會阻塞處理器,這會降低處理器的性能。因為這個等待遠遠比一個指令的執行時間長的多。

為了避免這種CPU運算能力的浪費,Store Bufferes被引入使用。處理器把它想要寫入到主存的值寫到緩存,然後繼續去處理其他事情。當所有失效確認(Invalidate Acknowledge)都接收到時,數據才會最終被提交。

執行失效也不是一個簡單的操作,它需要處理器去處理。另外,存儲緩存(Store Buffers)並不是無窮大的,所以處理器有時需要等待失效確認的返回。這兩個操作都會使得性能大幅降低。為了應付這種情況,引入了失效隊列——對於所有的收到的Invalidate請求,Invalidate Acknowlege消息必須立刻發送,Invalidate並不真正執行,而是被放在一個特殊的隊列中,在方便的時候才會去執行,處理器不會發送任何消息給所處理的緩存條目,直到它處理Invalidate。

Ⅸ 固態硬碟有緩存和沒有緩存有什麼區別

有外部緩存優勢是性能一致性更好,也就是空盤和滿盤性能差距不會太大,缺點是掉電容易丟數據,需要額外的掉電保護電路和在固件中加入掉電保護邏輯。


無緩存優勢是掉電相對不容易丟失數據,以及更好的成本控制,缺點就是4k性能會比較難看,而且性能一致性不夠好,不適合高負載的場合,比如資料庫伺服器等。


不過總之日常家用沒有任何區別就是了,東芝Q系列無緩存設計只是東芝對自家顆粒性能的自信以及節約成本的表現而已,家用不用糾結這些。

SSD的緩存分為兩種,一種是DRAM緩存,另一種是SLC緩存。

DRAM緩存是使用DRAM晶元(也就是內存顆粒)作為緩存,固態硬碟上的DRAM晶元一般不會用來直接緩存數據,DRAM主要是用來儲存FTL緩存映射表,這個映射表表達了快閃記憶體單元物理地址同文件系統邏輯地址之間的關系。

所有固態硬碟都有FTL映射表,不同之處在於無DRAM的SSD通常把表的主體放在快閃記憶體中,隨用隨取,效率較低。

高端固態硬碟會把FTL映射表完整地放入DRAM緩存中,通常需要按照1GB:1MB的比例配置DRAM緩存。

有些固態硬碟為了在節省成本的同時可以把DRAM緩存作為宣傳籌碼,選擇了不管何種容量都只配備256MB緩存的方式,這種情況下只能直接管理256GB的快閃記憶體空間,依然存在一些不足。

所以除了觀察固態硬碟是否搭載DRAM緩存晶元之外,大家還應通過晶元表面的編號查詢它的具體容量,確保買到的是按照1GB:1MB完整配備DRAM緩存的高性能產品。

目前SLC緩存基本所有TLC固態硬碟都有。目前大部分固態硬碟的SLC緩存,並不是真的使用了SLC顆粒作為緩存,而是使用TLC模擬SLC來提升連續讀寫速度。

TLC的讀寫速度較慢,為了提升連續寫入時固態硬碟的表現,主控會先將數據寫入SLC緩存中,當緩存寫滿後,才會像TLC快閃記憶體中寫入,這樣就會造成寫入速度的斷崖式下跌,此時的速度被稱為緩外速度,緩外速度的高低也是衡量SSD性能的重要指標。

假設一塊SSD配備10GB的SLC緩存,我向固態硬碟中寫入20GB的文件時,前10GB的數據先被寫入到緩存中,後10GB的數據則會直接寫入到TLC中。速度會呈現出下圖這種形式:

雖然日常不會經常向SSD中反復寫入大文件,但是緩存外寫入性能直接反映了NAND顆粒的品質以及GC策略的優劣。緩外速度高的SSD比速度低的盤質量要好。