欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

redis緩存與數(shù)據(jù)庫(kù)一致性的問(wèn)題及解決

 更新時(shí)間:2023年06月03日 11:02:49   作者:chenshiying007  
這篇文章主要介紹了redis緩存與數(shù)據(jù)庫(kù)一致性的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、需求起因

假設(shè)先寫(xiě)數(shù)據(jù)庫(kù),再淘汰緩存:第一步寫(xiě)數(shù)據(jù)庫(kù)操作成功,第二步淘汰緩存失敗,則會(huì)出現(xiàn)DB中是新數(shù)據(jù),Cache中是舊數(shù)據(jù),數(shù)據(jù)不一致【db中是新數(shù)據(jù),cache中是舊數(shù)據(jù)】。

假設(shè)先淘汰緩存,再寫(xiě)數(shù)據(jù)庫(kù):第一步淘汰緩存成功,第二步寫(xiě)數(shù)據(jù)庫(kù)失敗【cache中無(wú)數(shù)據(jù),db中是舊數(shù)據(jù)】。

結(jié)論:先淘汰緩存,再寫(xiě)數(shù)據(jù)庫(kù)。

二、數(shù)據(jù)不一致原因

先操作緩存,在寫(xiě)數(shù)據(jù)庫(kù)成功之前,如果有讀請(qǐng)求發(fā)生,可能導(dǎo)致舊數(shù)據(jù)入緩存,引發(fā)數(shù)據(jù)不一致。

寫(xiě)流程

1)先淘汰cache

2)再寫(xiě)db

讀流程

1)先讀cache,如果數(shù)據(jù)命中hit則返回

2)如果數(shù)據(jù)未命中miss則讀db

3)將db中讀取出來(lái)的數(shù)據(jù)入緩存

什么情況下可能出現(xiàn)緩存和數(shù)據(jù)庫(kù)中數(shù)據(jù)不一致呢?

在分布式環(huán)境下,數(shù)據(jù)的讀寫(xiě)都是并發(fā)的,上游有多個(gè)應(yīng)用,通過(guò)一個(gè)服務(wù)的多個(gè)部署(為了保證可用性,一定是部署多份的),對(duì)同一個(gè)數(shù)據(jù)進(jìn)行讀寫(xiě),在數(shù)據(jù)庫(kù)層面并發(fā)的讀寫(xiě)并不能保證完成順序,也就是說(shuō)后發(fā)出的讀請(qǐng)求很可能先完成(讀出臟數(shù)據(jù)):

  • a)發(fā)生了寫(xiě)請(qǐng)求A,A的第一步淘汰了cache(如上圖中的1)
  • b)A的第二步寫(xiě)數(shù)據(jù)庫(kù),發(fā)出修改請(qǐng)求(如上圖中的2)
  • c)發(fā)生了讀請(qǐng)求B,B的第一步讀取cache,發(fā)現(xiàn)cache中是空的(如上圖中的步驟3)
  • d)B的第二步讀取數(shù)據(jù)庫(kù),發(fā)出讀取請(qǐng)求,此時(shí)A的第二步寫(xiě)數(shù)據(jù)還沒(méi)完成,讀出了一個(gè)臟數(shù)據(jù)放入cache(如上圖中的步驟4)

即在數(shù)據(jù)庫(kù)層面,后發(fā)出的請(qǐng)求4比先發(fā)出的請(qǐng)求2先完成了,讀出了臟數(shù)據(jù),臟數(shù)據(jù)又入了緩存,緩存與數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致出現(xiàn)了

三、問(wèn)題解決思路

能否做到先發(fā)出的請(qǐng)求一定先執(zhí)行完成呢?常見(jiàn)的思路是“串行化” 

細(xì)節(jié)如下:

1)service的上游是多個(gè)業(yè)務(wù)應(yīng)用,上游發(fā)起請(qǐng)求對(duì)同一個(gè)數(shù)據(jù)并發(fā)的進(jìn)行讀寫(xiě)操作,上例中并發(fā)進(jìn)行了一個(gè)uid=1的余額修改(寫(xiě))操作與uid=1的余額查詢(讀)操作

2)service的下游是數(shù)據(jù)庫(kù)DB,假設(shè)只讀寫(xiě)一個(gè)DB

