引言
該文是對《分布式之資料庫和緩存雙寫一緻性方案解析》,一文的補充。部落客在該文中,提到了這麼一句話
應該沒人問我,為什麼沒有先更新緩存,再更新資料庫這種政策。
部落客當時覺得,這種更新政策比較簡單,沒必要多做說明,結果太多人留言給部落客,問我為什麼不說這套方案?好吧,部落客先跟大家道個歉,是我的問題。是以再開一文,把這個方案說明一下
正文
下面說明一下先更緩存,再更新資料庫這套方案
更新資料庫失敗了怎麼辦?
這個問題其實很好解決,提供一個補償措施即可。這個補償措施,大家靈活變通,部落客隻是舉例,如下圖所示:

流程如下所示
(1)更新緩存資料;
(2)更新資料庫失敗
(3)将需要更新的sql發送至消息隊列
(4)自己消費消息,獲得需要更新的sql
(5)繼續重試更新操作,直到成功
其他方案不列舉,因為重點不在這,在下面的情況
有存在其他的線程安全問題麼?
有的,假設這會同時有請求A和請求B進行更新操作,那麼會出現
(1)線程A更新了緩存
(2)線程B更新了緩存
(3)線程B更新了資料庫
(4)線程A更新了資料庫
請求A更新資料庫應該比請求B更新資料庫早才對,但是因為網絡等原因,B卻比A更早更新了資料庫。這就導緻了髒資料,是以不考慮。
可是,這時候有一個細心的讀者,給部落客舉了一個反例。該例子出自《從P1到P7——我在淘寶這7年》這篇部落格,
部落客偷個懶,直接貼一下該部落格的原話
在【招财進寶】項目中有一個技術的細節值得拿出來說說,淘寶商品詳情頁面每天的流量在10億以上,裡面的内容都是放在緩存裡的,做【招财進寶】的時候,我們要給賣家顯示他的商品被浏覽的次數,這個數字必須實時更新,而用緩存的話一般都是異步更新的。于是商品表裡面增加了這樣一個字段,每增加一個PV這個字段就要更新一次。釋出上去一個小時資料庫就挂掉了,撐不住這麼高的update。資料庫撐不住怎麼辦?一般的緩存政策是不支援實時更新的,這時候多隆大神想了個辦法,在apache上面寫了一個子產品,這個數字根本不經過下層的web容器(隻經過apache)就寫入一個集中式的緩存區了,這個緩存區的資料再異步更新到資料庫。好像什麼問題,到了多隆手裡,總能迎刃而解。
好吧,如果沒耐心的讀者,直接看部落客的總結吧。上面巴拉巴拉一堆,就是說,當時他們有一個讀多寫多的場景,然後多隆大神用了先更緩存,再異步更新資料庫的政策。
難道淘寶的大神沒發現線程安全問題?
不是的,上面提到的場景具有一個特殊性。我們先摘取關鍵一句話
于是商品表裡面增加了這樣一個字段,每增加一個PV這個字段就要更新一次
ps:PV是page view,頁面浏覽量的意思。
部落客鬥膽猜測,他們做的應該是使用者每次點選,資料庫裡的這個字段就加一的操作。
那我們這時的SQL一般是這麼寫
update product_tb set number = number+1 where product_id =xxx
大家注意到了麼,并發執行這句SQL并不需要關心執行順序。哪個更新線程先執行加一的SQL語句 ,與操作順序有什麼關系呢?
再說的通俗一點,假設我們同時有請求A和請求B進行更新操作,那麼會出現
因為他們這個時候執行的sql是無序的,是以上面的步驟(3)和步驟(4)哪一個步驟先執行,并沒有關系。最終結果一定是一緻的。
容部落客啰嗦,來個執行個體,假設表product_tb如下
product_id | number |
---|---|
1 | 3 |
這時請求A和請求B同時對product_id為1的資料進行更新操作,無論是按出現并發問題時的順序 | |
(1)線程B更新了資料庫,進行加一 | |
(2)線程A更新了資料庫,進行加一 | |
還是正常的順序 | |
(1)線程A更新了資料庫,進行加一 | |
(2)線程B更新了資料庫,進行加一 | |
最終結果都是 |
5 | |
ok。說到這裡,大家應該是懂了。換句話說,如果此時,操作的sql是有序的,就會出現最上面說的線程安全問題。是以,希望大家針對問題多思考總結。 | |
給大家留一個思考問題? | |
如果此時是一個讀多寫多的場景,又要求更新資料庫的操作必須嚴格保證順序,那這個時候怎麼保證緩存和資料庫的一緻性?大家可以來我的部落格留言。 |
總結
本文是對上次文章的一次文章的一次補充。隻怪部落客思考問題太過簡單,給大家留了個坑。是以再開一篇文章進行補充說明。希望大家能夠有所收獲。
作者:孤獨煙
出處: http://rjzheng.cnblogs.com/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如果覺得還有幫助的話,可以點一下右下角的【推薦】。