1. 程式人生 > 實用技巧 >Java後臺服務慢優化雜談

Java後臺服務慢優化雜談

Java後臺服務慢優化雜談

前言

你是否遇到過這樣的場景,當我們點選頁面某個按鈕後,頁面一直loading,要等待好幾分鐘才出結果的畫面,有時直接502或504,作為一個後臺開發,看到自己開發的系統是這個樣子,就問你慚愧嗎。
這種問題其實是效能問題,當用戶量少資料少的時候,處理還是很快的,資料量一旦大起來,後臺處理時間就會延長,前端大部分直接超時或無限等待直接死掉。

方案

解決資料量大的效能問題,要根據實際業務場景來針對分析。但歸根結底,只有一條最終方案,即減少與資料庫互動次數,尤其是在for迴圈裡面。我們所有慢的場景,按這個方式優化,之前好幾分鐘,十幾分鐘的功能都優化到了3秒內。

For迴圈內查詢資料庫優化

我們很多場景如新增,修改,上傳,下載報表,都會有for迴圈內查詢資料庫的操作,而且一次迴圈有的與資料庫要互動好次操作,這樣下來如果迴圈是以使用者列表來處理的,一個租戶下1000個使用者,每個使用者要與資料庫互動幾次,再乘以1000,想想得多耗時。
這種場景的優化很簡單,直接將迴圈體內與資料庫的互動全部拿到迴圈外,通過業務邏輯,表結構關係是可以做到的,然後在迴圈體內只做記憶體計算,實驗證明,迴圈體內與資料庫互動的次數越少,耗時越小,可能有人會那你迴圈體內Java處理也慢啊,非也,Java純記憶體處理其實一點都不慢。

//宣告for迴圈處理結果集
List<?> list = new
ArrayList<>(); //迴圈前提前向資料庫查詢要用到的資料 List<?> userList = userMapper.selectList(xxx); for(User user: userList){ //處理單個使用者業務邏輯,避免多次查庫 list.add(xxx); }

For迴圈內修改資料庫優化

上面說的是迴圈體內查詢資料庫,這裡要說的場景就是迴圈體內插入或修改資料庫記錄,還是1000個使用者迴圈插入或修改關聯表,與資料庫的互動次數也龐大的,這裡的優化也很簡單,將要變更到資料庫物件全部封裝到集體中,迴圈處理完成後 ,再一次性或分批將集合資料插入資料庫,這也會大大提高修改操作的效能的。

//定義待插入資料庫的集合
List<User> list = new ArrayList();
for(User u : userList){
    //處理待插入資料庫的User物件
    list.add(u);
}
//批量(也可以設定分批次)插入資料庫
userMapper.batchInsert(list);

多執行緒併發處理

增加執行緒池這種優化方案就不用多說了吧

threadPoolTaskExecutor.submit(()->{
    try {
        //業務邏輯處理
    } catch (Exception e) {
        
    }
});

快取

在以上業務程式碼優化完畢,如果還要再提升效能,那就可以對多查詢的業務加快取處理,如Redis,Memcached。

非同步

快取也加了,併發效能還上不來,就可以使用非同步處理了,將請求放入訊息佇列MQ,然後多執行緒非同步消費佇列處理請求。

伺服器叢集

在生產環境一般都不會是單節點部署,要保障系統穩定性肯定是要多節點部署,這也能在優化程式碼程式碼的基礎上提高併發效能,尤其是當使用中介軟體如快取,MQ,更是要使用多節點叢集,才能發揮中介軟體的作用,如上篇Redis+Kafka非同步提高併發,可以將介面併發能力提升到3000-5000QPS。

作者介紹:小林,狐小E資深開發工程師,專注移動協同辦公平臺的SAAS軟體開發以及輕應用開發
最近開發了一款移動辦公軟體狐小E