session.merge 緩存不更新_如何保證緩存與數據庫雙寫時的數據一致性?

在做系統優化時,想到了將數據進行分級存儲的思路。因為在系統中會存在一些數據,有些數據的實時性要求不高,比如一些配置信息。基本上配置了很久才會變一次。而有一些數據實時性要求非常高,比如訂單和流水的數據。所以這里根據數據要求實時性不同將數據分為三級。

  • 第1級:訂單數據和支付流水數據;這兩塊數據對實時性和精確性要求很高,所以不添加任何緩存,讀寫操作將直接操作數據庫。

  • 第2級:用戶相關數據;這些數據和用戶相關,具有讀多寫少的特征,所以我們使用redis進行緩存。

  • 第3級:支付配置信息;這些數據和用戶無關,具有數據量小,頻繁讀,幾乎不修改的特征,所以我們使用本地內存進行緩存。

但是只要使用到緩存,無論是本地內存做緩存還是使用 redis 做緩存,那么就會存在數據同步的問題,因為配置信息緩存在內存中,而內存時無法感知到數據在數據庫的修改。這樣就會造成數據庫中的數據與緩存中數據不一致的問題。接下來就討論一下關于保證緩存和數據庫雙寫時的數據一致性。

解決方案

那么我們這里列出來所有策略,并且討論他們優劣性。

  1. 先更新數據庫,后更新緩存

  2. 先更新數據庫,后刪除緩存

  3. 先更新緩存,后更新數據庫

  4. 先刪除緩存,后更新數據庫

先更新數據庫,后更新緩存

這種場景一般是沒有人使用的,主要原因是在更新緩存那一步,為什么呢?因為有的業務需求緩存中存在的值并不是直接從數據庫中查出來的,有的是需要經過一系列計算來的緩存值,那么這時候后你要更新緩存的話其實代價是很高的。如果此時有大量的對數據庫進行寫數據的請求,但是讀請求并不多,那么此時如果每次寫請求都更新一下緩存,那么性能損耗是非常大的。

舉個例子比如在數據庫中有一個值為 1 的值,此時我們有 10 個請求對其每次加一的操作,但是這期間并沒有讀操作進來,如果用了先更新數據庫的辦法,那么此時就會有十個請求對緩存進行更新,會有大量的冷數據產生,如果我們不更新緩存而是刪除緩存,那么在有讀請求來的時候那么就會只更新緩存一次。

先更新緩存,后更新數據庫

這一種情況應該不需要我們考慮了吧,和第一種情況是一樣的。

先刪除緩存,后更新數據庫

該方案也會出問題,具體出現的原因如下。

5ababb8f8f34b267c2bb9681ec4dcbb1.png

此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)

  1. 請求 A 會先刪除 Redis 中的數據,然后去數據庫進行更新操作

  2. 此時請求 B 看到 Redis 中的數據時空的,會去數據庫中查詢該值,補錄到 Redis 中

  3. 但是此時請求 A 并沒有更新成功,或者事務還未提交

那么這時候就會產生數據庫和 Redis 數據不一致的問題。如何解決呢?其實最簡單的解決辦法就是延時雙刪的策略。

a6f7c0bdf64a9b32557992a365241bef.png

但是上述的保證事務提交完以后再進行刪除緩存還有一個問題,就是如果你使用的是 Mysql 的讀寫分離的架構的話,那么其實主從同步之間也會有時間差。

c1ad245a34b4a7340ac761f045cc46c9.png

此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)

  1. 請求 A 更新操作,刪除了 Redis

  2. 請求主庫進行更新操作,主庫與從庫進行同步數據的操作

  3. 請 B 查詢操作,發現 Redis 中沒有數據

  4. 去從庫中拿去數據

  5. 此時同步數據還未完成,拿到的數據是舊數據

此時的解決辦法就是如果是對 Redis 進行填充數據的查詢數據庫操作,那么就強制將其指向主庫進行查詢。

359a3a1311cc849f43c60f44a8fc5932.png

先更新數據庫,后刪除緩存

問題:這一種情況也會出現問題,比如更新數據庫成功了,但是在刪除緩存的階段出錯了沒有刪除成功,那么此時再讀取緩存的時候每次都是錯誤的數據了。

90bae82e4a3715216b050534241ffa6f.png

此時解決方案就是利用消息隊列進行刪除的補償。具體的業務邏輯用語言描述如下:

  1. 請求 A 先對數據庫進行更新操作

  2. 在對 Redis 進行刪除操作的時候發現報錯,刪除失敗

  3. 此時將Redis 的 key 作為消息體發送到消息隊列中

  4. 系統接收到消息隊列發送的消息后再次對 Redis 進行刪除操作

