今天下午有同事反饋訂單列表頁狀態(tài)與詳情頁狀態(tài)不一致宋欺。
背景:
用戶下單及付款等操作后,部分訂單信息會推送到公司二方團隊用于列表頁展示胰伍。
(列表頁由平臺統(tǒng)一維護齿诞,詳情頁業(yè)務(wù)方維護)
有業(yè)務(wù)事件發(fā)生時,會推一次訂單骂租。因而同一訂單會多次推送祷杈。
不同業(yè)務(wù)事件間隔不定,存在并發(fā)推送一條數(shù)據(jù)的場景菩咨。
核對日志吠式,發(fā)現(xiàn)了問題。
訂單推送時抽米,平臺會以version的大小作為是否拋棄該次推送結(jié)果特占。
背景:
version計算邏輯:用當(dāng)前時間減去下單時間
將歷史推送的version存于DB,每次從DB中獲取當(dāng)前的version(只查有效的云茸,不含軟刪)是目。
version+1后,先將當(dāng)前的version軟刪标捺,再寫進一條數(shù)據(jù)懊纳。
(超過Integer.MAX_VALUE有單獨邏輯)
若version不存在,則會根據(jù)當(dāng)前時間重新生成一條version亡容,寫入DB嗤疯。
坑點:平臺接收推送數(shù)據(jù)成功,數(shù)據(jù)格式正確闺兢,即會告知業(yè)務(wù)方推送成功茂缚。
對推送version小于歷史version的數(shù)據(jù),平臺內(nèi)部會拋棄該次推送的數(shù)據(jù)屋谭,但是仍然告知業(yè)務(wù)方推送成功脚囊。
根據(jù)訂單號去查該訂單的推送version記錄:
verison記錄
可以看出有一條version超大。從日志上看桐磁,35和10973兩條記錄的推送間隔在ms級別悔耘。
由于平臺的策略,導(dǎo)致version10973之后的推送數(shù)據(jù)均會失效我擂。
根據(jù)DB中version數(shù)據(jù)反推衬以,時序如下:
請求時序
這里還存在代碼bug:之前是向從庫查詢version記錄缓艳,在A將34置為無效并同步到從庫后,B讀從庫發(fā)現(xiàn)無記錄泄鹏,然后B會向主庫寫了一條新的version記錄10973郎任。讀從庫增大了A、B之間的時間差备籽。
發(fā)現(xiàn)了問題之后舶治,fix策略:
查詢version均走主庫
若不存在version,生成后寫入车猬;
若存在霉猛,將當(dāng)前version+1,帶樂觀鎖version更新(放棄軟刪+新增步驟)珠闰;
若更新失敗惜浅,則查詢實時的version,+1后再次帶樂觀鎖version更新伏嗜;
對于推送的數(shù)據(jù)部分坛悉,實時查主庫后再推送;
(實際fix邏輯比這復(fù)雜承绸,由于一些原因不過多描述)
事后反思裸影,存在以下問題:
關(guān)鍵操作,不能讀從庫军熏;
對于同一條數(shù)據(jù)的操作轩猩,不能先軟刪,再新增一條數(shù)據(jù)(非原子操作荡澎,會造成很多問題均践,如軟刪遺漏、新增失敗摩幔,均會導(dǎo)致問題)彤委;
平臺應(yīng)明確告知會拋棄當(dāng)前數(shù)據(jù)(告知原因更佳),而不是告知成功或衡;
推送前應(yīng)實時查最新數(shù)據(jù)焦影,而是已有數(shù)據(jù);