我一直以來,對性能測試中,連接池的大小要如何配置,不是太清楚;
就我所知道的,就DB自帶對連接數的限制,在sqlserver中用select @@connection 可以查到,
在代碼中,可以配置DB的連接池,
在中間件中,可以配置最大的線程數等等。
在性能測試中,這些配置顯然很重要,要不然,木桶原理,哪一個低了,都是個性能瓶頸,在其他地方再怎么費力,也無能為力。
今天做了一個實驗,不考慮中間件,不去考慮代碼邏輯啊,接口調用什么的,只考慮數據庫連接池,和實際並發數的影響。
工具也很簡單,就用Jmeter中元件JDBC Connection Configuration配置DB連接數,再在JDBC請求中向表中新增一條記錄。新增不像查詢的,不會因為數據量的多少受影響。
因為線程數是受系統的用戶數決定的,所以要分析受眾數量,
可以通過以往的日志分析,一般系統中都會記錄用戶在何時,何種渠道,登錄了,退出了,修改了,等等,總之是這樣的交互表
通過分解,高峰時間段,以半小時,或每小時計算,每秒鍾的最大用戶數
也可以通過社會工程學,並叫上算法分析師,分析和計算出高峰期用戶數量
還有一些是活動Campaign, 一段時間內的大促活動,比如雙十一支付寶支付接口,比如商場活動促銷,搶拍,秒殺,等等,
看看每秒鍾的用戶數量,能否大概掌握和預估一定的值;
比如我們這邊,大促之前會通過短信或者微信的方式,通知我們的會員,在xxx鏈接領取優惠券,xxx時間可以積分兌換更多好禮,在xxx時候購買充值會員卡等等
分析有無裂變的方式,會引來更多會員,一般不太好控制,或者會故意將通知會員的速度調節慢些;
不可裂變,即用戶即使轉發鏈接給好友,好友不支持參與活動,這個時候,單位時間內能預估的會員就比較清楚。
分析活動短信或微信的轉化率,即有百分之多少的會員,能夠在收到通知后,立即點擊鏈接來參與活動。
通常會有一個比例,但也有可能因為活動力度問題,比例不太一致。
總之,為了系統能文件運營,要用預估的峰值去跑。
而數據庫的線程池: 可以根據預估的峰值,參考之后進行設置。
線程池的原理:
其實線程池的原理很簡單,類似於操作系統中的緩沖區的概念,它的流程如下:
先啟動若干數量的線程,並讓這些線程都處於睡眠狀態,當客戶端有一個新請求時,就會喚醒線程池中的某一個睡眠線程,讓它來處理客戶端的這個請求,
當處理完這個請求后,線程又處於睡眠狀態。
可能你也許會問:為什么要搞得這么麻煩,如果每當客戶端有新的請求時,我就創建一個新的線程不就完了?
這也許是個不錯的方法,因為它能使得你編寫代碼相對容易一些,但你卻忽略了一個重要的問題?
那就是性能!
就拿我所在的單位來說,我的單位是一個省級數據大集中的銀行網絡中心,高峰期每秒的客戶端請求並發數超過100,
如果為每個客戶端請求創建一個新線程的話,
那耗費的CPU時間和內存將是驚人的,
如果采用一個擁有200個線程的線程池,
那將會節約大量的系統資源,使得更多的CPU時間和內存用來處理實際的商業應用,
而不是頻繁的線程創建與銷毀。
先看以下圖:
圖中兩次壓測,並發數一樣,數據庫連接池不一樣,上一個是10,下面的一個是100,並發數都是100,連接池大的時候,吞吐量要大很多。
並且由於並發數大於連接池,導致上面的錯誤率很高,大多數的錯誤原因是:
Cannot get a connection, pool error Timeout waiting for idle object
實驗的結果
從第一次到第四次結果來看
當DB的最大連接數:當並發數<=最大鏈接數的時候,且啟動時間慢,相當於請求來了,就能處理。
此時相等時間內的總請求數相近,吞吐量彼此相近。
當DB的最大鏈接> 當前並發數,且啟動時間慢,
此時相等時間內的總請求數相近,吞吐量彼此相近。
一般來講,現在都是前后端分離的系統,面向的是全網的受眾,
我覺得啟動時間,設置為1,比較合適;
當然,我這邊沒有去監控MySQL所在機器的CPU和內存情況。
第九次和第十次的結果也可以看出,並發數如果大於了DB連接數,
相同時間內,第九次的處理的總的請求數明顯大於第十次,吞吐量自然也高;
第十次吞吐量比第九次低了很多,且錯誤率達到7%,錯誤原因是:
不需要總是不停的去進行上下文切換,
第6次的失敗原因:
Cannot create PoolableConnectionFactory (Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.)