百萬級數據導入(hyperf+xlswriter+task+websocket)

需要實現的功能:
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 分塊的,我的表裏沒那麼數據,就沒分塊

來看看 9145 條數據 cpu 的調度率

 

可以看到,因爲均分到四個不同 task worker 緣故,cpu 調用不會只在一個進程上而是在多個進程均衡調度!!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章