3)中間是服務(wù)層service,它又分為了這么幾個(gè)部分

  • 3.1)最上層是任務(wù)隊(duì)列
  • 3.2)中間是工作線程,每個(gè)工作線程完成實(shí)際的工作任務(wù),典型的工作任務(wù)是通過(guò)數(shù)據(jù)庫(kù)連接池讀寫(xiě)數(shù)據(jù)庫(kù)
  • 3.3)最下層是數(shù)據(jù)庫(kù)連接池,所有的SQL語(yǔ)句都是通過(guò)數(shù)據(jù)庫(kù)連接池發(fā)往數(shù)據(jù)庫(kù)去執(zhí)行的

工作線程的典型工作流是這樣的:

void work_thread_routine(){
Task t = TaskQueue.pop(); // 獲取任務(wù)
// 任務(wù)邏輯處理,生成sql語(yǔ)句
DBConnection c = CPool.GetDBConnection(); // 從DB連接池獲取一個(gè)DB連接
c.execSQL(sql); // 通過(guò)DB連接執(zhí)行sql語(yǔ)句
CPool.PutDBConnection(c); // 將DB連接放回DB連接池
}

提問(wèn):任務(wù)隊(duì)列其實(shí)已經(jīng)做了任務(wù)串行化的工作,能否保證任務(wù)不并發(fā)執(zhí)行?

答:不行,因?yàn)?/strong>

(1)1個(gè)服務(wù)有多個(gè)工作線程,串行彈出的任務(wù)會(huì)被并行執(zhí)行

(2)1個(gè)服務(wù)有多個(gè)數(shù)據(jù)庫(kù)連接,每個(gè)工作線程獲取不同的數(shù)據(jù)庫(kù)連接會(huì)在DB層面并發(fā)執(zhí)行

提問(wèn):假設(shè)服務(wù)只部署一份,能否保證任務(wù)不并發(fā)執(zhí)行?

答:不行,原因同上

提問(wèn):假設(shè)1個(gè)服務(wù)只有1條數(shù)據(jù)庫(kù)連接,能否保證任務(wù)不并發(fā)執(zhí)行?

答:不行,因?yàn)?/strong>

(1)1個(gè)服務(wù)只有1條數(shù)據(jù)庫(kù)連接,只能保證在一個(gè)服務(wù)器上的請(qǐng)求在數(shù)據(jù)庫(kù)層面是串行執(zhí)行的

(2)因?yàn)榉?wù)是分布式部署的,多個(gè)服務(wù)上的請(qǐng)求在數(shù)據(jù)庫(kù)層面仍可能是并發(fā)執(zhí)行的

提問(wèn):假設(shè)服務(wù)只部署一份,且1個(gè)服務(wù)只有1條連接,能否保證任務(wù)不并發(fā)執(zhí)行?

答:可以,全局來(lái)看請(qǐng)求是串行執(zhí)行的,吞吐量很低,并且服務(wù)無(wú)法保證可用性

完了,看似無(wú)望了,

1)任務(wù)隊(duì)列不能保證串行化

2)單服務(wù)多數(shù)據(jù)庫(kù)連接不能保證串行化

3)多服務(wù)單數(shù)據(jù)庫(kù)連接不能保證串行化

4)單服務(wù)單數(shù)據(jù)庫(kù)連接可能保證串行化,但吞吐量級(jí)低,且不能保證服務(wù)的可用性,幾乎不可行,那是否還有解?

解決方式

  • 退一步想,其實(shí)不需要讓全局的請(qǐng)求串行化,而只需要“讓同一個(gè)數(shù)據(jù)的訪問(wèn)能串行化”就行。
  • 在一個(gè)服務(wù)內(nèi),如何做到“讓同一個(gè)數(shù)據(jù)的訪問(wèn)串行化”,只需要“讓同一個(gè)數(shù)據(jù)的訪問(wèn)通過(guò)同一條DB連接執(zhí)行”就行。
  • 如何做到“讓同一個(gè)數(shù)據(jù)的訪問(wèn)通過(guò)同一條DB連接執(zhí)行”,只需要“在DB連接池層面稍微修改,按數(shù)據(jù)取連接即可”
  • 獲取DB連接的CPool.GetDBConnection()【返回任何一個(gè)可用DB連接】改為
  • CPool.GetDBConnection(longid)【返回id取模相關(guān)聯(lián)的DB連接】

這個(gè)修改的好處是:

1)簡(jiǎn)單,只需要修改DB連接池實(shí)現(xiàn),以及DB連接獲取處

