之前寫過了- 通用池化架構commons-pool2實踐以及通用池化架構實踐之GenericKeyedObjectPool。接下來我就對這個池化架構進行性能測試。首先呢就是因為這個池化技術必需要有足夠的性能,不然通過池化技術優化的部分,在較高QPS的性能測試中,對象池可能成為本機瓶頸。
硬體軟體配置
硬體就是我自己的電腦,型号
MacBook Pro (16-inch, 2019)
,配置
6C16G
。因為這次測試并沒有測試到性能極限,在測試方案設計的前階段已經有了相對明顯的結論了。
軟體方面,還是Groovy,預設Java程序啟動參數。對象池化的設定後面可以在代碼中看到,經過我的測試,隻要對象池中還有空閑對象就足夠滿足目前性能。因為我本次用的是固定線程模型,是以換算過來就是對象數大于線程數即可。
測試前準備
測試分成了兩部分:無等待歸還對象、有等待歸還對象。因為無等待歸還對象測試過程中,結論出現的太早也太明顯了。
可池化對象
/**
* 可池化對象
*/
private static class FunTesterPooled {
String name
int age
}
池化工場
/**
* 池化工廠
*/
private static class FunFactory extends BasePooledObjectFactory<FunTesterPooled> {
@Override
FunTesterPooled create() throws Exception {
return new FunTesterPooled()
}
@Override
PooledObject<FunTesterPooled> wrap(FunTesterPooled obj) {
return new DefaultPooledObject<FunTesterPooled>(obj)
}
@Override
void destroyObject(PooledObject<FunTesterPooled> p, DestroyMode destroyMode) throws Exception {
p.getObject().setName("") //回收資源
super.destroyObject(p, destroyMode)
}
}
對象池
static def initPool() {
def config = new GenericObjectPoolConfig<FunTesterPooled>()
config.setMaxIdle(10)
config.setMinIdle(2)
config.setMaxTotal(thread * 2)
return new GenericObjectPool<FunTesterPooled>(new FunFactory(), config)
}
性能測試用例
static GenericObjectPool<FunTesterPooled> pool
static def desc = "池化架構性能測試"
static int times = 3000000
static int thread = 2
public static void main(String[] args) {
this.pool = initPool()
ThreadBase.COUNT = true
RUNUP_TIME = 0
def barrier = new CyclicBarrier(thread + 1)
POOL_SIZE = thread
def borrows = []
thread.times {
fun {
borrows << pool.borrowObject()
barrier.await()
}
}
barrier.await()
borrows.each {
pool.returnObject(it)
}
output("對象建立完畢 建立數量${pool.getNumIdle()}")
new Concurrent(new FunTester(), thread, desc).start()
pool.close()
}
private static class FunTester extends FixedThread {
FunTester() {
super(null, times, true)
}
@Override
protected void doing() throws Exception {
pool.returnObject(pool.borrowObject())
}
@Override
FunTester clone() {
return new FunTester()
}
}
其中往對象池中添加對象的時候,一開始我思路有點偏,是以想了一個
java.util.concurrent.CyclicBarrier
的方案。其實我們直接可以使用官方提供的
org.apache.commons.pool2.ObjectPool#addObjects
方法實作,代碼非常簡單,一行搞定
pool.addObjects(thread)
。
測試結果
無等待
線程數 | 執行次數(萬) | QPS |
---|---|---|
1 | 300 | 1876172 |
2 | 300 | 1852364 |
5 | 300 | 1533912 |
10 | 300 | 1524538 |
10 | 100 | 1571623 |
20 | 100 | 1568692 |
可以看出,QPS非常高,足夠滿足線性能測試需求。
等待
線程數 | 執行次數(k) | 單線程QPS |
---|---|---|
20 | 10 | 410 |
50 | 10 | 406 |
100 | 5 | 406 |
200 | 2 | 404 |
300 | 2 | 403 |
400 | 2 | 403 |
500 | 2 | 262 |
800 | 2 | 143 |
1000 | 2 | 114 |