資料庫和快取一致性推薦方式

2021-10-23 16:18:06 字數 3269 閱讀 7862

資料儲存在資料庫中,為了加快業務訪問的速度,我們將資料庫中的一些資料放在快取中,那麼問題來了,如何確保db和快取中資料的一致性呢?我們列出了5種方法,大家都了解一下,然後根據業務自己選擇。

獲取快取邏輯

使用過定時器,定時重新整理redis中的快取。

db更新資料邏輯

更新資料不用考慮快取中的資料,直接更新資料就可以了

存在的問題

快取中資料和db中資料一致性可能沒有那麼及時,不過最終在某個時間點,資料是一致的。

獲取快取邏輯

c1:根據key在redis中獲取對應的value

c2:如果value存在,直接返回value;若value不存在,繼續下面步驟

c3:從資料庫獲取值,賦值給value,然後將key->value放入redis,返回value

更新db邏輯

u1:開始db事務

u2:更新資料

u3:提交db事務

u4:刪除redis中當前資料的快取

存在的問題

上面u3成功,u4失敗,會導致刪除快取失敗,導致快取中資料和db資料會不一致。

如果同時有很多執行緒到達c2發現快取不存在,同時請求c3訪問db,會對db造成很大的壓力

獲取快取邏輯

c1:根據key在redis中獲取對應的value

c2:如果value存在,直接返回value;若value不存在,繼續下面步驟

c3:從資料庫獲取值,賦值給value,然後將key->value放入redis,返回value

更新db邏輯

u1:刪除redis中當前資料的快取

u2:開始db事務

u3:更新資料

u4:提交db事務

存在的問題

更新資料的執行緒執行u1成功之後,u2還未執行時,此時獲取快取的執行緒剛好執行了c1到c3的邏輯,此時會將舊的資料放入redis,導致redis和db資料不一致

同樣存在方案2中說到的問題:如果同時有很多執行緒到達c2發現快取不存在,同時請求c3訪問db,會對db造成很大的壓力

對方案2做改進,確保db更新成功之後,刪除快取操作一定會執行,我們可以通過可靠訊息來實現,可靠訊息可以確保更新db操作和刪除redis中快取最終要麼都成功要麼都失敗,依靠的是最終一致性來實現的。

改進之後過程如下。

獲取快取邏輯

c1:根據key在redis中獲取對應的value

c2:如果value存在,直接返回value;若value不存在,繼續下面步驟

c3:從資料庫獲取值,賦值給value,然後將key->value放入redis,返回value

更新db邏輯

u1:開始db事務

u2:更新資料

u3:投遞刪除redis快取的訊息

u4:提交db事務

訊息消費者-清理redis快取的消費者

接受到清理redis快取的訊息之後,將redis中對應的快取清除。

存在的問題

更新db和清理redis中的快取之間存在一定的時間延遲,這段時間內,redis快取的資料是舊的,也就是說這段時間內db和快取資料是不一致的,但是最終會一致,這個不一致的時間可能比較小(這個需要看訊息消費的效率了)

同樣存在方案2中說到的問題:如果同時有很多執行緒到達c2發現快取不存在,同時請求c3訪問db,會對db造成很大的壓力

我們先了解一些知識。

redis中幾個方法

get(key)

獲取key的值,如果存在,則返回;如果不存在,則返回nil

setnx(key,value)
setnx的含義就是set if not exists,該方法是原子的,如果key不存在,則設定當前key成功,返回1;如果當前key已經存在,則設定當前key失敗,返回0

del(key)
將key對應的值從redis中刪除

資料庫相關知識
select v from t where t.key = #key# for update;

update t set v = #v# where t.key = #key#;

上面兩個sql會相互阻塞,直到其中乙個提交之後,另外乙個才可以繼續執行。

下面我們就通過上面的知識來實現db和快取強一致性。

更新資料邏輯

1.開啟db事務

2.update t set v = #v# where t.key = #key#;

3.根據key刪除redis中的快取:redisuti.del(key);

4.提交db事務

獲取快取邏輯
public

class

cacheutil

//過期時間為當前時間+5秒

string expiretimekey = key +

"expiretime"

;long expiretimevalue = system.

currenttimemillis()

+5000

;//setnx是原子操作,所以只有乙個會成功

int setnx = redisutils.

setnx

(expiretimekey, expiretimevalue +"")

;if(setnx ==0)

else

//重試

return

getcache

(key);}

else

return value;

}//redis工具類,內部方法為偽**

public

static

class

redisutils

//設定key對應的value

public

static

void

set(string key, string value)

//刪除redis中乙個key對應的值

public

static

void

del(string key)

//setnx的含義就是set if not exists,該方法是原子的,如果key不存在,

//則設定當前key成功,返回1;如果當前key已經存在,則設定當前key失敗,返回0

public

static

intsetnx

(string key, string value)

}}

資料庫和快取一致性

今天程式過程中突然想到了乙個問題,怎麼保證redis快取和mysql資料庫中的資料相同 一致性 即在更新資料時怎樣保證資料庫和redis快取始終相同。從理論上講,給快取設定過期時間是保證最終一致性的解決方案。這種方案下,所有寫操作以資料庫為準,對快取做最大努力即可。下面介紹的是不依賴於給快取設定過期...

資料庫和快取一致性方案

redis儲存快取,mysql儲存資料。快取進行有效期設定。但是更新mysql,不會更新快取。這樣導致快取和資料庫的一致性問題比較長 mysql更新後,進行更新redis快取。查詢的時候先查詢redis快取,如果沒有快取,只查詢資料庫進行更新快取 快取和資料庫不一致性的時間短 cache aside...

資料庫和快取一致性問題

前言 快取一致性是指業務在引入分布式快取系統後,業務對資料的更新除了要更新儲存以外還需要同時更新快取,對兩個系統進行資料更新就要先解決分布式系統中的隔離性和原子性難題。目前大多數業務在引入分布式快取後都是通過犧牲小概率的一致性來保障業務效能,因為要在業務層嚴格保障資料的一致性,代價非常高,業務引入分...