日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

你知道緩存的這個問題到底把多少程序員坑慘了嗎?

來源: 責(zé)編: 時間:2024-07-05 09:05:12 1081觀看
導(dǎo)讀引言你是不是也經(jīng)歷過這種情況?某個陽光明媚的上午,你正享受著枸杞泡水和敲代碼的美妙時刻,突然接到客服部門的電話。電話那頭的聲音急切又焦慮:“客戶抱怨說,怎么點擊購買總是失敗?”作為技術(shù)人員,你瞬間腦袋里浮現(xiàn)出無數(shù)可

引言

你是不是也經(jīng)歷過這種情況?某個陽光明媚的上午,你正享受著枸杞泡水和敲代碼的美妙時刻,突然接到客服部門的電話。53e28資訊網(wǎng)——每日最新資訊28at.com

電話那頭的聲音急切又焦慮:“客戶抱怨說,怎么點擊購買總是失敗?”53e28資訊網(wǎng)——每日最新資訊28at.com

作為技術(shù)人員,你瞬間腦袋里浮現(xiàn)出無數(shù)可能的原因,其中最讓人頭疼的,莫過于緩存與數(shù)據(jù)庫的不一致問題。53e28資訊網(wǎng)——每日最新資訊28at.com

這個問題不僅影響用戶體驗,還可能導(dǎo)致業(yè)務(wù)數(shù)據(jù)的混亂。53e28資訊網(wǎng)——每日最新資訊28at.com

今兒就來聊聊緩存與數(shù)據(jù)庫不一致的問題,幫大家理清楚問題所在,并給出推薦方案。53e28資訊網(wǎng)——每日最新資訊28at.com

問題剖析

在現(xiàn)代系統(tǒng)中,緩存可以極大地提升性能,減少數(shù)據(jù)庫的壓力。53e28資訊網(wǎng)——每日最新資訊28at.com

然而,一旦緩存和數(shù)據(jù)庫的數(shù)據(jù)不一致,就會引發(fā)各種詭異的問題。53e28資訊網(wǎng)——每日最新資訊28at.com

系統(tǒng)維護(hù)的重要性在此凸顯,極端手段比如清空緩存,可能會在短時間內(nèi)解決問題,但從長遠(yuǎn)來看,這些操作往往帶來更大的隱患。53e28資訊網(wǎng)——每日最新資訊28at.com

解決方案概覽

我們來看看幾種常見的解決緩存與數(shù)據(jù)庫不一致的方案,每種方案都有各自的優(yōu)缺點:53e28資訊網(wǎng)——每日最新資訊28at.com

  1. 先更新緩存,再更新數(shù)據(jù)庫
  2. 先更新數(shù)據(jù)庫,再更新緩存
  3. 先刪除緩存,后更新數(shù)據(jù)庫
  4. 先更新數(shù)據(jù)庫,后刪除緩存

深入探討

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

這種方案看似簡單,實際上很少被推薦。53e28資訊網(wǎng)——每日最新資訊28at.com

原因在于如果在更新數(shù)據(jù)庫之前發(fā)生了錯誤,緩存中的數(shù)據(jù)將和數(shù)據(jù)庫中的數(shù)據(jù)不一致,最終導(dǎo)致更大的問題。53e28資訊網(wǎng)——每日最新資訊28at.com

