網際網路一致性架構設計 -- db和cache一致性
需求分析
下面兩種情況會出現髒資料:
單庫情況下
服務層的併發讀寫,快取與資料庫的操作交叉進行,這種情況雖然少見,但理論上是存在的,後發起的請求b在先發起的請求a中間完成了。
1. 請求a發起乙個寫操作,第一步淘汰了cache,然後這個請求因為各種原因在服務層卡住了(進行大量的業務邏輯計算,例如計算了1秒鐘),如上圖步驟1
2. 請求b發起乙個讀操作,讀cache,cache miss,如上圖步驟2
3. 請求b繼續讀db,讀出來乙個髒資料,然後髒資料入cache,如上圖步驟3
4. 請求a卡了很久後終於寫資料庫了,寫入了最新的資料,如上圖步驟4
主從同步
讀寫分離的情況下,讀從庫讀到舊資料,這種情況請求a和請求b的時序是完全沒有問題的,是主動同步的時延(假設延時1秒鐘)中間有讀請求讀從庫讀到髒資料導致的不一致。
1. 請求a發起乙個寫操作,第一步淘汰了cache,如上圖步驟1
2. 請求a寫資料庫了,寫入了最新的資料,如上圖步驟2
3. 請求b發起乙個讀操作,讀cache,cache miss,如上圖步驟3
4. 請求b繼續讀db,讀的是從庫,此時主從同步還沒有完成,讀出來乙個髒資料,然後髒資料入cache,如上圖步4
5. 最後資料庫的主從同步完成了,如上圖步驟5
不一致的原因
1. 單庫情況下,服務層在進行1s的邏輯計算過程中,可能讀到舊資料入快取
2. 主從庫+讀寫分離情況下,在1s鐘主從同步延時過程中,可能讀到舊資料入快取
建議:先淘汰快取,再更新資料庫
單庫情況的優化
自己重寫資料庫連線池,例如根據userid取模,得到唯一的資料庫連線,如何做到「讓同乙個資料的訪問序列化」,只需要「讓同乙個資料的訪問通過同一條db連線執行」就行。
如何做到「讓同乙個資料的訪問通過同一條db連線執行」,只需要「在db連線池層面稍微修改,按資料取連線即可」?
獲取db連線的
cpool.getdbconnection()【返回任何乙個可用db連線】
改為cpool.getdbconnection(longid)【返回id取模相關聯的db連線】
1. service的上游是多個業務應用,上游發起請求對同乙個資料併發的進行讀寫操作,上例中併發進行了乙個uid=1的餘額修改(寫)操作與uid=1的餘額查詢(讀)操作。
2. service的下游是資料庫db,假設只讀寫乙個db。
3. 中間是服務層service,它又分為了這麼幾個部分
(1) 最上層是任務佇列
(2) 中間是工作執行緒,每個工作執行緒完成實際的工作任務,典型的工作任務是通過資料庫連線池讀寫資料庫
(3) 最下層是資料庫連線池,所有的sql語句都是通過資料庫連線池發往資料庫去執行的
4. 當用uid=1寫資料庫時,正在使用資料庫連線池中的連線1。
5. 此時用uid度資料庫,同樣要使用連線1,這樣讀操作就會進行等待,要前面寫資料完畢,釋放資料庫連線後才能讀資料。
拓展
能否做到同乙個資料的訪問落在同乙個服務上?
重新修改結構如下:
獲取service連線的
cpool.getserviceconnection()【返回任何乙個可用service連線】
改為cpool.getserviceconnection(longid)【返回id取模相關聯的service連線】
1. 業務應用的上游不確定是啥,可能是直接是http請求,可能也是乙個服務的上游呼叫
2. 業務應用的下游是多個服務service
3. 中間是業務應用,它又分為了這麼幾個部分
(1)最上層是任務佇列【或許web-server例如tomcat幫你幹了這個事情了】
(2)中間是工作執行緒【或許web-server的工作執行緒或者cgi工作執行緒幫你幹了執行緒分派這個事情了】,每個工作執行緒完成實際的業務任務,典型的工作任務是通過服務連線池進行rpc呼叫
(3)最下層是服務連線池,所有的rpc呼叫都是通過服務連線池往下游服務去發包執行的
4. 當請求service層時,根據uid來取模,決定使用哪個service的連線
主從同步情況下的優化
既然舊資料就是在那1s的間隙中入快取的,是不是可以在寫請求完成後,再休眠1s,再次淘汰快取,就能將這1s內寫入的髒資料再次淘汰掉呢?
方法一
1. 先淘汰快取
2. 再寫資料庫(這兩步和原來一樣)
3. 休眠1秒,再次淘汰快取
缺點:所有的寫請求都阻塞了1秒,大大降低了寫請求的吞吐量,增長了處理時間,業務上是接受不了的。
方法二
1. 先淘汰快取
2. 再寫資料庫(這兩步和原來一樣)
3. 不再休眠1s,而是往訊息匯流排esb傳送乙個訊息,傳送完成之後馬上就能返回
缺點:需要業務線的寫操作增加乙個步驟,這就是我們所謂的**入侵
方法三
業務線的**就不需要動了,新增乙個線下的讀binlog的非同步淘汰模組,讀取到binlog中的資料,非同步的淘汰快取。
總結
單庫
由於資料庫層面的讀寫併發,引發的資料庫與快取資料不一致的問題(本質是後發生的讀請求先返回了),可能通過兩個小的改動解決:
1. 修改服務service連線池,id取模選取服務連線,能夠保證同乙個資料的讀寫都落在同乙個後端服務上
2. 修改資料庫db連線池,id取模選取db連線,能夠保證同乙個資料的讀寫在資料庫層面是序列的
主從資料庫
在「異常時序」或者「讀從庫」導致髒資料入快取時,可以用二次非同步淘汰的「快取雙淘汰」法來解決快取與資料庫中資料不一致的問題,具體實施至少有三種方案:
1. timer非同步淘汰(本文沒有細講,本質就是起個執行緒專門非同步二次淘汰快取)
2. 匯流排非同步淘汰
3. 讀binlog非同步淘汰
網際網路一致性架構設計 DB雙主一致性
網際網路一致性架構設計 db雙主一致性 mysql資料庫集群常使用一主多從,主從同步,讀寫分離的方式來擴充資料庫的讀效能,保證讀庫的高可用,但此時寫庫仍然是單點。解決方法 在乙個mysql資料庫集群中可以設定兩個主庫,並設定雙向同步,以冗餘寫庫的方式來保證寫庫的高可用。需求分析 資料冗餘會引發資料的...
網際網路一致性架構設計 session一致性
網際網路一致性架構設計 session一致性 session是什麼 伺服器為每個使用者建立乙個會話,儲存使用者的相關資訊,以便多次請求能夠定位到同乙個上下文。web開發中,web server可以自動為同乙個瀏覽器的訪問使用者自動建立session,提供資料儲存功能。最常見的,會把使用者的登入資訊 ...
關於網際網路「一致性」架構設計的一切
前篇 都收到好評 本文再做總結,體系化介紹網際網路一致性架構技術。一 session一致性 文章 session一致性,架構設計,實踐 內容 二 資料庫主從一致性 文章 資料庫主從一致性,架構設計,實踐 內容 三 資料庫雙主一致性 文章 資料庫雙主一致性,架構設計,實踐 內容 四 資料庫與快取一致性...