需要實現的功能:
1、匯入excel檔案,10w條資料或者更多
2、進行入庫操作
可能涉及多張表
需要進行多表資料校驗(updateOrCreate)
需要保證多張表資料一致(transaction)
3、前端實時顯示入庫進度
實現思路:
將資料進行分塊然後分配到不同程式進行數資料庫匯入操作,每個task worker完成後會觸發onfinsh方法,監聽該事件透過websocket進行進度通知
可能遇到的問題:
檔案太大了,一下撈到記憶體,記憶體會爆炸
資料分塊投遞程式和程式消費的問題
程式消費完通知的問題
資料庫寫入阻塞導致匯入非常慢
解決方案
1、xlsx的讀取分幾種模式,全量讀取和遊標讀取,選擇遊標讀取耗費的記憶體是非常小的,然後可以根據讀取數量進行一次處理
while ($res = $this->xlsObj->nextRow($_dataType)) {
$data[] = $res;
$count++;
if ($count % 10000 == 0) {
//回撥資料插入的方法
$closure($data);
unset($data);
}
}
2、關於進行投遞和消費問題,如果在傳統fpm專案中,一般會選擇訊息中介軟體,先把訊息推送到中介軟體,然後再多程式消費,但是一般投遞訊息是越小越好,都需要經過序列化處理、然後程式消費在進行反序列化,swoole為我們提供了一套更簡單的方案,來看官方說明:
swoole預設程式間通訊都是基於unix socket的,他的效能如下:
這樣一來和中介軟體的連結耗時和傳輸耗時全部可以省掉,投遞和消費都是基於記憶體的無io操作
3、程式消費的時候需要入庫,雖然swoole的mysql io 已經全部協程化、因為我這裡是多表檢驗難免需要查詢校驗後再進行入庫,所以這裡開了協程併發入庫,使用 hyperf utils 裡面的 parallel 設定併發數為 10,這樣也快很多
4、程式消費完通知的問題我們可以透過監聽OnFinish事件,程式匯入結束後返回已完成條數和總條數,就可得知進度,讓webscoket server 主動向 client 推送進度
實現效果
這裡沒分塊是因為我預設是按100分塊的,我的表裡沒那麼資料,就沒分塊
技術棧
- hyperf (swoole框架)
- xlsxwriter (基於c的excel匯入匯出擴充套件)
- 多程式投遞和消費 (基於swoole task的api呼叫)
- websocket 實時通訊
- 訊息佇列模式使用作業系統提供的記憶體佇列儲存資料,未指定
mssage_queue_key
訊息佇列Key
,將使用私有佇列,在Server
程式終止後會刪除訊息佇列。 - 指定訊息佇列
Key
後Server
程式終止後,訊息佇列中的資料不會刪除,因此程式重啟後仍然能取到資料
本作品採用《CC 協議》,轉載必須註明作者和本文連結