2)連接池的修改不需要關(guān)注業(yè)務(wù),傳入的id是什么含義連接池不關(guān)注,直接按照id取模返回DB連接即可

3)可以適用多種業(yè)務(wù)場(chǎng)景,取用戶數(shù)據(jù)業(yè)務(wù)傳入user-id取連接,取訂單數(shù)據(jù)業(yè)務(wù)傳入order-id取連接即可

這樣的話,就能夠保證同一個(gè)數(shù)據(jù)例如uid在數(shù)據(jù)庫(kù)層面的執(zhí)行一定是串行的

稍等稍等,服務(wù)可是部署了很多份的,上述方案只能保證同一個(gè)數(shù)據(jù)在一個(gè)服務(wù)上的訪問(wèn),在DB層面的執(zhí)行是串行化的,實(shí)際上服務(wù)是分布式部署的,在全局范圍內(nèi)的訪問(wèn)仍是并行的,怎么解決呢?能不能做到同一個(gè)數(shù)據(jù)的訪問(wèn)一定落到同一個(gè)服務(wù)呢?

能否做到同一個(gè)數(shù)據(jù)的訪問(wèn)落在同一個(gè)服務(wù)上?

上面分析了服務(wù)層service的上下游及內(nèi)部結(jié)構(gòu),再一起看一下應(yīng)用層上下游及內(nèi)部結(jié)構(gòu) 

上圖是一個(gè)業(yè)務(wù)應(yīng)用的上下游及服務(wù)內(nèi)部詳細(xì)展開(kāi),細(xì)節(jié)如下:

1)業(yè)務(wù)應(yīng)用的上游不確定是啥,可能是直接是http請(qǐng)求,可能也是一個(gè)服務(wù)的上游調(diào)用

2)業(yè)務(wù)應(yīng)用的下游是多個(gè)服務(wù)service

3)中間是業(yè)務(wù)應(yīng)用,它又分為了這么幾個(gè)部分

  • 3.1)最上層是任務(wù)隊(duì)列【或許web-server例如tomcat幫你干了這個(gè)事情了】
  • 3.2)中間是工作線程【或許web-server的工作線程或者cgi工作線程幫你干了線程分派這個(gè)事情了】,每個(gè)工作線程完成實(shí)際的業(yè)務(wù)任務(wù),典型的工作任務(wù)是通過(guò)服務(wù)連接池進(jìn)行RPC調(diào)用
  • 3.3)最下層是服務(wù)連接池,所有的RPC調(diào)用都是通過(guò)服務(wù)連接池往下游服務(wù)去發(fā)包執(zhí)行的

工作線程的典型工作流是這樣的:

voidwork_thread_routine(){
Task t = TaskQueue.pop(); // 獲取任務(wù)
// 任務(wù)邏輯處理,組成一個(gè)網(wǎng)絡(luò)包packet,調(diào)用下游RPC接口
ServiceConnection c = CPool.GetServiceConnection(); // 從Service連接池獲取一個(gè)Service連接
c.Send(packet); // 通過(guò)Service連接發(fā)送報(bào)文執(zhí)行RPC請(qǐng)求
CPool.PutServiceConnection(c); // 將Service連接放回Service連接池
}

似曾相識(shí)吧?沒(méi)錯(cuò),只要對(duì)服務(wù)連接池進(jìn)行少量改動(dòng):

獲取Service連接的CPool.GetServiceConnection()【返回任何一個(gè)可用Service連接】改為CPool.GetServiceConnection(longid)【返回id取模相關(guān)聯(lián)的Service連接】這樣的話,就能夠保證同一個(gè)數(shù)據(jù)例如uid的請(qǐng)求落到同一個(gè)服務(wù)Service上。

由于數(shù)據(jù)庫(kù)層面的讀寫(xiě)并發(fā),引發(fā)的數(shù)據(jù)庫(kù)與緩存數(shù)據(jù)不一致的問(wèn)題(本質(zhì)是后發(fā)生的讀請(qǐng)求先返回了),可能通過(guò)兩個(gè)小的改動(dòng)解決:

1)修改服務(wù)Service連接池,id取模選取服務(wù)連接,能夠保證同一個(gè)數(shù)據(jù)的讀寫(xiě)都落在同一個(gè)后端服務(wù)上

