天天看點

AntDB 性能測試篇(一):Jmeter工具

AntDB現已開源:

開源url:https://github.com/ADBSQL/AntDB
QQ交流群:
           

背景: AntDB 是一款源自于 PG 核心的通用分布式事務性關系資料庫。目前需要驗證資料庫的讀寫能力。第一個想到的是pgbench,postgresql提供的一個壓測工具,不過内部使用的是libpq通訊協定,與生産使用的jdbc擴充協定有點差别;第二個想到的LR,想想LR部署安裝的繁雜,關鍵是不免費,用破解版涉及商用可能被起訴的風險;第三個想到的是JMeter,小巧的純java寫的可以用來測試資料庫的工具。

JMeter與pgbench相比:

AntDB是基于postgresql核心開發的,熟悉postgresql的都比較了解pgbench工具。pgbench是一種在PostgreSQL上運作基準測試的簡單程式,用C語言開發的,内部走的是libpq,效率非常高。但是考慮到現場使用的是JAVA開發,調用jdbc走的擴充協定,是以本次不采用pgbench工具。

JMeter與LoadRunner相比:

JMeter 是一款開源的測試工具,雖然與LoadRunner相比,沒有LR功能那麼強大,結果分析也沒有LR那麼詳細。但JMeter有其本身的優勢:

1、開源,是一款開源的免費軟體,免費!免費!免費!重要的事情說三遍…

2、小巧,相比LR幾個G大小,它非常小巧,不需要安裝,但需要JDK環境,因為它是使用java開發的工具;

3、可以運作在Windows以及linux環境中;

4、功能相對比較全面,jmeter設計之初隻是一個簡單的web性能測試工具,但經過不段的更新擴充,現在可以完成資料庫、FTP、LDAP、WebService等方面的測試。因為它的開源性,當然你也可以根據自己的需求擴充它的功能。

言歸正傳,下面開始使用JMeter來測試AntDB:

安裝JMeter:

1、http://jmeter.apache.org/下載下傳最新版本的JMeter,上傳linux伺服器上,本次下載下傳的是apache-jmeter-2.13版本;

2、解壓JMeter:

tar -zxvf apache-jmeter-.tgz 
           

3、檢查目前使用者的JAVA版本,需要注意的是最新的apache-jmeter-3.3版本要求java 1.8并且不支援java1.9,下載下傳的時候注意看官網版本要求

[zhugy@localhost4 bin]$ java -version
java version "1.7.0_111"
OpenJDK Runtime Environment (rhel-.7.2.el6_8-x86_64 u111-b01)
OpenJDK -Bit Server VM (build -b01, mixed mode)
           

4、将JMeter的可執行目錄添加到環境變量中去:apache-jmeter-2.13/bin

配置測試AntDB驅動和配置檔案:

1、上傳AntDB的jdbc驅動(基于postgresql的jdbc驅動作了一些調整)到JMeter的lib目錄下:

[zhugy@localhost4 lib]$ pwd
/home/zhugy/jmeter/apache-jmeter-/lib
[zhugy@localhost4 lib]$  ll| grep postgresql
-rw-r--r--  zhugy zhugy   Sep   : postgresql-..jre7-SNAPSHOT.jar
           

2、以insert為例,完整的jmeter的jmx配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="測試計劃" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Argume
nts" testname="使用者定義的變量" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="測試adb單查詢性能" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="L
oopController" testname="循環控制器" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">10000</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">0</stringProp>
        <longProp name="ThreadGroup.start_time">1475998829000</longProp>
        <longProp name="ThreadGroup.end_time">1475998829000</longProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration">180</stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>
      <hashTree>
        <JDBCSampler guiclass="TestBeanGUI" testclass="JDBCSampler" testname="JDBC Request" enabled="true">
          <stringProp name="dataSource">postgresql</stringProp>
          <stringProp name="query">INSERT INTO customer(cust_id, credit_id, service_grade_id, credit_limit_id, party_id, cust
_name, common_region_id, cust_source_id, cust_order_id) VALUES(${cust_id}, 1112, 3, 10010, 10000, &apos;測試使用者&apos;, 200,
101, 10011);</stringProp>
          <stringProp name="queryArguments"></stringProp>
          <stringProp name="queryArgumentsTypes"></stringProp>
          <stringProp name="queryTimeout"></stringProp>
          <stringProp name="queryType">Callable Statement</stringProp>
          <stringProp name="resultSetHandler">Store as String</stringProp>
          <stringProp name="resultVariable"></stringProp>
          <stringProp name="variableNames"></stringProp>
        </JDBCSampler>
        <hashTree/>
        <JDBCDataSource guiclass="TestBeanGUI" testclass="JDBCDataSource" testname="JDBC Connection Configuration" enabled="t
