最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

分布式技術(shù)原理與實(shí)戰(zhàn)45講--第35講:經(jīng)典問題:先更新數(shù)據(jù)庫,還是先更新緩存

2023-02-24 16:36 作者:gzqhero  | 我要投稿

上一課時分享了緩存使用中的幾個問題場景:緩存穿透、緩存擊穿和緩存雪崩,這幾個問題聚焦的是緩存本身的穩(wěn)定性,包括緩存集群和緩存的數(shù)據(jù),除了這些,緩存應(yīng)用中,緩存和上下游系統(tǒng)的數(shù)據(jù)同步也很重要。這一課時,我們來學(xué)習(xí)緩存應(yīng)用中的另一個高頻問題:應(yīng)用緩存以后,緩存和數(shù)據(jù)庫何時同步。

數(shù)據(jù)不一致問題

我們知道,除了少部分配置信息類緩存,比如業(yè)務(wù)中的黑白名單信息、頁面展示配置等,大部分緩存應(yīng)用一般是作為前端請求和持久化存儲的中間層,承擔(dān)前端的海量請求。

緩存層數(shù)據(jù)庫存儲層 是獨(dú)立的系統(tǒng),我們在數(shù)據(jù)更新的時候,最理想的情況當(dāng)然是緩存和數(shù)據(jù)庫同時更新成功。但是由于緩存和數(shù)據(jù)庫是分開的,無法做到原子性的同時進(jìn)行數(shù)據(jù)修改,可能出現(xiàn)緩存更新失敗,或者數(shù)據(jù)庫更新失敗的情況,這時候會出現(xiàn)數(shù)據(jù)不一致,影響前端業(yè)務(wù)。

以電商中的商品服務(wù)為例,針對 C 端用戶的大部分請求都是通過緩存來承載的,假設(shè)某次更新操作將商品詳情 A 的價格從 1000 元更新為 1200 元,數(shù)據(jù)庫更新成功,但是緩存更新失敗。這時候就會出現(xiàn) C 端用戶在查看商品詳情時,看到的還是 1000 元,實(shí)際下單時可能是別的價格,最終會影響用戶的購買決策,影響平臺的購物體驗(yàn)。

可以看到,在使用緩存時,如果不能很好地控制緩存和數(shù)據(jù)庫的一致性,可能會出現(xiàn)非常多的業(yè)務(wù)問題。

更新緩存有哪些方式

緩存更新方案是通過對更新緩存和更新數(shù)據(jù)庫這兩個操作的設(shè)計(jì),來實(shí)現(xiàn)數(shù)據(jù)的最終一致性,避免出現(xiàn)業(yè)務(wù)問題。

先來看一下什么時候創(chuàng)建緩存,前端請求的讀操作先從緩存中查詢數(shù)據(jù),如果沒有命中數(shù)據(jù),則查詢數(shù)據(jù)庫,從數(shù)據(jù)庫查詢成功后,返回結(jié)果,同時更新緩存,方便下次操作。

在數(shù)據(jù)不發(fā)生變更的情況下,這種方式?jīng)]有問題,如果數(shù)據(jù)發(fā)生了更新操作,就必須要考慮如何操作緩存,保證一致性。

先更新數(shù)據(jù)庫,再更新緩存

先來看第一種方式,在寫操作中,先更新數(shù)據(jù)庫,更新成功后,再更新緩存。這種方式最容易想到,但是問題也很明顯,數(shù)據(jù)庫更新成功以后,由于緩存和數(shù)據(jù)庫是分布式的,更新緩存可能會失敗,就會出現(xiàn)上面例子中的問題,數(shù)據(jù)庫是新的,但緩存中數(shù)據(jù)是舊的,出現(xiàn)不一致的情況。

先刪緩存,再更新數(shù)據(jù)庫

這種方案是在數(shù)據(jù)更新時,首先刪除緩存,再更新數(shù)據(jù)庫,這樣可以在一定程度上避免數(shù)據(jù)不一致的情況。

現(xiàn)在考慮一個并發(fā)場景,假如某次的更新操作,更新了商品詳情 A 的價格,線程 A 進(jìn)行更新時失效了緩存數(shù)據(jù),線程 B 此時發(fā)起一次查詢,發(fā)現(xiàn)緩存為空,于是查詢數(shù)據(jù)庫并更新緩存,然后線程 A 更新數(shù)據(jù)庫為新的價格。

在這種并發(fā)操作下,緩存的數(shù)據(jù)仍然是舊的,出現(xiàn)業(yè)務(wù)不一致。

先更新數(shù)據(jù)庫,再刪緩存

這個是經(jīng)典的緩存 + 數(shù)據(jù)庫讀寫的模式,有些資料稱它為 Cache Aside 方案。具體操作是這樣的:讀的時候,先讀緩存,緩存沒有的話,那么就讀數(shù)據(jù)庫,然后取出數(shù)據(jù)后放入緩存,同時返回響應(yīng),更新的時候,先更新數(shù)據(jù)庫,數(shù)據(jù)庫更新成功之后再刪除緩存。

為什么說這種方式經(jīng)典呢?

在 Cache Aside 方案中,調(diào)整了數(shù)據(jù)庫更新和緩存失效的順序,先更新數(shù)據(jù)庫,再失效緩存。

