如何保證緩存和數據庫的雙寫一致性

程序員面試資料大全|各種技術書籍等資料-1000G
IDEA開發工具- FREE

一、雙寫一致性問題本質

在分布式系統中,緩存與數據庫雙寫一致性指當數據被修改時,如何確保緩存(如Redis)和數據庫(如MySQL)中的數據保持同步。核心挑戰在于處理并發操作系統故障場景下的數據一致性問題。

典型不一致場景

ClientA Cache DB ClientB 更新數據X=1 成功 刪除緩存X 讀X(緩存未命中) 讀X(舊值X=0) 寫入緩存X=0 緩存中存儲了舊值 ClientA Cache DB ClientB

二、主流解決方案對比

方案適用場景優點缺點一致性強度
Cache-Aside讀多寫少簡單易實現存在不一致時間窗口最終一致
Write-Through寫密集型強一致性保證性能損耗大強一致
Write-Behind高吞吐場景高性能數據丟失風險最終一致
雙刪策略高一致性要求減少不一致窗口實現復雜強一致

三、核心解決方案詳解

方案1:Cache-Aside(旁路緩存)

最佳實踐:讀多寫少場景

寫操作
更新數據庫
刪除緩存
讀操作
緩存存在?
返回緩存數據
從數據庫讀取
寫入緩存
返回數據

關鍵實現代碼:

public void updateData(Data data) {// 1. 更新數據庫dataDao.update(data);// 2. 刪除緩存redis.del(data.getId());
}public Data getData(String id) {// 1. 從緩存獲取Data data = redis.get(id);if (data != null) {return data;}// 2. 從數據庫讀取data = dataDao.get(id);// 3. 寫入緩存(設置過期時間)redis.setex(id, 300, data);return data;
}

方案2:Write-Through(穿透寫入)

最佳實踐:強一致性要求場景

Client Cache DB 寫請求 同步寫入數據 寫入結果 操作結果 Client Cache DB

特點:

  • 緩存層作為數據庫代理
  • 所有寫操作同步更新緩存和數據庫
  • 讀操作只訪問緩存

方案3:Write-Behind(異步回寫)

最佳實踐:高吞吐場景

寫操作
寫入緩存
異步隊列
批量更新數據庫

實現代碼示例:

// 使用內存隊列實現異步更新
private BlockingQueue<Data> writeQueue = new LinkedBlockingQueue<>();public void updateData(Data data) {// 1. 更新緩存redis.set(data.getId(), data);// 2. 加入異步隊列writeQueue.offer(data);
}// 單獨的消費者線程
class DbWriter implements Runnable {public void run() {while (true) {Data data = writeQueue.take();dataDao.update(data); // 批量更新優化}}
}

方案4:雙刪策略(Double Delete)

最佳實踐:高一致性要求場景

Client Cache DB 第一次刪除緩存 更新數據庫 第二次刪除緩存(延遲) Client Cache DB

實現代碼:

public void updateDataWithDoubleDelete(Data data) {// 1. 首次刪除緩存redis.del(data.getId());// 2. 更新數據庫dataDao.update(data);// 3. 延遲二次刪除executor.schedule(() -> {redis.del(data.getId());}, 500, TimeUnit.MILLISECONDS); // 500ms延遲
}

四、高級一致性保障方案

方案1:分布式事務(強一致)

業務開始
開啟分布式事務
更新數據庫
更新緩存
操作成功?
提交事務
回滾事務

實現技術:

  • 2PC(兩階段提交)
  • TCC(Try-Confirm-Cancel)
  • Saga事務模式

方案2:基于Binlog的數據同步

Binlog
MySQL
消息隊列
緩存更新服務
Redis

實現組件:

  1. Canal監聽MySQL Binlog
  2. Kafka/RocketMQ作為消息隊列
  3. 消費者服務更新緩存

優點:

  • 完全解耦
  • 保證最終一致性
  • 支持重試機制

五、異常場景處理方案

1. 緩存更新失敗

成功
失敗
更新數據庫
刪除緩存
成功?
完成
加入重試隊列
定時重試
告警通知

2. 數據庫更新失敗