rue">
          <boolProp name="autocommit">true</boolProp>
          <stringProp name="checkQuery"></stringProp>
          <stringProp name="connectionAge">5000</stringProp>
          <stringProp name="dataSource">postgresql</stringProp>
          <stringProp name="dbUrl">jdbc:postgresql://10.1.226.201:6603/postgres?binaryTransfer=false&amp;forcebinary=false</s
tringProp>
          <stringProp name="driver">org.postgresql.Driver</stringProp>
          <boolProp name="keepAlive">true</boolProp>
          <stringProp name="password">123456</stringProp>
          <stringProp name="poolMax">100</stringProp>
          <stringProp name="timeout">10000</stringProp>
          <stringProp name="transactionIsolation">DEFAULT</stringProp>
          <stringProp name="trimInterval">60000</stringProp>
          <stringProp name="username">zgy</stringProp>
        </JDBCDataSource>
        <hashTree/>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random Variable" enabled="tru
e">
          <stringProp name="variableName">cust_id</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="maximumValue">20000000</stringProp>
          <stringProp name="randomSeed"></stringProp>
          <boolProp name="perThread">false</boolProp>
        </RandomVariableConfig>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>
           

針對上述流程檔案,分解為幾步:

  • 線程組設定:

    ThreadGroup.num_threads 線程數,就是我們常說的并發數

    LoopController.loops 循環次數

    ThreadGroup.ramp_time 啟動時間,類似于LR的準備時間

<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="測試adb單查詢性能" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="L
oopController" testname="循環控制器" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">10000</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">0</stringProp>
        <longProp name="ThreadGroup.start_time">1475998829000</longProp>
        <longProp name="ThreadGroup.end_time">1475998829000</longProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration">180</stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>
           
  • AntDB連接配接設定:

    dbUrl: antdb的URL

    driver: 驅動類型

    username:資料庫使用者名

    password: 資料庫密碼

    checkQuery:連接配接檢查,比方配置select 1,每次建立連接配接後會執行,測試中一般不設定

<JDBCDataSource guiclass="TestBeanGUI" testclass="JDBCDataSource" testname="JDBC Connection Configuration" enabled="t
rue">
          <boolProp name="autocommit">true</boolProp>
          <stringProp name="checkQuery"></stringProp>
          <stringProp name="connectionAge">5000</stringProp>
          <stringProp name="dataSource">postgresql</stringProp>
          <stringProp name="dbUrl">jdbc:postgresql://10.1.226.201:6603/postgres?binaryTransfer=false&amp;forcebinary=false</s
tringProp>
          <stringProp name="driver">org.postgresql.Driver</stringProp>
          <boolProp name="keepAlive">true</boolProp>
          <stringProp name="password">123456</stringProp>
          <stringProp name="poolMax">100</stringProp>
          <stringProp name="timeout">10000</stringProp>
          <stringProp name="transactionIsolation">DEFAULT</stringProp>
          <stringProp name="trimInterval">60000</stringProp>
          <stringProp name="username">zgy</stringProp>
        </JDBCDataSource>
           
  • 變量設定:

    variableName: 變量名

    minimumValue: 最小值

    maximumValue: 最大值

    有幾種取值方式,感興趣可以自己去試驗,本次選取的是:Random(取随機數)

<RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Random Variable" enabled="tru
e">
          <stringProp name="variableName">cust_id</stringProp>
          <stringProp name="outputFormat"></stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="maximumValue">20000000</stringProp>
          <stringProp name="randomSeed"></stringProp>
          <boolProp name="perThread">false</boolProp>
        </RandomVariableConfig>
           
  • jdbc requst:

    dataSource: 取上面AntDB連接配接的name

    query: 執行的sql,引用變量的話用${變量名}

    queryType: 對應jdbc的方法調用

<JDBCSampler guiclass="TestBeanGUI" testclass="JDBCSampler" testname="JDBC Request" enabled="true">
          <stringProp name="dataSource">postgresql</stringProp>
          <stringProp name="query">INSERT INTO customer(cust_id, credit_id, service_grade_id, credit_limit_id, party_id, cust
_name, common_region_id, cust_source_id, cust_order_id) VALUES(${cust_id}, 1112, 3, 10010, 10000, &apos;測試使用者&apos;, 200,
101, 10011);</stringProp>
          <stringProp name="queryArguments"></stringProp>
          <stringProp name="queryArgumentsTypes"></stringProp>
          <stringProp name="queryTimeout"></stringProp>
          <stringProp name="queryType">Callable Statement</stringProp>
          <stringProp name="resultSetHandler">Store as String</stringProp>
          <stringProp name="resultVariable"></stringProp>
          <stringProp name="variableNames"></stringProp>
        </JDBCSampler>
           

到此,安裝和配置部分完成。

測試AntDB:

執行很簡單:

[[email protected] antdb2.]$ vim jmeter.sh
#!/bin/bash
jmx=$1
jmeter -n -t $jmx -l jmeterlog.jtl
[[email protected] adb2.]$ sh jmeter.sh insert.jmx 
           

會在目前目錄下生成兩個檔案:

jmeter.log 記錄執行過程日志,包括性能結果記錄

jmeterlog.jtl 記錄每個請求的響應

[[email protected] antdb2]$ ll
-rw-rw-r-- 1 zhugy zhugy 201100 Feb  7 16:36 jmeter.log
-rw-rw-r-- 1 zhugy zhugy  19662 Feb  7 16:36 jmeterlog.jtl
[[email protected] antdb2]$ tail f jmeter.log 
tail: cannot open `f' for reading: No such file or directory
==> jmeter.log <==
// :: INFO  - jmeter.engine.StandardJMeterEngine: All thread groups have been started 
// :: INFO  - jmeter.threads.JMeterThread: Thread started: 測試adb單查詢性能 - 
// :: INFO  - jmeter.samplers.SampleResult: Note: Sample TimeStamps are START times 
// :: INFO  - jmeter.samplers.SampleResult: sampleresult.default.encoding is set to ISO-- 
// :: INFO  - jmeter.samplers.SampleResult: sampleresult.useNanoTime=true 
// :: INFO  - jmeter.samplers.SampleResult: sampleresult.nanoThreadSleep= 
// :: INFO  - jmeter.threads.JMeterThread: Thread is done: 測試adb單查詢性能 - 
// :: INFO  - jmeter.threads.JMeterThread: Thread finished: 測試adb單查詢性能 - 
// :: INFO  - jmeter.engine.StandardJMeterEngine: Notifying test listeners of end of test 
// :: INFO  - jmeter.reporters.Summariser: summary =       in   s =    /s Avg:    Min:    Max:    Err:      (%) 
[[email protected] antdb2]$ tail f jmeterlog.jtl 
tail: cannot open `f' for reading: No such file or directory
==> jmeterlog.jtl <==
,,JDBC Request,,OK,測試adb單查詢性能 -,text,true,,,,
,,JDBC Request,,OK,測試adb單查詢性能 -,text,true,,,,
,,JDBC Request,,OK,測試adb單查詢性能 -,text,true,,,,
,,JDBC Request,,OK,測試adb單查詢性能 -,text,true,,,,