問(wèn)題
如果數(shù)據(jù)庫(kù)的數(shù)據(jù)在redis中有一份緩存,那么數(shù)據(jù)修改時(shí),就需要在分布系統(tǒng)中的兩個(gè)獨(dú)立點(diǎn)同步修改。由于整個(gè)操作不是原子的,無(wú)論先修改哪一個(gè),都會(huì)有短暫的不一致。
由此帶來(lái)另外兩個(gè)問(wèn)題:1. 存在并發(fā)時(shí),非原子操作可能引入并發(fā)問(wèn)題。2. 如果修改操作的兩步中,后一步失敗,那么也會(huì)造成緩存與數(shù)據(jù)庫(kù)的不一致。
如何解決(強(qiáng)一致)?
要解決原子操作的不一致問(wèn)題,只能通過(guò)鎖來(lái)解決 。將兩步操作通過(guò)鎖變?yōu)樵硬僮?。我們可以使用redis,為每個(gè)key構(gòu)造分布鎖。
具體流程如下:
- 讀取時(shí)將數(shù)據(jù)與鎖一同返回,如果發(fā)現(xiàn)數(shù)據(jù)未加鎖,則認(rèn)為當(dāng)前數(shù)據(jù)有效。
- 讀取時(shí),如果發(fā)現(xiàn)已經(jīng)上了寫(xiě)鎖,則重試。
- 寫(xiě)數(shù)據(jù)時(shí),首先嘗試加鎖。此鎖鎖定1秒時(shí)間。如果加鎖成功,開(kāi)始更新數(shù)據(jù)庫(kù)。無(wú)論更新失敗或者成功都解鎖。如果成功,同時(shí)使緩存過(guò)期。
- 寫(xiě)數(shù)據(jù)時(shí),如果加鎖失敗。則重試。
- 如果加鎖成功,更新數(shù)據(jù)庫(kù)成功,但是解鎖失敗,那么鎖將在1s后自動(dòng)解鎖。
存在的缺點(diǎn)
- 在正常的流程中,如果寫(xiě)操作過(guò)于頻繁,那么大量的讀操作、寫(xiě)操作會(huì)被阻塞。
- 在最壞的情況下,某個(gè)key可能會(huì)被鎖超過(guò)1s。
其它方法
如果對(duì)一致性要求不高,那么在寫(xiě)庫(kù)之前,可以先設(shè)置key為1s后過(guò)期,再更新數(shù)據(jù)庫(kù)。如果更新key失敗,則重試。更新數(shù)據(jù)庫(kù)完成后,設(shè)置key過(guò)期。如果設(shè)置過(guò)期失敗,那么數(shù)據(jù)最多有1s不一致。