自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Jmh基準測試,看我怎么用它來測試Mongodb的數(shù)據(jù)加載性能

開發(fā) 前端 MongoDB
最近我們這邊引入了mongodb,不過沒有實際上測試過性能如何,只是聽說讀寫比mysql快,你今天沒有什么排期,測試一下,然后今天內(nèi)給我個答案吧!

 [[410165]]

本文轉載自微信公眾號「稀飯下雪」,作者帥氣的小飯飯 。轉載本文請聯(lián)系稀飯下雪公眾號。

「主管小肥肥:」 最近我們這邊引入了mongodb,不過沒有實際上測試過性能如何,只是聽說讀寫比mysql快,你今天沒有什么排期,測試一下,然后今天內(nèi)給我個答案吧

「小飯飯:」 好的,接下來就是測試性能的一天了。

到了這里,可能大部分人的第一想法應該是直接用這種方式:

  1. public void test() { 
  2.     long start = System.currentTimeMillis(); 
  3.     // 執(zhí)行邏輯 
  4.     long end = System.currentTimeMillis();   
  5.     System.out.println(end - start); 

no,我這次使用的是JMH

無論出自何種原因需要進行性能評估,量化指標總是必要的,那么如何量化呢?

這就需要我們的主角 JMH 登場了!

先給你們看個效果圖

性能對比圖

什么是JMH

JMH(Java Microbenchmark Harness)是用于代碼微基準測試的工具套件,主要是基于方法層面的基準測試,精度可以達到納秒級。

該工具是由 Oracle 內(nèi)部實現(xiàn) JIT 的大牛們編寫的,他們應該比任何人都了解 JIT 以及 JVM 對于基準測試的影響。

當你定位到熱點方法,希望進一步優(yōu)化方法性能的時候,就可以使用 JMH 對優(yōu)化的結果進行量化的分析。

JMH 比較典型的應用場景如下:

  • 想準確地知道某個方法需要執(zhí)行多長時間,以及執(zhí)行時間和輸入之間的相關性
  • 對比接口不同實現(xiàn)在給定條件下的吞吐量
  • 查看多少百分比的請求在多長時間內(nèi)完成

下面我們以mongodb、hibernate、jdbc數(shù)據(jù)加載性能對比為例,使用 JMH 做基準測試。

怎么做JMH基準測試?

  • 加入依賴

因為 JMH 是 JDK9 自帶的,如果是 JDK9 之前的版本需要加入如下依賴:

  1. <dependency> 
  2.     <groupId>org.openjdk.jmh</groupId> 
  3.     <artifactId>jmh-core</artifactId> 
  4.     <version>1.29</version> 
  5. </dependency> 
  6. <dependency> 
  7.     <groupId>org.openjdk.jmh</groupId> 
  8.     <artifactId>jmh-generator-annprocess</artifactId> 
  9.     <version>1.29</version> 
  10. </dependency> 
  • 編寫基準測試

接下來,創(chuàng)建一個 JMH 測試類,具體代碼如下所示:

  1. @BenchmarkMode({Mode.AverageTime}) 
  2. @Warmup(iterations = 1, time = 5) 
  3. @Measurement(iterations = 3, time = 5) 
  4. @Threads(1) 
  5. @Fork(1) 
  6. @OutputTimeUnit(TimeUnit.MILLISECONDS) 
  7. @State(Scope.Benchmark) 
  8. public class ReadBenchMarks { 
  9.     @Benchmark 
  10.     public void loadMongoTemplate(){ 
  11.         // mongoTemplate數(shù)據(jù)加載 
  12.     } 
  13.  
  14.     @Benchmark 
  15.     public void loadMongoDriver(){ 
  16.         // mongoDriver數(shù)據(jù)加載 
  17.     } 
  18.  
  19.     @Benchmark 
  20.     public void loadHibernate(){ 
  21.         // hibernate數(shù)據(jù)加載 
  22.     } 
  23.  
  24.     @Benchmark 
  25.     public void loadJdbc(){ 
  26.         // jdbc數(shù)據(jù)加載 
  27.     } 
  28.  
  29.     public static void main(String[] args) throws RunnerException { 
  30.         Options options = new OptionsBuilder() 
  31.                 .include(ReadBenchMarks.class.getSimpleName()) 
  32.                 .output("db.log"
  33.                 .build(); 
  34.         new Runner(options).run(); 
  35.     } 

「核心關注點:」

類上加了注解

  • 需要測試的方法用 @Benchmark 注解標識
  • 啟動的方式

這些注解的具體含義將在下面介紹。

大家有興趣可以看下官方提供的 jmh 示例 demo:http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

  • 執(zhí)行基準測試

準備工作做好了,接下來,運行代碼,等待片刻,測試結果就出來了

  1. # JMH version: 1.29 
  2. # VM version: JDK 1.8.0_251, Java HotSpot(TM) Client VM, 25.251-b08 
  3. # VM invoker: C:\soft\Java\jdk1.8.0_251\jre\bin\java.exe 
  4. # VM options: -javaagent:C:\soft\idea\IntelliJ IDEA Community Edition 2020.1.1\lib\idea_rt.jar=53895:C:\soft\idea\IntelliJ IDEA Community Edition 2020.1.1\bin -Dfile.encoding=UTF-8 
  5. # Blackhole mode: full + dont-inline hint 
  6. # Warmup: 2 iterations, 5 s each 
  7. # Measurement: 10 iterations, 5 s each 
  8. # Timeout: 10 min per iteration 
  9. # Threads: 1 thread, will synchronize iterations 
  10. # Benchmark mode: Average timetime/op 
  11. # Benchmark: com.db.jmh.write.WriteBenchMarks.writeHibernate 
  12. # Parameters: (info = 10031,1,5) 
  13.  
  14. # Run progress: 0.00% complete, ETA 00:06:00 
  15. # Fork: 1 of 1 
  16. # Warmup Iteration   1: 7.743 ms/op 
  17. # Warmup Iteration   2: 9.433 ms/op 
  18. Iteration   1: 7.854 ms/op 
  19. Iteration   2: 8.638 ms/op 
  20. Iteration   3: 8.579 ms/op 
  21. Iteration   4: 8.213 ms/op 
  22. Iteration   5: 8.843 ms/op 
  23. Iteration   6: 9.178 ms/op 
  24. Iteration   7: 7.739 ms/op 
  25. Iteration   8: 9.608 ms/op 
  26. Iteration   9: 10.152 ms/op 
  27. Iteration  10: 9.461 ms/op 
  28.  
  29. Result "com.db.jmh.write.WriteBenchMarks.writeHibernate"
  30.   8.827 ±(99.9%) 1.182 ms/op [Average] 
  31.   (minavgmax) = (7.739, 8.827, 10.152), stdev = 0.782 
  32.   CI (99.9%): [7.645, 10.008] (assumes normal distribution) 
  33.  
  34. # Run complete. Total time: 00:06:38 
  35.  
  36. REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on 
  37. why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial 
  38. experiments, perform baseline and negative tests that provide experimental control, make sure 
  39. the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts. 
  40. Do not assume the numbers tell you what you want them to tell. 
  41.  
  42. Benchmark                           (info)  Mode  Cnt   Score   Error  Units 
  43. WriteBenchMarks.writeHibernate   10031,1,5  avgt   10   8.827 ± 1.182  ms/op 
  44. WriteBenchMarks.writeHibernate   10032,5,6  avgt   10   8.783 ± 1.478  ms/op 
  45. WriteBenchMarks.writeHibernate  10033,5,20  avgt   10  12.574 ± 0.928  ms/op 
  46. WriteBenchMarks.writeMongo       10031,1,5  avgt   10   5.057 ± 0.358  ms/op 
  47. WriteBenchMarks.writeMongo       10032,5,6  avgt   10   7.392 ± 0.651  ms/op 
  48. WriteBenchMarks.writeMongo      10033,5,20  avgt   10  12.590 ± 0.795  ms/op 

下面對結果做下簡單說明:

  1. # JMH version: 1.29 
  2. # VM version: JDK 1.8.0_251, Java HotSpot(TM) Client VM, 25.251-b08 
  3. # VM invoker: C:\soft\Java\jdk1.8.0_251\jre\bin\java.exe 
  4. # VM options: -javaagent:C:\soft\idea\IntelliJ IDEA Community Edition 2020.1.1\lib\idea_rt.jar=53895:C:\soft\idea\IntelliJ IDEA Community Edition 2020.1.1\bin -Dfile.encoding=UTF-8 
  5. # Blackhole mode: full + dont-inline hint 
  6. # Warmup: 2 iterations, 5 s each 
  7. # Measurement: 10 iterations, 5 s each 
  8. # Timeout: 10 min per iteration 
  9. # Threads: 1 thread, will synchronize iterations 
  10. # Benchmark mode: Average timetime/op 
  11. # Benchmark: com.db.jmh.write.WriteBenchMarks.writeHibernate 
  12. # Parameters: (info = 10031,1,5) 

該部分為「測試的基本信息」,比如使用的 Java 路徑,預熱代碼的迭代次數(shù),測量代碼的迭代次數(shù),使用的線程數(shù)量,測試的統(tǒng)計單位等。

  1. # Warmup Iteration   1: 7.743 ms/op 
  2. # Warmup Iteration   2: 9.433 ms/op 

該部分為每一次熱身中的性能指標,預熱測試不會作為最終的統(tǒng)計結果。預熱的目的是「讓 JVM 對被測代碼進行足夠多的優(yōu)化」,比如,在預熱后,被測代碼應該得到了充分的 JIT 編譯和優(yōu)化。

  1. Iteration   1: 7.854 ms/op 
  2. Iteration   2: 8.638 ms/op 
  3. Iteration   3: 8.579 ms/op 
  4. Iteration   4: 8.213 ms/op 
  5. Iteration   5: 8.843 ms/op 
  6. Iteration   6: 9.178 ms/op 
  7. Iteration   7: 7.739 ms/op 
  8. Iteration   8: 9.608 ms/op 
  9. Iteration   9: 10.152 ms/op 
  10. Iteration  10: 9.461 ms/op 
  11.  
  12.  
  13. Result "com.db.jmh.write.WriteBenchMarks.writeHibernate"
  14.   8.827 ±(99.9%) 1.182 ms/op [Average] 
  15.   (minavgmax) = (7.739, 8.827, 10.152), stdev = 0.782 
  16.   CI (99.9%): [7.645, 10.008] (assumes normal distribution) 

該部分顯示測量迭代的情況,每一次迭代都顯示了當前的執(zhí)行速率,即一個操作所花費的時,在進行 10 次迭代后,進行統(tǒng)計。

最后的測試結果如下所示:

  1. Benchmark                           (info)  Mode  Cnt   Score   Error  Units 
  2. WriteBenchMarks.writeHibernate   10031,1,5  avgt   10   8.827 ± 1.182  ms/op 
  3. WriteBenchMarks.writeHibernate   10032,5,6  avgt   10   8.783 ± 1.478  ms/op 
  4. WriteBenchMarks.writeHibernate  10033,5,20  avgt   10  12.574 ± 0.928  ms/op 
  5. WriteBenchMarks.writeMongo       10031,1,5  avgt   10   5.057 ± 0.358  ms/op 
  6. WriteBenchMarks.writeMongo       10032,5,6  avgt   10   7.392 ± 0.651  ms/op 
  7. WriteBenchMarks.writeMongo      10033,5,20  avgt   10  12.590 ± 0.795  ms/op 

看這些數(shù)據(jù)也能看出個大概,不過我不大可能直接將這個數(shù)據(jù)扔給老大, 因此用了以下兩個網(wǎng)站

  • JMH Visual Chart:http://deepoove.com/jmh-visual-chart/
  • JMH Visualizer:https://jmh.morethan.io/

生成了一開始看到的那張圖形化界面。

補充下,JMH 基礎

為了能夠更好地使用 JMH 的各項功能,下面對 JMH 的基本概念進行講解:

  • @BenchmarkMode

用來配置 Mode 選項,可用于類或者方法上,這個注解的 value 是一個數(shù)組,可以把幾種 Mode 集合在一起執(zhí)行,如:@BenchmarkMode({Mode.SampleTime, Mode.AverageTime}),還可以設置為 Mode.All,即全部執(zhí)行一遍。

  1. Throughput:整體吞吐量,每秒執(zhí)行了多少次調(diào)用,單位為 ops/time
  2. AverageTime:用的平均時間,每次操作的平均時間,單位為 time/op
  3. SampleTime:隨機取樣,最后輸出取樣結果的分布
  4. SingleShotTime:只運行一次,往往同時把 Warmup 次數(shù)設為 0,用于測試冷啟動時的性能
  5. All:上面的所有模式都執(zhí)行一次
  • @State

通過 State 可以指定一個對象的作用范圍,JMH 根據(jù) scope 來進行實例化和共享操作。@State 可以被繼承使用,如果父類定義了該注解,子類則無需定義。由于 JMH 允許多線程同時執(zhí)行測試,不同的選項含義如下:

  1. Scope.Benchmark:所有測試線程共享一個實例,測試有狀態(tài)實例在多線程共享下的性能
  2. Scope.Group:同一個線程在同一個 group 里共享實例
  3. Scope.Thread:默認的 State,每個測試線程分配一個實例

@OutputTimeUnit

為統(tǒng)計結果的時間單位,可用于類或者方法注解

  • @Warmup

預熱所需要配置的一些基本測試參數(shù),可用于類或者方法上。一般前幾次進行程序測試的時候都會比較慢,所以要讓程序進行幾輪預熱,保證測試的準確性。參數(shù)如下所示:

  1. iterations:預熱的次數(shù)
  2. time:每次預熱的時間
  3. timeUnit:時間的單位,默認秒
  4. batchSize:批處理大小,每次操作調(diào)用幾次方法
  • @Measurement

實際調(diào)用方法所需要配置的一些基本測試參數(shù),可用于類或者方法上,參數(shù)和 @Warmup 相同。

  • @Threads

每個進程中的測試線程,可用于類或者方法上。

  • @Fork

進行 fork 的次數(shù),可用于類或者方法上。如果 fork 數(shù)是 2 的話,則 JMH 會 fork 出兩個進程來進行測試。

  • @Param

指定某項參數(shù)的多種情況,特別適合用來測試一個函數(shù)在不同的參數(shù)輸入的情況下的性能,只能作用在字段上,使用該注解必須定義 @State 注解。

在介紹完常用的注解后,讓我們來看下 JMH 有哪些陷阱。

回答個疑問,為什么需要預熱?

因為 JVM 的 JIT 機制的存在,如果某個函數(shù)被調(diào)用多次之后,JVM 會嘗試將其編譯為機器碼,從而提高執(zhí)行速度,所以為了讓 benchmark 的結果更加接近真實情況就需要進行預熱。

如何將測試結果 可視化

其實很簡單,將main函數(shù)改成

  1. public static void main(String[] args) throws RunnerException { 
  2.     Options opt = new OptionsBuilder() 
  3.             .include(WriteBenchMarks.class.getSimpleName()) 
  4.             .result("db_read.json"
  5.             .resultFormat(ResultFormatType.JSON).build(); 
  6.     new Runner(opt).run(); 

就可以了,再將生成的json格式文件扔進以下網(wǎng)站:

  • JMH Visual Chart:http://deepoove.com/jmh-visual-chart/
  • JMH Visualizer:https://jmh.morethan.io/

就可以了啦。

「小飯飯:」 我測完啦,還生成了柱形圖給你看看

「主管小肥肥:」 不錯,mongodb的性能確實ok,你做的也不錯,還以為你會用System.currentTimeMillis()這種low的手段呢,沒想到用上了JMH,做的不錯,快調(diào)薪了,必須給你加一筆。

原文鏈接:https://mp.weixin.qq.com/s/hTRa-eOSvSns0sm2P2BMVg

 

責任編輯:武曉燕 來源: 稀飯下雪
相關推薦

2023-10-20 11:24:25

JMH基準測試

2021-12-29 10:30:15

JMH代碼Java

2016-09-23 16:36:25

LinuxPCPhoronix

2024-03-06 18:09:06

Linux性能工具

2023-07-31 09:13:13

ValidatorGolang

2009-10-10 11:11:40

服務器測試

2021-07-17 15:25:05

PHP 8.1基準測試開發(fā)

2013-05-07 09:47:30

測試MySQLMySQL測試

2012-07-31 09:02:49

Apworks

2023-01-06 08:31:53

數(shù)據(jù)庫基準測試

2011-09-27 10:11:14

MongoDBR

2011-03-03 10:32:07

Mongodb億級數(shù)據(jù)量

2022-03-29 11:48:40

Go泛型測試

2023-05-12 13:21:12

JMHJava程序

2023-10-08 16:28:36

數(shù)據(jù)庫DuckDB

2015-05-19 16:52:13

企業(yè)網(wǎng)D1Net

2010-05-13 15:43:34

MySQL宣布

2020-06-10 10:40:03

JavaJMH字符串

2011-07-28 09:08:14

MongoDB性能測試

2022-07-06 09:29:40

JMH性能測試
點贊
收藏

51CTO技術棧公眾號