但是這個方案會有一個缺點就是會對業務代碼造成大量的侵入,深深的耦合在一起,所以這時會有一個優化的方案,我們知道對 Mysql 數據庫更新操作后再 binlog 日志中我們都能夠找到相應的操作,那么我們可以訂閱 Mysql 數據庫的 binlog 日志對緩存進行操作。

c80f380037e0ca690c72c114b1c2e86d.png

總結

每種方案各有利弊,比如在第二種先刪除緩存,后更新數據庫這個方案我們最后討論了要更新 Redis 的時候強制走主庫查詢就能解決問題,那么這樣的操作會對業務代碼進行大量的侵入,但是不需要增加的系統,不需要增加整體的服務的復雜度。最后一種方案我們最后討論了利用訂閱 binlog 日志進行搭建獨立系統操作 Redis,這樣的缺點其實就是增加了系統復雜度。其實每一次的選擇都需要我們對于我們的業務進行評估來選擇,沒有一種技術是對于所有業務都通用的。沒有最好的,只有最適合我們的。

87954c761f8691f377e086ad05c07a49.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532075.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532075.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532075.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java替換圖片中文字_Java 添加、替換、刪除Word中的圖片

文檔中,可以通過圖文混排的方式來增加內容的可讀性,相比純文本文檔,在內容展現方式上也更具美觀性。在給文檔添加圖片時,可設置圖片的文本環繞方式、旋轉角度、圖片高度/寬度等;另外,也可對文檔中已有的圖片…

kafka如何保證不重復消費又不丟失數據_Kafka寫入的數據如何保證不丟失?

我們暫且不考慮寫磁盤的具體過程,先大致看看下面的圖,這代表了 Kafka 的核心架構原理。Kafka 分布式存儲架構那么現在問題來了,如果每天產生幾十 TB 的數據,難道都寫一臺機器的磁盤上嗎?這明顯是不靠譜的啊!所以說,這…

不允許輸入特殊字符的正則表達式_JavaScript正則表達式常用技巧

正則表達式是用于匹配字符串中字符組合的模式。在 JavaScript 中,正則表達式也是對象。這些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。正則表達式的掌握程度能粗略地看出程序員的技術底子&#xff…

latex 算法_GitHub項目awesome-latex-drawing新增內容(四):繪制貝葉斯網絡

