記錄一次系統效能調優過程

2021-09-26 15:42:28 字數 4451 閱讀 9197

問題回顧

問題清單

模組合併過程中各種衝突,各種bean無法正常載入

事件處理效能原來每秒3000~1w左右,現在突然驟降至幾百左右;

事件存在丟失現象,而且丟失比較嚴重

發現系統cache一直在不斷的**,free -m 後發現可餘記憶體幾乎用沒了(剩餘100m左右,其實就差不多是用完了,不會再降低)

1. **衝突

2. 事件處理效能慢

現有的處理流程如下:

專案採用springboot構建,引入 spring-boot-stater-redis

通過http接收到非同步事件,儲存到redis;

儲存的同時,將事件通過redis的發布訂閱傳送到不同的處理單元進行處理;

每個事件處理單元通過redis訂閱,然後處理事件;

起乙個定時器,每秒鐘從redis中查詢乙個時間視窗的事件,構建索引,然後bulkindex到es

2.1 問題發現

redis的訂閱發布,內部會維護乙個container執行緒,此執行緒會一直存在;

每次訂閱,都會產生乙個新的字首為redislisteningcontainer-的執行緒處理;

通過jvisualvm.exe 檢視執行緒數,該類執行緒數一直在飆公升

2.2 問題定位

2.2.1 redis訂閱發布問題

程式中的實現如下:

@bean

redismessagelistenercontainer managecontainer(

redisconnectionfactory factory, messagelistener listener)

**中被注釋掉的那一行,實際**中是沒有該行的,也就是沒有設定taskexecutorredismessagelistenercontainer.class

...

protected taskexecutor createdefaulttaskexecutor()

...

******asynctaskexecutor.class

...

protected void doexecute(runnable task)

...

2.2.2 事件處理都是耗時操作,造成執行緒數越來越多,甚至oom

2.3 問題解決

找到問題的產生原因,主要的解決思路有三種:

建立了2個執行緒組(參考netty的底層實現):

乙個用於處理事件接收 「event-recv-executor-」

coresize = n * 2,cpu密集型

乙個用於事件的非同步處理 「event-task-executor-」

coresize = n / 0.1,io密集型

事件處理邏輯

@override

eventtaskexecutor.execute(() -> );

}

現有的處理流程如下:

專案採用springboot構建,引入 spring-boot-stater-redis

後台維護了乙個定時器,每秒鐘從redis中查詢乙個時間視窗的事件

3.1 問題發現
在後台定位日誌輸出,正常情況下,應該是每秒鐘執行一次定時,

但實際是,系統並不保證一定能每隔1s執行一次,

由於系統中線程比較多,cpu的切換頻繁,

導致定時有可能1s執行幾次或者每隔幾秒執行一次

3.2 問題定位

3.2.1 定時任務不可靠

由於定時並無法保證執行,而定時任務獲取事件時,是按照時間視窗擷取,

通過redistemplate.opsforzset().rangebyscore(key, minscore, maxscore)實現,

勢必會造成有資料無法被載入到程式中,而一直儲存在redis中,無法獲取,也無法刪除

3.3 問題解決

找到問題的產生原因,主要的解決思路有兩種:

本次問題中採用的是第三種形式。起乙個單獨的執行緒,阻塞監聽。

事件接收後,直接塞到乙個blockingqueue中;

當blockingqueue有資料時,while迴圈不阻塞,逐條讀取佇列中的資訊;

每隔1000條資料,或者每隔1s,將資料寫入es,並分發其他處理流程

在4g的機器下,發現經過一段時間的發包處理後,系統cache增長的非常快,最後幾近於全部佔滿:

大概每秒鐘10m的漲幅

4.1 問題發現

因為對於es的了解,插入資料時,先寫快取,後fsync到磁碟上,因此懷疑es可能存在問題;

專案中日誌使用log4j2不當:

4.2 問題定位

4.2.1 es插入機制問題

經過隔段分析,將有可能出現問題的地方,分別遮蔽後,進行測試。 最終定位到,在es批量寫入資料時,才會出現cache大量增長的現象

4.3 問題解決

用命令檢視記憶體free -m

es運算元據的底層機制:

資料寫入時,es記憶體緩慢上公升,是因為小檔案過多(es本身會在index時候建立大量的小檔案),linux dentry 和 inode cache會增加。

本問題其實並沒有完全解決,只是在一定程度上用效能換取快取。

修改系統引數,提高slab記憶體釋放的優先順序:

echo 10000 > /proc/sys/vm/vfs_cache_pressure;
修改es配置引數

## 這些引數是之前優化的

threadpool.bulk.type: fixed

threadpool.bulk.min: 10

threadpool.bulk.max: 10

threadpool.bulk.queue_size: 2000

threadpool.index.type: fixed

threadpool.index.size: 100

threadpool.index.queue_size: 1000

index.max_result_window: 1000000

index.query.bool.max_clause_count: 1024000

# 以下的引數為本次優化中新增的:

# 設定es最大快取資料條數和快取失效時間

index.cache.field.max_size: 20000

index.cache.field.expire: 1m

# 當記憶體不足時,對查詢結果資料快取進行**

index.cache.field.type: soft

# 當記憶體達到一定比例時,觸發gc。預設為jvm的70%[記憶體使用最大值]

#indices.breaker.total.limit: 70%

# 用於fielddata快取的記憶體數量,

# 主要用於當使用排序操作時,es會將一些熱點資料載入到記憶體中來提供客戶端訪問

indices.fielddata.cache.expire: 20m

indices.fielddata.cache.size: 10%

# 乙個節點索引緩衝區的大小[max 預設無限制]

#indices.memory.index_buffer_size: 10%

#indices.memory.min_index_buffer_size: 48m

#indices.memory.max_index_buffer_size: 100m

# 執行資料過濾時的資料快取,預設為10%

#indices.cache.filter.size: 10%

#indices.cache.filter.expire: 20m

# 當tranlog的大小達到此值時,會進行一次flush操作,預設是512m

index.translog.flush_threshold_size: 100m

# 在指定時間間隔內如果沒有進行進行flush操作,會進行一次強制的flush操作,預設是30分鐘

index.translog.flush_threshold_period: 1m

# 多長時間進行一次的磁碟操作,預設是5s

index.gateway.local.sync: 1s

願大家共同進步,共同成長。

系統效能調優

系統效能調優 效能測試分析人員經過對結果的分析以後,有可能提出系統存在效能瓶頸。這時相關開發人員 資料庫管理員 系統管理員 網路管理員等就需要根據效能測試分析人員提出的意見同效能分析人員共同分析確定更細節的內容,相關人員對系統進行調整以後,效能測試人員繼續進行第二輪 第三輪 的測試,與以前的測試結果...

系統效能調優

系統效能調優 效能測試分析人員經過對結果的分析以後,有可能提出系統存在效能瓶頸。這時相關開發人員 資料庫管理員 系統管理員 網路管理員等就需要根據效能測試分析人員提出的意見同效能分析人員共同分析確定更細節的內容,相關人員對系統進行調整以後,效能測試人員繼續進行第二輪 第三輪 的測試,與以前的測試結果...

記錄一次查詢調優過程

調優過程中使用explain命令檢視執行過程,包括執行時間 掃瞄方式 是否用到索引等,explain 使用 timing on timing off 乙個查詢介面被頻繁呼叫,且查詢過程較慢 首先考慮優化sql語句 其次考慮優化業務 最後考慮是否需要新增快取機制 3.1 優化sql 原始sql,分組查...