來自:碼農翻身(微訊號:coderising)
為了能讓Tomcat他們訪問, 我提供了幾十個資料庫連線——不能提供更多了,因為每個連線都要耗費我不少資源。
這些天Tomcat他們實在不像話,資料庫讀寫的請求像大海的波濤一樣洶湧澎湃,不斷向我襲來。
996是別想了, 24*7才是殘酷人生。
我沒辦法, 只好拼命地壓榨硬碟,看著他的磁頭在光滑的碟片上滑來滑去,尋找磁軌,定位扇區,讀取資料。這小夥子挺不錯的, 任勞任怨,但是就是太慢,居然比記憶體慢幾千倍。
很快,連硬碟也招架不住了,他對我說:“MySQL大哥,再這樣下去我就要壞掉了。”
果然,沒過幾天,硬碟病倒了,系統崩潰了。
第二天我一覺醒來,就發現系統重啟了,但是有點不對勁,這Tomcat發來的SQL怎麼這麼少啊!還都是些Insert, Update, Delete !
硬碟對我說:“你還不知道吧,昨天晚上我們的主人張大胖做了個資料庫的讀寫分離!”
“讀寫分離?”
“是啊, 張大胖統計了一下, 我們讀和寫的比例大概是20:1, 非常適合讀寫分離,簡單來說,就是建立多個資料庫,你是主庫,主要負責寫,還有兩個從庫,主要負責讀。這樣我們就沒有多少壓力了。”
“我這裡存了這麼多資料, 怎麼複製給另外兩個小弟呢?” 我問道。
“這你不用擔心,張大胖昨天已經給你做了一個快照,他把快照已經複製到了那兩個小弟那裡。接下來你只需要把今天早上產生的新的資料發過去就行了。”
正在這個時候,那個叫旺財的小弟給我打招呼了: “大哥,你把你那裡的執行過的Insert, Update, Delete這樣的SQL陳述句都記錄下來,然後發給我和小強,我們倆要這些SQL在我們自己的資料庫上’重放’一下!”
我看了一下自己的配置,果然如此,我只需要把SQL陳述句發過去就OK了。
有了兩個小弟的承接讀操作,我的工作大大減輕,又可以和硬碟喝茶聊天了。
可是沒多久,Tomcat氣衝衝地來質問我:“你們怎麼搞的,資料出現不一致了,Order表, rand_num那一列!”
這是怎麼回事? 我可是把所有的SQL陳述句都發給旺財和小強執行了啊,怎麼會不一致?
我們三個不敢怠慢, 趕緊翻看最近執行的SQL, 尤其是更新Order表, rand_num列相關的。
終於發現了罪魁禍首,就是這個函式: RAND() , 它會傳回一個隨機數, 經過處理後,更新到rand_num這一列。
在不同的資料庫執行,這個函式傳回的值也就不同,這就會導致我們的資料不一致了。
我感到非常羞愧,因為資料的一致性是我們資料庫家族最引以為豪的特性。 在單機的時候,我們自己就可以透過事務來保證了。 但是一旦有多個資料庫,形成了分散式的環境,想讓大家都保持一致,怎麼會這麼麻煩?
我們只好請張大胖手工把資料改成一致的, 然後再想新的辦法。
小強說道:“大哥,我提議一個新方法,以後你別記錄SQL了,你只記錄SQL的所影響的行和相關的值,然後把這些日誌發給我們,例如:
對於Insert, 記錄下所有列的新值。
對於Delete,記錄下到底是哪一行被刪除(用主鍵來標識)
對於Update,記錄下哪一行被更新(用主鍵來標識),以及被更新的列和新值
有了這些日誌,我們就可以清楚地知道你那邊到底發生了什麼變化,我們把這些日誌應用到我們的資料庫上就可以了!”
鑒於上一次的教訓,這次我們仔細分析各種例外情況,確保沒有問題才正式採用。
我,旺財和小強通力合作,新的複製方式工作得很好。直到有一天我們遇到了一個Update陳述句:
update xxx set flag = 0;
這個陳述句一下子更新了幾十萬條資料。 在之前使用基於SQL的複製時,記錄下這一條陳述句就行了。 用現在的方式,得記錄幾十萬條資料,這太要命了!
怎麼辦? 退回到原來的“基於SQL的複製”,肯定不行!
要不預設用SQL複製? 如果SQL執行結果“不確定”,例如有RAND()函式呼叫,那我們就使用陳述句複製。
這是一種混合的樣式,雖然麻煩,但也只能如此了。
深更半夜Tomcat又來找我:“有個使用者在咱們發了一個帖子,我在你這裡做了Insert 操作,然後使用者掃清頁面的時候,我從旺財那裡讀取資料,卻讀不到! 現在人家來投訴我們了!”
我心想,這傢伙也太快了吧, 居然比我複製資料的速度還快。
我又檢查了一下我和旺財之間的複製通道,由於網路原因,確實是有點延遲。
我對Tomcat說:“這是小事情,複製很快完成,他多掃清幾次肯定就可以了。”
Tomcat怒道:“這是嚴重的使用者體驗問題,怎麼是小事?”
“資料複製延遲多正常啊,反正我們三個能保證最終的一致性!”
Tomcat說:“最終一致性? 在我這裡可不行! 我給你們出個主意,我在insert資料的時候,你還沒有複製完成,怎麼就給我說已經insert成功了? 你必需得等到資料複製完成才能說insert成功!! 你的正確次序應該是這樣的。”
旺財一看到這個圖,大驚失色:“萬萬不可, 這樣一來就是同步複製了,如果網路比較慢, 第2.1和第2.2步遲遲不能完成, 那我們大哥就沒法告訴你插入資料成功, 使用者連帖子都發表不了!”
“是啊,這種使用者體驗會更差!” 小強幫腔。
Tomcat說:“我不管,反正是你們的問題!你們資料庫得想辦法解決!”
我說:“這個問題啊,本質上是資料延遲導致的,但是在分散式環境下這是不可避免的,我們在資料庫層面是解決不了的, 你們在應用層面多想想辦法吧。”
“能有什麼辦法?”
我說: “比如,對於不能容忍延遲的操作,都在我這裡(主庫)來讀寫,或者用個什麼方法判斷主庫和從庫是不是已經一致了。”
“也可以用個取巧的辦法, 讓使用者發表完帖子後等個幾秒鐘再來掃清……” 旺財補充。
Tomcat嘆了一口氣:“唉,你們這些傢伙啊, 只會推卸責任! 這我可管不了, 我們看看張大胖主人會怎麼辦吧!”
對於這種資料複製延遲的問題, 你會怎麼辦呢? 歡迎留言討論!
作者簡介: 劉欣,前IBM架構師,近20年從業經驗,”碼農翻身”公眾號作者,暢銷書《碼農翻身》作者,用故事講解技術是拿手好戲。 撥開技術迷霧,輕鬆瞭解技術本質,從”碼農翻身”開始。
朋友會在“發現-看一看”看到你“在看”的內容