public void updateCacheThenDatabase(String key, String value) {    cache.put(key, value);    try {        database.update(key, value);    } catch (Exception e) {        // 數(shù)據(jù)庫更新失敗,緩存數(shù)據(jù)可能錯誤        System.err.println("數(shù)據(jù)庫更新失敗: " + e.getMessage());    }}

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

這種方法解決了更新緩存失敗的問題,但可能引發(fā)另外一個問題:53e28資訊網(wǎng)——每日最新資訊28at.com

在高并發(fā)場景下,數(shù)據(jù)庫已經(jīng)更新,但緩存還沒有更新時,其他請求可能會讀到舊的緩存數(shù)據(jù)。53e28資訊網(wǎng)——每日最新資訊28at.com

public void updateDatabaseThenCache(String key, String value) {    database.update(key, value);    cache.put(key, value);}

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

這種方案在高并發(fā)下容易產(chǎn)生問題:53e28資訊網(wǎng)——每日最新資訊28at.com

在緩存刪除和數(shù)據(jù)庫更新之間的時間窗口內(nèi),其他請求可能會讀取到舊的數(shù)據(jù),導(dǎo)致短時間內(nèi)的數(shù)據(jù)不一致。53e28資訊網(wǎng)——每日最新資訊28at.com

public void deleteCacheThenUpdateDatabase(String key, String value) {    cache.remove(key);    try {        database.update(key, value);    } catch (Exception e) {        // 數(shù)據(jù)庫更新失敗,需要重新設(shè)置緩存        cache.put(key, getOldValueFromDatabase(key));        System.err.println("數(shù)據(jù)庫更新失敗: " + e.getMessage());    }}

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

這是較為推薦的一種方法,但在高并發(fā)場景下也有一定的局限性:53e28資訊網(wǎng)——每日最新資訊28at.com

如果數(shù)據(jù)庫更新成功但緩存刪除失敗,可能導(dǎo)致短時間內(nèi)的數(shù)據(jù)不一致。53e28資訊網(wǎng)——每日最新資訊28at.com

public void updateDatabaseThenDeleteCache(String key, String value) {    database.update(key, value);    cache.remove(key);}

強(qiáng)一致性與最終一致性

在討論一致性的時候,我們常常會提到強(qiáng)一致性和最終一致性。53e28資訊網(wǎng)——每日最新資訊28at.com

強(qiáng)一致性保證每次讀取的數(shù)據(jù)都是最新的,但在分布式系統(tǒng)中實現(xiàn)成本較高。53e28資訊網(wǎng)——每日最新資訊28at.com

最終一致性則允許數(shù)據(jù)在一定時間內(nèi)不一致,適用于大多數(shù)實際業(yè)務(wù)場景。53e28資訊網(wǎng)——每日最新資訊28at.com

根據(jù)業(yè)務(wù)需求權(quán)衡這兩者,是緩存策略設(shè)計中的重要一步。53e28資訊網(wǎng)——每日最新資訊28at.com

后面我會給出一個弱一致性的推薦方案,供大家參考。53e28資訊網(wǎng)——每日最新資訊28at.com

SpringCache

SpringCache是一個非常實用的緩存管理框架,能幫助我們簡化緩存操作。53e28資訊網(wǎng)——每日最新資訊28at.com

以下是一個簡單的SpringCache配置示例:53e28資訊網(wǎng)——每日最新資訊28at.com

@Configuration@EnableCachingpublic class CacheConfig {    @Bean    public CacheManager cacheManager() {        return new ConcurrentMapCacheManager("entities");    }}

SpringCache 的優(yōu)點:53e28資訊網(wǎng)——每日最新資訊28at.com

  • 簡化緩存管理:SpringCache 提供了簡潔的 API,能夠輕松集成到現(xiàn)有項目中。
  • 注解驅(qū)動:使用注解如 @Cacheable、@CachePut 和 @CacheEvict,使得緩存操作更直觀。
  • 靈活配置:支持多種緩存實現(xiàn),能夠根據(jù)需求選擇合適的緩存方案。

SpringCache 的缺點:53e28資訊網(wǎng)——每日最新資訊28at.com

  • 限制性:默認(rèn)的緩存管理器在一些復(fù)雜場景下可能不夠靈活。
  • 性能瓶頸:在高并發(fā)場景下,內(nèi)存緩存可能會成為性能瓶頸,需要合理設(shè)計和優(yōu)化。

常用的注解包括@Cacheable、@CachePut和@CacheEvict:53e28資訊網(wǎng)——每日最新資訊28at.com

@Cacheable("entities")public Entity findById(Long id) {    // 如果緩存中存在,則直接返回緩存中的數(shù)據(jù)    // 否則調(diào)用方法查詢數(shù)據(jù)庫,并將結(jié)果存入緩存    return repository.findById(id).orElse(null);}@CachePut(value = "entities", key = "#entity.id")public Entity updateEntity(Entity entity) {    // 更新數(shù)據(jù)庫,同時更新緩存中的數(shù)據(jù)    return repository.save(entity);}@CacheEvict(value = "entities", allEntries = true)public void clearCache() {    // 清空緩存}

緩存預(yù)熱策略

緩存預(yù)熱的重要性不言而喻,上線后瞬時大流量可能導(dǎo)致緩存擊穿。53e28資訊網(wǎng)——每日最新資訊28at.com

以下是幾種常見的緩存預(yù)熱方案:53e28資訊網(wǎng)——每日最新資訊28at.com

  1. 啟動時加載:系統(tǒng)啟動時加載常用數(shù)據(jù)到緩存。
@Componentpublic class CachePreloader {    @Autowired    private CacheManager cacheManager;    @PostConstruct    public void preload() {        Cache cache = cacheManager.getCache("entities");        if (cache != null) {            // 假設(shè)我們有一個服務(wù)可以獲取需要預(yù)熱的數(shù)據(jù)            List<Entity> entities = fetchEntitiesForPreloading();            for (Entity entity : entities) {                cache.put(entity.getId(), entity);            }        }    }    private List<Entity> fetchEntitiesForPreloading() {        // 獲取需要預(yù)熱的數(shù)據(jù)        return repository.findAll();    }}
  1. 定時加載:定時任務(wù)定期加載數(shù)據(jù)。
@Componentpublic class ScheduledCachePreloader {    @Autowired    private CacheManager cacheManager;    @Scheduled(fixedRate = 60000) // 每分鐘執(zhí)行一次    public void preload() {        Cache cache = cacheManager.getCache("entities");        if (cache != null) {            // 獲取需要預(yù)熱的數(shù)據(jù)并加載到緩存            List<Entity> entities = fetchEntitiesForPreloading();            for (Entity entity : entities) {                cache.put(entity.getId(), entity);            }        }    }    private List<Entity> fetchEntitiesForPreloading() {        // 獲取需要預(yù)熱的數(shù)據(jù)        return repository.findAll();    }}
  1. 手動加載:手動執(zhí)行預(yù)熱腳本。
@Componentpublic class ManualCachePreloader {    @Autowired    private CacheManager cacheManager;    public void preload() {        Cache cache = cacheManager.getCache("entities");        if (cache != null) {            // 獲取需要預(yù)熱的數(shù)據(jù)并加載到緩存            List<Entity> entities = fetchEntitiesForPreloading();            for (Entity entity : entities) {                cache.put(entity.getId(), entity);            }        }    }    private List<Entity> fetchEntitiesForPreloading() {        // 獲取需要預(yù)熱的數(shù)據(jù)        return repository.findAll();    }}

推薦方案

綜合考慮各種方案的優(yōu)缺點,我給大家一種工作中真正常用的方案,也是我待過的互聯(lián)網(wǎng)公司中實踐過的方案。53e28資訊網(wǎng)——每日最新資訊28at.com

基本策略:刪除Redis中緩存 -> 更新數(shù)據(jù)庫 -> 最新數(shù)據(jù)set到Redis53e28資訊網(wǎng)——每日最新資訊28at.com

延遲雙刪:刪除Redis中緩存 -> 更新數(shù)據(jù)庫 -> 休眠500ms -> 再次刪除Redis中緩存 -> 最新數(shù)據(jù)set到Redis53e28資訊網(wǎng)——每日最新資訊28at.com

延遲三刪:刪除Redis中緩存 -> 更新數(shù)據(jù)庫 -> 休眠500ms -> 再次刪除Redis中緩存 -> 休眠500ms -> 再次刪除Redis中緩存 -> 最新數(shù)據(jù)set到Redis53e28資訊網(wǎng)——每日最新資訊28at.com

這是一種非常簡單且成本很低的操作,但能解決絕大多數(shù)的緩存與數(shù)據(jù)庫不一致問題。53e28資訊網(wǎng)——每日最新資訊28at.com

原理很好理解,就是更新數(shù)據(jù)庫之后設(shè)置合理的休眠時間,然后再次刪除掉其他線程請求進(jìn)來導(dǎo)致的舊緩存,最終達(dá)到緩存和數(shù)據(jù)庫都是最新數(shù)據(jù)的目的。53e28資訊網(wǎng)——每日最新資訊28at.com

其中休眠時間要根據(jù)自身業(yè)務(wù)的平均耗時來決定,而延遲雙刪其實就夠了,延遲三刪只是為了開闊大家的思路,因為真有些公司刪除三次來保證一些極端情況的不一致,但我覺得沒必要,太極端就不是弱一致性了。53e28資訊網(wǎng)——每日最新資訊28at.com

如果是比較復(fù)雜的項目,甚至能再進(jìn)一步的優(yōu)化,也就是借用定時任務(wù)和MQ來替代休眠線程,實現(xiàn)異步刪除緩存,達(dá)到弱一致性的結(jié)果。53e28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)與思考

緩存與數(shù)據(jù)庫一致性是一個復(fù)雜的問題,需要根據(jù)具體業(yè)務(wù)場景選擇合適的策略。53e28資訊網(wǎng)——每日最新資訊28at.com

大家需要記住一點,高可用性是系統(tǒng)的最優(yōu)先選擇,所以弱一致性就必然成為數(shù)據(jù)不一致性的最優(yōu)解,這是一種良性閉環(huán)。53e28資訊網(wǎng)——每日最新資訊28at.com

因為系統(tǒng)不能用,那是直接虧損,但數(shù)據(jù)出現(xiàn)低量的不一致,完全可以接受。53e28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-98863-0.html你知道緩存的這個問題到底把多少程序員坑慘了嗎?

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 使用Spring Boot和流量控制算法解決視頻會議系統(tǒng)網(wǎng)絡(luò)波動問題

下一篇: SpringBoot自帶Controller接口監(jiān)控,趕緊用起來

標(biāo)簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 砀山县| 安多县| 科技| 长阳| 太仓市| 大连市| 嫩江县| 昔阳县| 轮台县| 江西省| 庄河市| 长汀县| 嘉峪关市| 余干县| 青河县| 山东省| 仙桃市| 和政县| 许昌县| 龙州县| 佛坪县| 宁强县| 西昌市| 仁怀市| 观塘区| 水城县| 庐江县| 原平市| 沁源县| 连云港市| 乐平市| 施秉县| 福清市| 池州市| 保亭| 民权县| 板桥市| 元氏县| 九寨沟县| 西林县| 佛学|