近期,我們整理和開源了一個基于LaTeX的科技繪圖項目,并將其取名為awesome-latex-drawing(GitHub網址為:https://github.com/xinychen/awesome-latex-drawing),案例包括貝葉斯網絡、圖模型、矩陣/張量示意圖…

python123動物重量排序_python進階

面向對象oopclass Student(object):def __init__(self,name,score)self.name nameself.score scoredef print_score(self)print(%s: %s % (self.name,self.score))給對象發消息實際上就是調用對象對應的關聯函數,我們稱之為對象的方法(Method)。面向對象的程序寫出…

mysql中的生日應該是什么類型_MySQL中的定點數類型

上一篇文章我們嘮叨了浮點數,知道了浮點數存儲小數是不精確的。本篇繼續嘮叨一下MySQL中的另一種存儲小數的方式 —— 定點數。浮點數文章閃現:什么, 0.3 - 0.2 ≠ 0.1 ? 什么鬼定點數類型正因為用浮點數表示小數可能會有不精確的情況,在一些…

python怎么制作圖像_python數字圖像處理(5):圖像的繪制

實際上前面我們就已經用到了圖像的繪制,如:io.imshow(img)這一行代碼的實質是利用matplotlib包對圖片進行繪制,繪制成功后,返回一個matplotlib類型的數據。因此,我們也可以這樣寫:importmatplotlib.pyplot …

axios代理跨域 cli4_vuecli 3.0之跨域請求代理配置及axios路徑配置 莫小龍

vue-cli 3.0之跨域請求代理配置及axios路徑配置問題:在前后端分離的跨域請求中,報跨域問題配置:vue.config.js:module.exports {runtimeCompiler: true,publicPath: /, // 設置打包文件相對路徑devServer: {// open: process.pla…

string轉為char數組_StringBuilder的區別是什么?String是不可變?一點課堂(多岸學院)...

String和StringBuffer、StringBuilder的區別可變性簡單的來說:String 類中使用 final 關鍵字字符數組保存字符串,private final char value[],所以 String 對象是不可變的。而StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuild…

python去年軟件排行_2017年編程語言排行榜,Python位居榜首(C語言需求最大)

最近IEEE Spectrum 發布了編程語言交互式排行榜,為很多學習代碼的朋友們詳解各類代碼語言的需求和占有率。為學習代碼的朋友們能更加重視哪一種編程語言而有一個明確的方向。下面排行榜123網為你公布2017年編程語言排行榜,Python位居榜首(C語言需求最大)。2017年編程…

mysql test數據庫_mysql數據庫test

Re介紹一下CentOS下MySQL數據庫的安裝與配置方法MySQL數據庫配置的具體步驟:1、編輯MySQL的配置文件,使用vi /etc/my.cnf[rootsample ~]# vi /etc/my.cnf  ← 編輯MySQL的配置文件[mysqld]datadir/var/lib/mysqlsocket/var/lib/mysql/mysql.sock# Defau…

mysql 升級 openssl_【1分鐘教程】LNMP架構應用實戰 Openssl升級操作

由于實際生產環境需求,需要將LNMP環境中的openssl版本升級至目前最新版本openssl-1.1.0c,這玩意升級還真的不是一般的麻煩,由于它與系統各種服務都有相關的聯系,比如ssh服務等,因此,升級非常的繁瑣,所以今天…

miui秒解bl鎖_MIUI12解鎖bl篇(原諒我的過失,接上篇文章)

求原諒真心求原諒由于我的疏忽,上期教程不完整,對大家造成不便在這里給大家真誠道歉!對不起!請收下我的膝蓋!!!我的上個教程小米手機MIUI系統降級任意版本通用教程,MIUI12→MIUI9因為…

腐蝕rust服務器命令_【使用 Rust 寫 Parser】2. 解析Redis協議

系列所有文章https://zhuanlan.zhihu.com/p/115017849?zhuanlan.zhihu.comhttps://zhuanlan.zhihu.com/p/139387293?zhuanlan.zhihu.comhttps://zhuanlan.zhihu.com/p/146455601?zhuanlan.zhihu.comhttps://zhuanlan.zhihu.com/p/186217695?zhuanlan.zhihu.com在基本熟悉 n…

python中dic_python之dic {字典}(重要指數*****)

1. 什么是字典{name: 汪峰, age: 18} 鍵:值 別的語言鍵值對數據鍵: 必須是可哈希(不可變的數據類型),并且是唯一的值: 任意可以保存任意類型的數據字典是無序的python3.6版本以上,默認定義了順序,python3.5以下是隨機顯示不能進?切片?作. 它只能通過key來獲取dict中的數據字典…

python裝飾器帶參數函數二階導數公式_一文搞定Python裝飾器,看完面試不再慌

本文始發于個人公眾號:TechFlow,原創不易,求個關注今天是Python專題的第12篇文章,我們來看看Python裝飾器。一段囧事差不多五年前面試的時候,我就領教過它的重要性。那時候我Python剛剛初學乍練,看完了廖雪…

centos7源碼安裝mysql報錯_CentOS7 下源碼安裝MySQL數據庫 8.0.11

本文主要向大家介紹了CentOS7 下源碼安裝MySQL數據庫 8.0.11,通過具體的內容向大家展現,希望對大家學習MySQL數據庫有所幫助。CentOS7 下源碼安裝MySQL 8.0.11系統環境:CentOS7, 內核:Linux 3.10.0-862.el7.x86_64如果…

python全排列問題_Python基于回溯法子集樹模板解決全排列問題示例

本文實例講述了Python基于回溯法子集樹模板解決全排列問題。分享給大家供大家參考,具體如下:問題實現 a, b, c, d 四個元素的全排列。分析這個問題可以直接套用排列樹模板。不過本文使用子集樹模板。分析如下:一個解x就是n個元素的一種排列&a…

file js new 傳到后臺_js 圖片上傳傳給后臺的3種格式

$("#imgfile").change(function () {var formData new FormData();$.each($(#imgfile)[0].files, function (i, file) {formData.set(idcard, file); //idcard 字段 根據自己后端接口定});//processData: false, contentType: false,多用來處理異步上傳二進制文件。…

usbserialcontroller驅動安裝不了_win10-有NVIDIA獨顯提示未安裝控制面板的離線安裝方式...

最近越來越多的用戶反映NVIDIA顯卡驅動設置不了啦,找不到NVIDIA顯卡的控制面板。 也不知道NVIDIA在什么版本開始驅動安裝包就不自帶NVIDIA顯卡控制面板了。 全新安裝的顯卡驅動就沒有控制面板;或者Windows 10自帶更新了顯卡新版驅動后導致沒有。 每次帶N…