一次批量操作的優化

2022-09-03 00:54:08 字數 1391 閱讀 3919

最近在做賬務系統的批量核銷介面的優化,該介面的功能抽象來說就是暴露給另乙個系統,每次呼叫會進行計算並更新庫里的值(感覺好普通的樣子)。

假設我這邊的系統是r(received),對方系統是s(send),那麼現在的工作流程是這樣的:

1.請求分充值請求和消費請求。充值請求是商戶維度的,而消費是訂單維度的。而商戶則與訂單是一對多的對應關係,產品與商戶的關係也是一對多。除開特定的某一產品,每一商戶下均有幾千到幾十萬不等的訂單數目。

2.在日記賬(可看做交易資訊表)中儲存了發生交易的訂單號以及商戶號。核銷也是通過這個表的資料進行的。

3.商戶之上還有產品的維度,產品與商戶的對應關係基本是一對一,有乙個特例存在乙個產品對應幾百的商戶的情況。

4.優化方向可以從商戶和產品的角度入手,考慮到底是從商戶的維度進行核銷請求還是產品的維度。考慮到每日交易的結算單是從商戶維度產生的,因此確定以商戶的維度進行核銷請求,一方面保證了對外介面的維度統一,一方面由於只有乙個產品是特殊情況,因此不打算因為它而影響整個設計。

綜合以上考慮,優化之後的流程圖如下圖:

然而這樣做完之後發現效能獲得了大幅度提公升,之前單筆操作的耗時大概是150~500ms 之間,手動控制事務後單筆耗時只有30~50ms。然而在併發操作中發現了另外乙個問題:如果在核銷商戶 a 的過程中(假設處理執行緒的名稱為 thread-a),商戶 b 同時進行核銷操作(假設處理的執行緒名稱為 thread-b),如果 a 商戶核銷數目較大,達到幾萬甚至幾十萬的級別,那麼 thread-b 會因為長時間拿不到資料庫中表的許可權而丟擲 deadlock 異常,這明顯與我們想要的結果不符,因此只能繼續想對策。

之後想到每指定筆數(比如每100筆)進行一次事務提交,這樣在兼顧效能的同時還可以保證併發操作不會出現異常。這樣導致的另外乙個問題是,如果商戶 a 中有1000條資料,在核銷第500~600筆中的某一筆失敗了的話,這個區間的操作會回滾,但是之前的資料並不會,這樣一筆請求**失敗了很難發現錯誤點,也不好進行重推操作。為了解決這個問題,想了兩個方案:

1.在日誌中每次開啟一次事務就在日誌中列印該批操作的商戶號和起止編號,同時在提交的時候和出現異常的情況下也列印出來並報警。這樣如果發現某一批次失敗了的話,可以在日誌中查詢並重新推送這筆請求,然後在**中加以控制,只處理指定區間的核銷。

2.在日記賬表中新增標誌位,表示該筆是否成功核銷,處理的時候將每筆處理過的標識為成功,並且只處理標誌位不是成功的。這樣在出現失敗時重推請求,就不用考慮其他事情。

在仔細分析對比之後把第一種方案篩掉了,原因是依賴日誌不如依賴資料庫穩定,二來第二種方案邏輯上更容易理解。

以上。

一次針對批量查詢處理的優化

客戶呼叫批量查詢介面對solr核進行查詢時覺得查詢響應時間有些慢,介面的內部實現目前是順序執行每個查詢,再把結果彙總起來返回給呼叫方。因此,考慮引入執行緒池對查詢介面的內部實現進行重構優化。先宣告乙個大小可隨之增長的執行緒池,private executorservice executor exec...

記錄一次oracle批量插入操作

begin insert into t police person id,name,birthday,cardno,departmentid,policeid,callgroup,callno,callgpsid,telephone,position,mobilephone,address,emai...

記一次新建操作(insert)的優化過程

mysql的 insert常用方法 插入後返回插入成功後的主鍵 insert paramtype object sql cdata insert into ucdp budget plan gmt create,gmt modified,biz date,status name,biz code,s...