目前大部分業(yè)務(wù)場景中都應(yīng)用了讀寫分離,如果先刪除緩存,在讀寫并發(fā)時,可能出現(xiàn)數(shù)據(jù)不一致。考慮這種情況:

  • 線程 A 刪除緩存,然后更新數(shù)據(jù)庫主庫;

  • 線程 B 讀取緩存,沒有讀到,查詢從庫,并且設(shè)置緩存為從庫數(shù)據(jù);

  • 主庫和從庫同步。

在這種情況下,緩存里的數(shù)據(jù)就是舊的,所以建議先更新數(shù)據(jù)庫,再失效緩存。當(dāng)然,在 Cache Aside 方案中,也存在刪除緩存失敗的可能,因?yàn)榫彺鎰h除操作比較輕量級,可以通過多次重試等來解決,你也可以考慮下有沒有其他的方案來保證。

對緩存更新的思考

為什么刪除而不是更新緩存

現(xiàn)在思考一個問題,為什么是刪除緩存,而不是更新緩存呢?刪除一個數(shù)據(jù),相比更新一個數(shù)據(jù)更加輕量級,出問題的概率更小。

在實(shí)際業(yè)務(wù)中,緩存的數(shù)據(jù)可能不是直接來自數(shù)據(jù)庫表,也許來自多張底層數(shù)據(jù)表的聚合。比如上面提到的商品詳情信息,在底層可能會關(guān)聯(lián)商品表、價格表、庫存表等,如果更新了一個價格字段,那么就要更新整個數(shù)據(jù)庫,還要關(guān)聯(lián)的去查詢和匯總各個周邊業(yè)務(wù)系統(tǒng)的數(shù)據(jù),這個操作會非常耗時。

從另外一個角度,不是所有的緩存數(shù)據(jù)都是頻繁訪問的,更新后的緩存可能會長時間不被訪問,所以說,從計(jì)算資源和整體性能的考慮,更新的時候刪除緩存,等到下次查詢命中再填充緩存,是一個更好的方案。

系統(tǒng)設(shè)計(jì)中有一個思想叫 Lazy Loading,適用于那些加載代價大的操作,刪除緩存而不是更新緩存,就是懶加載思想的一個應(yīng)用。

多級緩存如何更新

再看一個實(shí)際應(yīng)用中的問題,多級緩存如何更新?

多級緩存是系統(tǒng)中一個常用的設(shè)計(jì),我們在第 32 課時“緩存分類”中提過,服務(wù)端緩存分為 應(yīng)用內(nèi)緩存外部緩存,比如在電商的商品信息展示中,可能會有多級緩存協(xié)同。

那么多級緩存之間如何同步數(shù)據(jù)呢?

常見的方案是通過消息隊(duì)列通知的方式,也就是在數(shù)據(jù)庫更新后,通過事務(wù)性消息隊(duì)列加監(jiān)聽的方式,失效對應(yīng)的緩存。

多級緩存比較難保證數(shù)據(jù)一致性,通常用在對數(shù)據(jù)一致性不敏感的業(yè)務(wù)中,比如新聞資訊類、電商的用戶評論模塊等。

上面的內(nèi)容是幾種常用的緩存和數(shù)據(jù)庫的雙寫一致性方案,大家在開發(fā)中肯定應(yīng)用過設(shè)計(jì)模式,這些緩存應(yīng)用套路和設(shè)計(jì)模式一樣,是前人在大量工程開發(fā)中的總結(jié),是一個通用的解決范式。

在具體業(yè)務(wù)中,還是需要有針對性地進(jìn)行設(shè)計(jì),比如通過給數(shù)據(jù)添加版本號,或者通過時間戳 + 業(yè)務(wù)主鍵的方式,控制緩存的數(shù)據(jù)版本實(shí)現(xiàn)最終一致性。

另外還可以通過我們在第 32 課時“RocketMQ 應(yīng)用”中講過的 Binlog 分發(fā)方式,通過 Binlog 異步更新緩存。

總結(jié)

這一課時我們探討了緩存和數(shù)據(jù)庫一致性的問題,包括業(yè)務(wù)開發(fā)中如何通過控制更新緩存和數(shù)據(jù)庫的時序,來盡量避免最終一致性問題。在專欄的第 1 課時就討論過分布式系統(tǒng)的 CAP 理論,經(jīng)過這么長時間的學(xué)習(xí),你是否對 CAP 理論中的不可能三角有了更深的理解呢?

在你負(fù)責(zé)的項(xiàng)目中,是如何應(yīng)用緩存,又如何保證緩存和數(shù)據(jù)庫數(shù)據(jù)一致性的呢,歡迎留言進(jìn)行分享。


分布式技術(shù)原理與實(shí)戰(zhàn)45講--第35講:經(jīng)典問題:先更新數(shù)據(jù)庫,還是先更新緩存的評論 (共 條)

分享到微博請遵守國家法律
九寨沟县| 大新县| 富阳市| 密云县| 内丘县| 沾益县| 龙陵县| 潮安县| 桐庐县| 沂源县| 奎屯市| 佛山市| 嘉兴市| 雷州市| 玉门市| 榆树市| 南澳县| 大邑县| 东兰县| 怀柔区| 乐都县| 巴彦淖尔市| 都兰县| 正蓝旗| 安化县| 綦江县| 临夏县| 乐业县| 谢通门县| 弋阳县| 夏津县| 高青县| 彰化县| 石屏县| 巍山| 东乡县| 中超| 广昌县| 全椒县| 泸水县| 营山县|