1. 程式人生 > >提交訂單效能優化系列之004-測試hikari資料來源

提交訂單效能優化系列之004-測試hikari資料來源

概括總結

使用hikari資料來源之後,相對於第003版的druid資料來源,從提交訂單這個複雜的操作上來說,效能提升了17.79%。而從獲取資料庫連線這一簡單的操作上來說,hikari比druid優秀幾百倍

004版本更新說明

pom.xml檔案中引入了新的jar包:

<!-- HikariCP資料庫連線工具 -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version
>
3.2.0</version> </dependency>

HikariCP-3.2.0.jar包的大小是141KB,而003版本中的druid-1.1.10.jar包的大小是2693KB,甚至都不是一個數量級的。

這一版本寫了兩個測試類:Version004TestVersion004Test2。其中Version004Test用於測試提交訂單的耗時情況,Version004Test2用於測試獲取資料庫連線的耗時情況。另外,由於hikari的效能好得超乎想像,毫秒這個單位已經太粗糙了,於是把Version004Test2中的時間單位改成了納秒

測試結果

Version004Test

的測試結果:

002版本(自己寫的資料來源)耗時(ms) 003版本(druid資料來源)耗時(ms) 004版本(hikari資料庫源)耗時(ms)
1047 1259 1035

003版本相對於002版本效能下降了: (1259 - 1047) / 1047 * 100% = 20.24%

004版本相對於003版本效能提升了: (1259 - 1035) / 1259 * 100% = 17.79%

004版本相對於002版本效能提升了: (1047 - 1035) / 1047 * 100% = 1.14%

Version004Test2的測試結果: 日誌列印如下:

druid 獲取一個數據庫連線平均耗時:2392283 納秒(獲取連線後不關閉連線) hikari 獲取一個數據庫連線平均耗時:3268791 納秒(獲取連線後不關閉連線) druid 獲取一個數據庫連線平均耗時:1812491 納秒(獲取連線後不關閉連線) hikari 獲取一個數據庫連線平均耗時:61716 納秒(獲取連線後不關閉連線) druid 獲取一個數據庫連線平均耗時:1800770 納秒(獲取連線後關閉連線) hikari 獲取一個數據庫連線平均耗時:2175 納秒(獲取連線後關閉連線) druid 獲取一個數據庫連線平均耗時:1834128 納秒(獲取連線後關閉連線) hikari 獲取一個數據庫連線平均耗時:2614 納秒(獲取連線後關閉連線)

可以總結為:如果獲取連線後,不關閉連線,則druid和hikari在效能上是一個級別的。但是由於實際專案中,獲取連線後都會關閉連線,這時候hikari的效能比druid優秀幾百倍:1800770 / 2175 = 827.94 倍。

【備註】:不同的機器上的測試結果會不一樣,以上測試結果僅供參考。

hikari為什麼這麼優秀?

HikariCP自己宣傳的賣點是”zero-overhead“,翻譯成中文也就是”零開銷“。但是要注意它是打了引號的,意思可以理解為:雖然不是真的零開銷,但是跟其他的資料來源工具比起來,可以認為是零開銷了。這樣的宣傳我是可以接受的。

這可不像是druid那樣明目張膽地吹牛皮說自己是Java語言中最好的資料庫連線池,連引號都不打。這樣的宣傳我也是可以接受的,畢竟druid在github上的星星數量確實是比其他的資料來源高很多。

話說回來,hikari為什麼這麼優秀呢?

這個回答我在測試之前點進去過,一看是英文版的,馬上關閉了。後來看到了Version004Test2的測試結果,又打開了那個頁面,靠著有道詞典一字一句地把文章看完了。總結起來有以下兩點:

  1. ArrayList的優化:當從ArrayList中移除某個物件時,會從頭到尾執行掃描,但是我們知道,資料庫相關的物件有很多都是需要關閉的,關閉的順序一般是與開啟的順序相反的,即最需要關閉的物件是儲存在列表的尾部的,這意味著,如果能從尾到頭來掃描的話,效能就會有提升。於是ArrayList就被自定義的FastList取代了

  2. 位元組碼層面的優化:對比一下以下兩行程式碼的區別:

    程式碼段1:(其中PROXY_FACTORY是類ProxyFactory的一個靜態例項物件)

    PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames)); 程式碼段2:(其中ProxyFactory是一個類) ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames)); 你能看出誰比誰的效能更高嗎?反正我是看不出來。不過,雖然從java程式碼的層面看不出來,但是一旦編譯成了位元組碼,區別就很明顯了(第二種效能更好)。我在這裡就不列舉了,你可以去這裡看看。

當然了,這兩點只是樣本例子,並不代表這個工具包中只做了這兩點優化。特別是其中的第2點,能涵蓋的範圍非常廣泛,真是讓人佩服。

原始碼