2)修改數(shù)據(jù)庫(kù)DB連接池,id取模選取DB連接,能夠保證同一個(gè)數(shù)據(jù)的讀寫(xiě)在數(shù)據(jù)庫(kù)層面是串行的

四、總結(jié)

本篇文章的作用在于提出分布式緩存的問(wèn)題

實(shí)現(xiàn)思路還可以是分布式鎖,這里只是拋磚引玉

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決 Redis 數(shù)據(jù)傾斜、熱點(diǎn)等問(wèn)題

    解決 Redis 數(shù)據(jù)傾斜、熱點(diǎn)等問(wèn)題

    ?單臺(tái)機(jī)器的硬件配置有上限制約,一般我們會(huì)采用分布式架構(gòu)將多臺(tái)機(jī)器組成一個(gè)集群,這篇文章主要介紹了解決 Redis 數(shù)據(jù)傾斜、熱點(diǎn)等問(wèn)題,需要的朋友可以參考下
    2022-12-12
  • Redis的過(guò)期策略以及內(nèi)存淘汰機(jī)制詳解

    Redis的過(guò)期策略以及內(nèi)存淘汰機(jī)制詳解

    這篇文章主要介紹了Redis的過(guò)期策略以及內(nèi)存淘汰機(jī)制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • 一次關(guān)于Redis內(nèi)存詭異增長(zhǎng)的排查過(guò)程實(shí)戰(zhàn)記錄

    一次關(guān)于Redis內(nèi)存詭異增長(zhǎng)的排查過(guò)程實(shí)戰(zhàn)記錄

    這篇文章主要給大家分享了一次關(guān)于Redis內(nèi)存詭異增長(zhǎng)的排查過(guò)程實(shí)戰(zhàn)記錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • 聊一聊Redis與MySQL雙寫(xiě)一致性如何保證

    聊一聊Redis與MySQL雙寫(xiě)一致性如何保證

    一致性就是數(shù)據(jù)保持一致,在分布式系統(tǒng)中,可以理解為多個(gè)節(jié)點(diǎn)中數(shù)據(jù)的值是一致的。本文給大家分享Redis與MySQL雙寫(xiě)一致性該如何保證,感興趣的朋友一起看看吧
    2021-06-06
  • Redis不同數(shù)據(jù)類型的命令語(yǔ)句詳解

    Redis不同數(shù)據(jù)類型的命令語(yǔ)句詳解

    這篇文章主要介紹了Redis不同數(shù)據(jù)類型的命令語(yǔ)句,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10
  • Redis 2.8-4.0過(guò)期鍵優(yōu)化過(guò)程全紀(jì)錄

    Redis 2.8-4.0過(guò)期鍵優(yōu)化過(guò)程全紀(jì)錄

    這篇文章主要給大家介紹了關(guān)于Redis 2.8-4.0過(guò)期鍵優(yōu)化的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 詳解redis腳本命令執(zhí)行問(wèn)題(redis.call)

    詳解redis腳本命令執(zhí)行問(wèn)題(redis.call)

    這篇文章主要介紹了redis腳本命令執(zhí)行問(wèn)題(redis.call),分別介紹了redis-cli命令行中執(zhí)行及l(fā)inux命令行中執(zhí)行問(wèn)題,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-03-03
  • redis刪除key下所有value步驟詳解

    redis刪除key下所有value步驟詳解

    在使用Redis時(shí),經(jīng)常需要?jiǎng)h除某個(gè)key下的所有value,本文就來(lái)詳細(xì)的介紹一下redis刪除key下所有value步驟,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Redis中LRU淘汰策略的深入分析

    Redis中LRU淘汰策略的深入分析

    這篇文章主要給大家介紹了關(guān)于Redis中LRU淘汰策略的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Windows環(huán)境下查看、添加、修改redis數(shù)據(jù)庫(kù)的密碼兩種方式

    Windows環(huán)境下查看、添加、修改redis數(shù)據(jù)庫(kù)的密碼兩種方式

    在Windows系統(tǒng)上設(shè)置Redis密碼的過(guò)程與Linux系統(tǒng)類似,但需注意幾個(gè)關(guān)鍵步驟以確保正確配置,這篇文章主要給大家介紹了關(guān)于Windows環(huán)境下查看、添加、修改redis數(shù)據(jù)庫(kù)的密碼兩種方式,需要的朋友可以參考下
    2024-07-07

最新評(píng)論