新聞中心
如果沒有這次全量數(shù)據(jù)對比工具,那么也許這個歷史問題會繼續(xù)隱藏著,直到發(fā)生線上事故才暴露出來,畢竟人工抽樣驗證發(fā)現(xiàn)的概率只有「5.8%」

公司專注于為企業(yè)提供成都網(wǎng)站制作、成都網(wǎng)站設(shè)計、微信公眾號開發(fā)、商城系統(tǒng)網(wǎng)站開發(fā),微信小程序定制開發(fā),軟件按需定制制作等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。憑借多年豐富的經(jīng)驗,我們會仔細了解各客戶的需求而做出多方面的分析、設(shè)計、整合,為客戶設(shè)計出具風格及創(chuàng)意性的商業(yè)解決方案,創(chuàng)新互聯(lián)建站更提供一系列網(wǎng)站制作和網(wǎng)站推廣的服務(wù)。
背景是發(fā)票系統(tǒng)有18500個電子發(fā)票訂單被財務(wù)系統(tǒng)駁回了,駁回原因是財務(wù)系統(tǒng)上線了全電發(fā)票需求,上線后電子發(fā)票枚舉被誤刪,無法處理電子發(fā)票。需要我們發(fā)票系統(tǒng)對這18500電子發(fā)票訂單,重新觸發(fā)提票,讓發(fā)票能正常開出來。也就是,我們需要刷數(shù)。刷數(shù)是個高危操作,極易引發(fā)線上問題。
經(jīng)驗教訓(xùn)告訴我們,刷數(shù)雖然是一種處理線上問題的方法,但是也特別容易引起二次事故。對于刷數(shù),我們需要像新需求一樣對待,經(jīng)過完備的需求分析、設(shè)計評審、代碼評審。主要考慮以下3點:
- 刷數(shù)范圍,怎么篩選問題數(shù)據(jù),評審過濾條件;
- 刷數(shù)程序,怎么修復(fù)問題數(shù)據(jù),評審代碼邏輯;
- 驗證方法,怎么驗證修復(fù)數(shù)據(jù),分析測試場景;
在刷數(shù)實施前,群里報備,周知相關(guān)方及相關(guān)人員。先試刷,驗證無問題后,再全刷,最后驗證問題數(shù)據(jù)已經(jīng)得以修復(fù)。這一套刷數(shù)流程,通過加強前期評審,能很好地預(yù)防缺陷,增強刷數(shù)成功的信心。但是人工評估可能遺漏場景,可能對真實數(shù)據(jù)情況把握不全,刷數(shù)的關(guān)鍵還在于最后的數(shù)據(jù)驗證。
抽樣驗證還是全量驗證,這是一個問題。抽樣驗證是人工隨機挑幾個數(shù)據(jù)進行驗證,我們通常傾向于使用抽樣驗證,一是抽樣驗證是一種科學的有效的驗證方法,雖然它存在一定概率的遺漏,但是很多時候是可以接受的風險;二是抽樣驗證也是無奈之舉,找不到辦法進行全量驗證。我們遇到的困難是,數(shù)據(jù)存在ES中,批量把所有數(shù)據(jù)查出來很麻煩,也無法直接編寫校驗邏輯,全量驗證似乎是不可能的。
全量驗證有2個思路:
- 如果能直連庫,那么先提數(shù),再寫程序?qū)Ρ龋?/li>
- 如果只能WEB頁面查數(shù),那么使用Python爬蟲提數(shù),再寫程序?qū)Ρ龋?/li>
后者適用于我們的情況。ES能通過WEB頁面查詢數(shù)據(jù),只要是WEB頁面,即使有Cookie,也能爬取到接口數(shù)據(jù)。F12抓包到查詢接口的URL、Cookie、入?yún)⒑?,使用Python的requests庫可以爬取查詢結(jié)果數(shù)據(jù):
url = 'http://xxx'
headers = {
'Cookie': 'xxx',
'Content-Type': 'application/json'
}
response = request('get', url=url, headers=headers)
result = response.json()我們使用這種方式,傳入訂單號,查詢到了申請單數(shù)據(jù),以便進行對比校驗邏輯。而訂單號,研發(fā)打在了日志里,需要下載日志文件后,進行解析,可以使用Python切片:
orders = set()
with open('some.log') as f:
for line in f.read().splitlines():
if 'xxx' in line:
orders.add(line[line.index('orderId='):line.index(',已執(zhí)行')].replace('orderId=', ''))
print(len(orders))
with open('orders.txt', 'w') as f:
f.writelines(','.join(orders)).index可以定位到關(guān)鍵詞的索引,然后[:]切片獲取指定內(nèi)容。
日志解析訂單號+爬蟲獲取申請單+編寫對比校驗邏輯,全量數(shù)據(jù)對比工具就完成了??墒?8500單,上萬級別數(shù)據(jù),要全部對比完,至少要幾個小時。是時候使用多線程了。
多線程第一步,拆解數(shù)據(jù),將18500單拆成以100單為一組的列表:
def split_list(lst, size):
"""
將列表 lst 拆分成每份 size 個元素的子列表,并返回一個包含所有子列表的列表。
"""
return [lst[i:i + size] for i in range(0, len(lst), size)]多線程第二步,隊列提數(shù),讓多個線程依次從列表中取出數(shù)據(jù),每個線程每次取不同的數(shù)據(jù):
import threading
# 待處理的數(shù)據(jù)列表
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 創(chuàng)建鎖對象
lock = threading.Lock()
# 定義線程函數(shù)
def process_data():
global data
while True:
# 加鎖
lock.acquire()
# 如果列表為空,說明所有數(shù)據(jù)已被處理完畢,退出循環(huán)
if len(data) == 0:
lock.release()
break
# 取出列表中的第一個數(shù)據(jù)
num = data.pop(0)
# 釋放鎖
lock.release()
# 對數(shù)據(jù)進行處理
print("Processing data:", num)
# 創(chuàng)建多個線程
threads = []
for i in range(5):
t = threading.Thread(target=process_data)
threads.append(t)
# 啟動所有線程
for t in threads:
t.start()
# 等待所有線程結(jié)束
for t in threads:
t.join()
print("All data processed.")阻塞隊列是通過加鎖來實現(xiàn)的,每個線程在取數(shù)前先加鎖,然后pop(0)取出列表中的第一個數(shù)據(jù),再釋放鎖。上述程序修改①data②數(shù)據(jù)處理邏輯③線程數(shù)即可使用。
對比工具使用多線程后,運行時間從小時級別降到了分鐘級別。當天研發(fā)本來以為要跑很久,準備第二天再來看,就先撤了。我執(zhí)著了一下多線程實現(xiàn),在ChatGPT幫助下,很快就把結(jié)果跑出來。趕緊打電話搖人,讓研發(fā)回來看問題,研發(fā)那時剛到家,掏出鑰匙把門打開。在全量對比前,我們也都做了一輪抽樣驗證,均沒有發(fā)現(xiàn)任何問題。18500單全量對比,發(fā)現(xiàn)有1064單存在問題,能抽樣發(fā)現(xiàn)的概率只有5.8%。
總結(jié),分析這些問題原因:
- 遺漏了1種數(shù)據(jù)情況,評估不到位
- 未考慮到刷數(shù)環(huán)境影響,在預(yù)發(fā)環(huán)境刷數(shù),上下游環(huán)境都是預(yù)發(fā),可能跟線上版本不一樣,尤其是做寫操作時,格外需要注意
- 刷數(shù)程序本身缺陷,這個缺陷隱藏在一段用了很多次刷數(shù)的歷史代碼里面,不是100%會導(dǎo)致問題
可以發(fā)現(xiàn),大數(shù)據(jù)量驗證,人工無法百分百保證數(shù)據(jù)準確性,抽樣檢查,94.2%概率發(fā)現(xiàn)不了問題。最穩(wěn)妥的辦法,還是全量對比,讓每條數(shù)據(jù),都經(jīng)過對比規(guī)則的檢驗。
分享文章:一次全量數(shù)據(jù)對比工具發(fā)現(xiàn)問題的過程與思考
網(wǎng)頁地址:http://m.fisionsoft.com.cn/article/coieecd.html


咨詢
建站咨詢