  • 事務回滾
  • 補償機制恢復緩存
public void updateDataWithCompensation(Data data) {try {// 1. 開啟事務transaction.begin();// 2. 更新數據庫dataDao.update(data);// 3. 刪除緩存redis.del(data.getId());// 4. 提交事務transaction.commit();} catch (Exception e) {// 5. 事務回滾transaction.rollback();// 6. 恢復緩存Data oldData = dataDao.get(data.getId());redis.set(data.getId(), oldData);}
}

六、最佳實踐選擇指南

場景特征推薦方案配置建議
讀多寫少,容忍短暫不一致Cache-Aside緩存過期時間 5-30分鐘
寫密集型,強一致性要求Write-Through配合本地緩存減少DB壓力
超高吞吐,可接受秒級延遲Write-Behind批量大小100-500條,刷新間隔1s
金融交易類系統分布式事務TCC模式+異步對賬
大型電商平臺Binlog同步Canal+Kafka+消費者集群

七、性能優化技巧

  1. 批量處理:合并多個緩存操作

    public void batchUpdate(List<Data> dataList) {// 批量更新數據庫dataDao.batchUpdate(dataList);// 批量刪除緩存List<String> keys = dataList.stream().map(Data::getId).collect(Collectors.toList());redis.del(keys.toArray(new String[0]));
    }
    
  2. 熱點數據特殊處理

    // 使用互斥鎖防止緩存擊穿
    public Data getHotData(String id) {Data data = redis.get(id);if (data == null) {if (redis.setnx("lock:" + id, "1")) {redis.expire("lock:" + id, 10); // 設置鎖超時data = dataDao.get(id);redis.set(id, data);redis.del("lock:" + id);} else {// 等待重試Thread.sleep(50);return getHotData(id);}}return data;
    }
    
  3. 多級緩存策略

    客戶端
    CDN
    邊緣緩存
    Redis集群
    本地緩存
    數據庫

八、監控與度量指標

  1. 關鍵監控項

    • 緩存命中率(Hit Ratio)
    • 緩存更新延遲(Update Latency)
    • 不一致事件計數
    • 重試隊列長度
  2. 告警規則

    # Prometheus告警規則示例
    - alert: HighCacheInconsistencyRateexpr: rate(cache_inconsistency_count[5m]) > 0.5for: 10mlabels:severity: criticalannotations:summary: "緩存不一致率過高"- alert: CacheUpdateTimeoutexpr: cache_update_latency_seconds > 1for: 5mlabels:severity: warningannotations:summary: "緩存更新延遲超過閾值"
    

程序員面試資料大全|各種技術書籍等資料-1000G
IDEA開發工具- FREE

在這里插入圖片描述

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

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

相關文章

Qt 5.9 XML文件寫入指南

Qt 5.9 XML文件寫入指南 在Qt 5.9中&#xff0c;有多種方法可以編寫XML文件。下面我將介紹三種主要方法&#xff0c;并提供完整的代碼示例和最佳實踐。 三種XML寫入方法對比 方法優點缺點適用場景QXmlStreamWriter高效、內存占用低無樹形結構大型XML文件QDomDocument樹形結構…

一些ubuntu命令記錄(持續補充)

一、查看代碼運行占用的內存 1、使用 top 命令 top 命令是一個實時的系統監控工具&#xff0c;可以顯示當前系統中所有進程的資源使用情況。運行以下命令&#xff1a; top 在 top 界面中&#xff0c;可以看到每個進程的內存使用情況&#xff08;%MEM 列&#xff09;。 如何…

今日學習:音視頻領域入門文章參考(待完善)

音視頻領域概覽 入門文章參考 CSDN 雷神 博客園 2022-5-22

.npmrc和.yarnrc配置文件介紹:分別用于 Node.js 中的 npm(Node Package Manager)和 Yarn 包管理工具

.npmrc 和 .yarnrc 是兩個配置文件&#xff0c;分別用于 Node.js 中的 npm&#xff08;Node Package Manager&#xff09;和 Yarn 包管理工具。它們存儲了與包管理相關的配置選項&#xff0c;允許用戶自定義和控制包的安裝、版本、緩存等行為。下面是它們的詳細說明&#xff1a…

數字人分身 + 矩陣系統聚合:源碼搭建,支持OEM

在 AIGC 技術爆發的當下&#xff0c;數字人分身已從概念走向實用&#xff0c;而矩陣系統的聚合能力則讓單個數字人分身突破場景限制&#xff0c;實現 “一人多崗” 的規模化應用。無論是企業客服、直播帶貨&#xff0c;還是教育培訓、虛擬社交&#xff0c;數字人分身 矩陣系統…

學習昇騰開發的第12天--安裝第三方依賴

第三方依賴安裝指導&#xff08;C樣例&#xff09; 前置條件 1. 按照官方指導文檔完成CANN包安裝。 2. CANN版本需要>5.0.4.alpha001&#xff0c;低于此版本請參見昇騰CANN樣例倉介紹中的版本說明切換tag并使用發行版。 安裝須知 samples倉中的部分c樣例使用到opencv&am…

機器人仿真(1)Ubuntu24.04下CLion的ROS2開發環境配置

目錄 一、前言二、配置要求安裝ROS2安裝CLion 三、配置步驟四、后記 一、前言 近日CLion已開放非商用免費使用。相比教程中常用的VSCode&#xff0c;CLion在自動補全、調試和環境變量配置等方面表現更為出色。不過截至本文撰寫時&#xff0c;CLion官網僅提供了Windows系統下的…

WPF兩種綁定方式的分析

一、兩種綁定方式的分析 你提供的代碼展示了兩種不同的屬性綁定實現方式&#xff1a;傳統的CLR屬性配合INotifyPropertyChanged接口&#xff0c;以及WPF依賴屬性(DependencyProperty)系統。 相同點 目的相同&#xff1a;兩種方式都是為了實現屬性值變化時通知UI更新數據綁定…

【零基礎學AI】第14講:支持向量機實戰 - 文本分類系統

本節課你將學到 理解支持向量機的核心思想和幾何直覺 掌握SVM的關鍵參數和核函數選擇 學會文本數據預處理和特征提取 完成一個郵件分類項目 對比SVM與其他算法的性能差異 開始之前 環境要求 Python 3.8內存: 建議2GB 需要安裝的包 pip install pandas numpy scikit-learn …

美團 mtgsig1.2 最新版分析

聲明: 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向分析 部分代碼 result cp.call…

【實戰】CRMEB Pro 企業版安裝教程(附 Nginx 反向代理配置 + 常見問題解決)

一、前言 CRMEB Pro 是一款企業級高并發高性能的電商系統&#xff0c;支持 Linux 服務器環境&#xff0c;需要 PHP 8.0 及以上版本&#xff0c;兼容多種 WEB 服務器&#xff08;如 Nginx 和 Apache&#xff09;&#xff0c;并支持 MySQL 數據庫。本文將詳細介紹如何從零開始安…

解決Linux下根目錄磁盤空間不足的問題

ubantu中提示根目錄磁盤空間不足 解決辦法&#xff1a;對根目錄磁盤空間進行擴展。 一、使用lsblk查看磁盤使用情況 命令行輸入&#xff1a;lsblk aaaubuntu:~/Desktop$ lsblk可以看到sda5是掛載在根目錄上的。所以我們要對sda5進行擴展 二、擴展硬盤空間 1、關閉虛擬機 2、…

【C++】--入門

前面我們學習C語言的時候&#xff0c;我們也有講過C的部分歷史&#xff0c;我們看其名字就知道其和我們的C語言肯定是有密不可分的關系的&#xff0c;我們的C是在C的基礎上發展的&#xff0c;其彌補了C語?在表達能?、可維護性 和可擴展性??的不?。 下面為C的近年來的幾次…

JAVA內存區域劃分

根據《JAVA虛擬機規范》的規定&#xff0c;JAVA虛擬機在執行JAVA程序的過程中會把內存劃分為不同的數據區域。不同類型的數據會存儲在不同的區域&#xff0c;理解JAVA內存區域的工作細節對理解JAVA多線程、線程安全性有著重要意義。 注意&#xff0c;JAVA內存區域的劃分與我們…

Navicat 導入 SQL 文件

1. 安裝并打開 Navicat 安裝 Navicat&#xff08;如 Navicat Premium、Navicat for MySQL&#xff09;&#xff0c;百度或者淘寶就有很多破解版。 打開 Navicat&#xff0c;進入主界面。 2. 新建數據庫連接 點擊左上角 “連接” 按鈕&#xff0c;選擇你對應的數據庫類型&…

《Go語言高級編程》玩轉RPC

《Go語言高級編程》玩轉RPC 一、客戶端 RPC 實現原理&#xff1a;異步調用機制 Go 的 RPC 客戶端支持同步和異步調用&#xff0c;核心在于 Client.Go 方法的實現&#xff1a; 1. 同步調用&#xff08;Client.Call&#xff09;的本質 func (client *Client) Call(serviceMet…

四大核心要素驅動汽車智能化創新與相關芯片競爭格局

作者&#xff1a;北京華興萬邦管理咨詢有限公司 翔煜 商瑞 智能汽車時代的加速到來&#xff0c;使車載智能系統面臨前所未有的算力需求。隨著越來越多車型引入電子電氣架構轉向中心化、智能駕駛的多傳感器融合、智能座艙的多模態交互以及生成式AI驅動的虛擬助手等創新技術&a…

照明新基建:塔能科技如何用數字骨骼支撐智慧城市生長

一、能源管理困局&#xff1a;雙碳目標下的市政用電痛點 在雙碳背景下&#xff0c;城市照明用電量已引起市政部門的重點關注。據國家統計局統計&#xff1a;我國城市照明用電量已占據全市城市用電量的28%&#xff0c;部分城市的照明用電量已高達35%以上&#xff0c;高壓鈉燈傳統…

讓Claude Code像Cursor一樣好用

最近折騰AI工具&#xff0c;發現Claude Code真是個寶藏。但說實話&#xff0c;初學者一上手&#xff0c;十有八九會被命令行那一堆黑框框勸退。你以為你用熟了&#xff1f;其實你只解鎖了Claude Code不到20%的威力&#xff0c;剩下的80%都藏在命令行背后的“黑魔法”里。00后誰…

ROS 2 中更改從設備(如電機控制器)的運動模式

在 ROS 2 中更改從設備&#xff08;如電機控制器&#xff09;的運動模式&#xff08;例如從位置模式切換到速度模式&#xff09;&#xff0c;需要通過操作模式&#xff08;Mode of Operation&#xff0c;對應對象字典索引0x6060&#xff09; 進行設置。結合你的配置&#xff08…