數據出問題了!
一次偶發的端上問題。
排查日志、監控、數據、代碼邏輯。
服務沒有添加事務性保障,不可避免的數據不一致:緩存有數據,數據庫沒數據或者相反;有A階段數據,沒有B階段數據;該有的數據沒有,不該有的數據卻存在。
主從機制遇到了強一致性需求,偶發的緩存不一致。
服務被埋下了錯誤的邏輯,日積月累全量的錯誤數據。
... ...
不管是哪種情景,總之是數據變臟了。
怎么辦?
一、處理當前問題的數據
對的,不是所有問題數據,是當前問題的數據,我們通常稱這種為緊急的問題,重不重要分情景另說。
用戶的問題訴求,總是需要第一時間響應的,這個關系大公司產品的使用體驗及公司形象,不容推延。
當然,在此之前,還是需要保留現場的,這些現場就是你排查的經過,每一步印證問題所提取的信息。
經驗需要積累,教訓也要留存。
二、修復引發問題的誘因
已經排查了問題的所在,也已經處理了個例的問題。那么接下來需要做的就是去修正服務的問題。
1、事務性保障問題
首先確定問題點是不是關鍵核心模塊,是不是可以容忍。
類如,交易系統,訂單、庫存、賬戶余額等關聯,是一點錯亂都無法忍受的,這就要從全方位進行數據一致性、正確性的保障。
服務邏輯層面的接口冪等性,業務操作的事務性,補償、重試保障可靠性;消息中間件層面的或涉及消息的持久化、鏡像容錯等;數據存儲層面的分布式緩存、數據庫主從等,不一例舉。
類如,閱讀數,點贊數此等,很少人會去關注具體的多一個或者少一個(較真兒的除外),某大V寫了篇文章,瞬間閱讀數就查過了幾萬,轉發上千,大V不會去關心本該有30001的閱讀數只有30000。
此類數據,或者求個最終一致性,或者偶爾的遺失數據也可以忽略。也就不必要去添加額外的耗損性能的事務性保障。
2、主從與強一致性
主從與強一致性就像兩個同極的磁鐵,通常都是無法共存的。
以前遇到過有同事在提到“剛寫進去又查出來”總會發笑,那種認為可笑的發笑。
而往往此時,我沒有笑,只有疑惑和思考。疑惑是笑的同事,為什么會笑;思考是,是不是只有這樣才能達到目的,有沒有更好的替代方式。
通常現實中的業務都是大業務套着小業務,小業務套着更小的業務,環環相扣,一環連着一環。也如,一個人背着一打木板過河,放下一個踩上去,然后再放下下一個,有二必先有一。
所以,固化前一個變更,然后進行下一個變更,這,很正常。
然而,隨着信息時代的爆炸式發展,信息服務的載重和載壓一年便是一個量級,這就不斷演化了現如今的許多多般復雜信息服務。而在這其中,便是這“主從”應運而生,橫亘至今。
主從是一種分治的思想,讀場景和寫場景,量級不同,處理邏輯不同,保障性不同,所以涉及數據層面,就可以采用不同的提供方式。
緩存或者數據庫,從主節點分離出一個或多個從節點專門用於數據的查詢,從節點實時同步主節點的數據變更,數據會有一定的延遲,但是基本符合現實的應用場景,我們追求的是不那么強的最終一致性。
主節點則主要負責對數據變更的處理,以及,必要的數據查詢,對於需要強一致性的場景。
在實際的應用開發中,要特別注意篩選出對數據延遲零容忍的的業務邏輯,結合實際,應用主節點進行數據查詢或者其它手段來保障數據的強一致性需求。
3.避免不必要的低級邏輯錯誤
這里,我們強調的是因為疏忽,非因個人能力而導致邏輯錯誤。
以前讀過卡耐基的人性的弱點,人是情感的生物,一生都在與自己的弱點作斗爭。人類自大,容易煩躁,又缺乏耐心。而這,往往會導致一些不必要的的失誤。
屬性賦值錯了,未賦值;空值未判斷; 特殊狀態值未過濾等等,細枝末節往往影響深遠。
人不可能不犯錯誤,我們需要做的是怎么去避免不必要的錯誤。
這里需要提一下就是 Code Review 的重要性。一個人很難發現自己錯誤,這其中有主觀情感因素及客觀認知問題。旁觀者清,Code Review 的過程就是一個發現,糾正,優化改進的過程,每個人的關注點不同,或全局的架構設計,或細節的變量命名,層層濾網過濾之后,將極大的減少出錯的可能。有一點需要指出的是,很多初次接觸 Code Review 的開發人員,往往會有抵觸情緒,或認為不必要,后羞於漏洞與眾人,團隊間在此方面需要建設共同的認知,意識,規約是非常有必要的。
三、處理臟數據
數據臟了怎么辦?洗洗就好了!
臟數據好處理嗎?好處理。問題是臟數據在哪里?
單個用戶問題的數據可以針對性的去處理。而那些隱藏的臟數據則需要去定位清洗。
1、限定影響范圍
哪些數據受影響了?從什么時候開始?影響是什么?
限定業務邏輯范圍,影響的數據面,比如,粉絲+好友+群組關聯的數據群,A關注了B,A多了一個好友,B多了一個粉絲,A把B放在了特定的群組里。
限定時間范圍:從什么時候開始上線了或者從什么時候觸發了有問題的業務邏輯,比如,對 X 對象的變更修改調整起始於 1 號,那么就需要查找所有 1 號至今的所有與 X 對象修改相關的活動數據。
限定影響:確定對數據的影響是什么,才能進一步決定下一步怎么處理,比如漏掉了一個屬性賦值,那么是否可以根據其它狀態屬性進行修正?改刪除的數據沒有刪除,是否直接刪除就能解決問題?
2、篩查數據
有了第一步的基礎,這一步需要做的就是找出問題數據。one by one,一個一個與校准值進行對比過濾。通常,我們會添加一個臨時的處理接口進行實時的校驗。
這里,需要指出的是,不同量級的數據的處理篩查方式上會有所區別。
如果,你的數據量是萬級別的,那么單個順序過濾就行了,不需要做什么額外的處理;
如果,你的數據量是十萬級別的,那么你可能需要在處理接口上添加批處理。
如果,你的數據量是百萬級別的,那么除了接口批處理外,腳本的多線程處理也會需要。
如果,你的數據量是千萬級別的,臨時擴展一些數據處理節點也會大大提高處理效率。
3、處理臟數據
臟數據總歸不是大量級的,處理之前,必要的校驗,驗證不可或缺。
選取測試數據或者從臟數據中選擇少許進行處理結果驗證。充分認證后,再進行全量處理。