這是我對Dubbo服務開展性能測試所作準備的第二篇學習筆記,編寫了一對Dubbo-Demo實例。主要參照的原帖:http://www.cnblogs.com/miaomiaokaixin/p/6129733.htmlhtml
因爲原做者這篇指導文章寫做的時間是2016年,使用的依賴包版本較舊;在學習的過程當中,改用了較新版本的Maven依賴,同時遇到一些錯誤。本文的寫做目的在於及時的記錄下學習過程、應對問題的解決等。java
本文講解jmeter測試dubbo接口的實現方式,文章以一個dubbo的接口爲例子進行講解,該dubbo接口實現的功能爲:git
若是想搭建Dubbo學習環境,請看另外一篇文檔《搭建Dubbo開發學習環境》。github
1、 服務端的工程web
代碼架構以下:redis
一、 建立一個Maven工程,取名:demo_dubbo_providerspring
POM文件爲:mongodb
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">apache <modelVersion>4.0.0</modelVersion>服務器 <groupId>com.ustc.demo.provider</groupId> <artifactId>demo_dubbo_provider</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging>
<name>dubbo-provider</name> <url>http://maven.apache.org</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.1</version> </dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency>
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.12</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.0.1</version> </dependency>
</dependencies>
<build> <plugins> <plugin> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack</id> <phase>package</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.1</version> <includes>META-INF/assembly/**</includes> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin>
<plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptor>src/main/assembly/assembly.xml</descriptor> <encoding>UTF-8</encoding> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
</project> |
二、 在src/main下新建文件夾assembly,而後在assembly文件夾下新建assembly.xml文件
<?xml version="1.0" encoding="UTF-8"?> <assembly> <id>assembly</id> <formats> <format>tar.gz</format> </formats> <includeBaseDirectory>true</includeBaseDirectory> <fileSets> <fileSet> <directory>${project.build.directory}/dubbo/META-INF/assembly/bin</directory> <outputDirectory>bin</outputDirectory> <fileMode>0755</fileMode> </fileSet> <fileSet> <directory>src/main/assembly/conf</directory> <outputDirectory>conf</outputDirectory> <fileMode>0644</fileMode> </fileSet> </fileSets> <dependencySets> <dependencySet> <outputDirectory>lib</outputDirectory> </dependencySet> </dependencySets> </assembly> |
三、 在src/main/assembly文件夾下新建conf文件夾,而後在conf文件夾下新建dubbo.properties文件。文件中zookeeper的地址根據實際進行修改。
dubbo.container=log4j,spring dubbo.application.name=demo-dubbo-provider dubbo.application.owner=jason #dubbo.registry.address=multicast://127.0.0.1:1234 dubbo.registry.address=zookeeper://192.168.8.241:2181 #dubbo.registry.address=redis://127.0.0.1:6379 #dubbo.registry.address=dubbo://127.0.0.1:9090 dubbo.monitor.protocol=registry dubbo.protocol.name=dubbo dubbo.protocol.port=20880 #dubbo.service.loadbalance=roundrobin #dubbo.log4j.file=logs/dubbo-demo-provider.log #dubbo.log4j.level=WARN |
四、 在src/test/resources包路徑下,新建dubbo.properties文件,內容和上面3的dubbo.properties文件內容相同。
五、 在src/test/resources路徑下,新建log4j.xml文件,內容以下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders --> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-5p: %c - %m%n" /> </layout> </appender>
<appender name="myFile" class="org.apache.log4j.RollingFileAppender"> <param name="File" value="logs/output.log" /><!-- 設置日誌輸出文件名 --> <!-- 設置是否在從新啓動服務時,在原有日誌的基礎添加新日誌 --> <param name="Append" value="true" /> <param name="MaxBackupIndex" value="10" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%p (%c:%L)- %m%n" /> </layout> </appender>
<!-- Application Loggers --> <logger name="com.ustcinfo.ishare.eip.si"> <level value="error" /> </logger>
<!-- 3rdparty Loggers --> <logger name="org.springframework.core"> <level value="warn" /> </logger>
<logger name="org.springframework.beans"> <level value="info" /> </logger>
<logger name="org.springframework.context"> <level value="info" /> </logger>
<logger name="org.springframework.web"> <level value="info" /> </logger> <logger name="org.mongodb.driver"> <level value="warn" /> </logger>
<!-- Root Logger --> <root> <priority value="error" /> <appender-ref ref="console" /> </root>
</log4j:configuration> |
下面開始編寫provider的主方法:
六、 編寫provider的接口sayHello,新建DemoService.java類:
package com.ustc.demo.provider;
public interface DemoService { public String sayHello(String name); } |
七、 編寫sayHello接口的實現類,新建DemoServiceImpl.java類:
package com.ustc.demo.provider;
import java.text.SimpleDateFormat; import java.util.Date;
public class DemoServiceImpl implements DemoService {
@Override public String sayHello(String name) { // TODO Auto-generated method stub String time = new SimpleDateFormat("HH:mm:ss").format(new Date()); System.out.println("From consumer: " + name);
return "The current time is:" + time; }
} |
八、 編寫spring的配置文件,在META-INF/spring文件夾下的demo-provider.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <bean id="demoService" class="com.ustc.demo.provider.DemoServiceImpl" /> <dubbo:registry address="zookeeper://192.168.8.241:2181" /> <dubbo:protocol name="dubbo" host="192.168.9.107" port="20880" /> <dubbo:service interface="com.ustc.demo.provider.DemoService" ref="demoService"/> </beans> |
dubbo:registry address:服務註冊於zookeeper所在的服務器;
dubbo:protocol host:服務提供方provider運行的服務器,添加Host字段能夠避免其餘機器上的消費方沒法訪問提供方。
九、 編寫測試main方法,新建DemoServiceMain.java類:
package com.ustc.demo.provider;
public class DemoServiceMain { public static void main(String[] args) { com.alibaba.dubbo.container.Main.main(args); } } |
這樣服務端的代碼就寫好了,實現的功能是當消費者來詢問當前時間是幾點的時候,返回當前時間。
2、 消費端的工程
代碼架構以下:
一、 建立一個Maven工程,取名:demo_dubbo_consumer
POM文件爲:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ustc.demo.consumer</groupId> <artifactId>demo_dubbo_comsumer</artifactId> <version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>consumer</name> <url>http://maven.apache.org</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.1</version> </dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.12</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.0.1</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.5.RELEASE</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency>
</dependencies>
<build> <plugins> <plugin> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack</id> <phase>package</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.1</version> <includes>META-INF/assembly/**</includes> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptor>src/main/assembly/assembly.xml</descriptor> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
</plugins> </build>
</project> |
PS:上面文件中,有幾處對log4j註釋的地方,主要的緣由是在最後build的時候,會提示工程中存在多個版本的log4j、產生衝突;所以對幾處較舊的版本進行了排除。
2. 在src/main下新建文件夾assembly,而後在assembly文件夾下新建assembly.xml文件。文件內容和Provider工程中的同名文件相同。
3. 在src/main/assembly文件夾下新建conf文件夾,而後在conf文件夾下新建dubbo.properties文件。文件內容和Provider工程中的同名文件相同。
4. 在src/test/resources包路徑下,新建dubbo.properties文件,內容和上面的3中dubbo.properties文件內容相同。
5. 編寫provider的接口sayHello,新建DemoService.java類:
package com.ustc.demo.provider;
public interface DemoService { public String sayHello(String name); } |
6. 編寫消費端請求類調用sayHello方法,新建DemoAction.java類
package com.ustc.demo.consumer;
import com.ustc.demo.provider.DemoService;
public class DemoAction { private DemoService demoService;
public void setDemoService(DemoService demoService) { this.demoService = demoService; }
public void start() throws Exception { for (int i = 0; i < Integer.MAX_VALUE; i ++) { try { String hello = demoService.sayHello("Hello, how much is the current time?"); System.out.println("From provider: " + hello); } catch (Exception e) { e.printStackTrace(); } Thread.sleep(2000); } } } |
7. 編寫spring的配置文件,在META-INF/spring文件夾下的dubbo-demo-action.xml文件:
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <bean class="com.ustc.demo.consumer.DemoAction" init-method="start"> <property name="demoService" ref="demoService" /> </bean> </beans> |
8. 編寫spring的配置文件,在META-INF/spring文件夾下的dubbo-demo-consumer.xml文件:
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:reference id="demoService" interface="com.ustc.demo.provider.DemoService" /> </beans> |
9. 編寫測試main方法,新建DemoConsumerMain.java類:
package com.ustc.demo.consumer;
public class DemoConsumerMain { public static void main(String[] args) { com.alibaba.dubbo.container.Main.main(args); } } |
10. 編寫log4j2的配置文件,在src/main/resources目錄下建立log4j2.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%m%n" /> </Console> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration> |
這樣咱們就完成了本地消費者代碼,在編寫符合jmeter格式的代碼前,咱們首先在本地開發工具中運行看看效果。
先啓動服務提供方的main方法,而後啓動服務消費方的main方法:
服務提供方控制檯:
服務消費方控制檯:
這樣調試發現消費端向服務端發送:「How much is the current time?」
而後服務端返回當前的時間,該dubbo接口的功能正常實現。
3、 用JMeter模擬消費方
咱們如今想對dubbo接口進行性能測試,能夠用jmeter模擬服務消費方併發調用服務提供方。由於jmeter支持java請求,故咱們能夠將服務提供方打包部署到服務器上運行,將服務消費方打成jar包放到jmeter的/lib/ext文件夾中,這樣就能實現jmeter模擬消費方去請求服務端,進行性能測試。
如今咱們來說解如何將上面的服務消費端的代碼編寫成能夠打包放到jmeter中的jar包代碼。
只須要對上面的消費者代碼進行3處修改便可:
- POM.xml文件
pom.xml文件中添加對jmeter的支持,在<dependencies></dependencies>之間添加以下代碼:
<!-- java jmeter依賴jar包 --> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_core</artifactId> <version>3.3</version> </dependency> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_java</artifactId> <version>3.3</version> </dependency> |
- 在src/main/resources下新建applicationConsumer.xml文件,zookeeper地址根據須要進行修改:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<!-- consumer application name --> <dubbo:application name="consumer-jmeter" /> <!-- registry address, used for consumer to discover services --> <dubbo:registry address="zookeeper://192.168.8.241:2181" /> <!-- which service to consume? --> <dubbo:reference id="demoService" interface="com.ustc.demo.provider.DemoService" /> </beans> |
- 在com.ustc.demo.consumer包下新建JmeterDemoAction.java類:
package com.ustc.demo.consumer;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient; import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; import org.apache.jmeter.samplers.SampleResult; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ustc.demo.provider.DemoService;
public class JmeterDemoAction extends AbstractJavaSamplerClient {
ApplicationContext context = null; public DemoService demoService = null;
public void setupTest(JavaSamplerContext arg0) { context = new ClassPathXmlApplicationContext("applicationConsumer.xml"); ((AbstractApplicationContext) context).start(); demoService = (DemoService) context.getBean("demoService"); }
@Override public SampleResult runTest(JavaSamplerContext arg0) { SampleResult sr = new SampleResult();
try { sr.sampleStart(); // 將Request內容輸出到Jmeter-查看結果樹的請求頁面 sr.setSamplerData("From consumer: Hello, how much is the current time?"); sr.setDataType(SampleResult.TEXT); // 調用provider的demoService.sayHello方法 String response = demoService.sayHello("Hello, how much is the current time?"); // 填寫Jmeter-查看結果樹的取樣器結果 sr.setResponseCodeOK(); sr.setResponseMessage("Java Sampler Response is done. "); // 將Response內容輸出到Jmeter-查看結果樹的響應數據頁面 sr.setResponseData("From provider: " + response, "utf-8"); sr.setDataType(SampleResult.TEXT); // 標記成功,並中止採樣 sr.setSuccessful(true); sr.sampleEnd(); } catch (Exception e) { e.printStackTrace(); } return sr; }
@SuppressWarnings("deprecation") public void teardownTest(JavaSamplerContext arg0) { if(null != context){ ((AbstractApplicationContext) context).destroy(); } }
// 供調試使用;打包前記得註釋掉 main 方法 public static void main(String[] args) { JmeterDemoAction test = new JmeterDemoAction(); test.setupTest(null); test.runTest(null); test.teardownTest(null); System.exit(0); }
} |
這樣就完成了jmeter的消費端代碼編寫。
4、 Maven Install打包消費端工程
打包完成後能夠看到消費端的target下生成了兩個文件:
一個demo_dubbo_comsumer-0.0.1-SNAPSHOT.jar;
一個demo_dubbo_comsumer-0.0.1-SNAPSHOT-assembly.tar.gz。
- 建立一個新的dependency-demo_dubbo_consumer文件夾;將consumer-0.0.1-SNAPSHOT-assembly.tar.gz中的lib文件夾下全部的jar包解壓到dependency-demo_dubbo_consumer文件夾下,而後將此文件夾拷貝到jmeter的lib/目錄下。
- 將consumer-0.0.1-SNAPSHOT.jar拷貝到jmeter的lib/ext目錄下。
因爲在這個Demo中,我沒有打包服務提供方的工程,所以Jmeter模擬消費方的執行過程當中,在Eclipse中Provider工程的main方法要保持運行。
在Dubbo-Admin頁面查看的狀況以下:
5、 建立Jmeter模擬的消費方測試腳本
- 引用測試依賴的jar文件
測試計劃 – Add directory or jar to classpath - 點擊瀏覽、定位到dependency-demo_dubbo_consumer文件夾,以後按Enter鍵就能夠所有引入到classpath中。
2.建立一個Java請求
添加一個線程組、添加Sampler – Java Sampler;
選中剛剛編寫的consumer.JmeterDemoAction:
3.添加結果查看器
添加監聽器:結果查看器、聚合報告。
4.簡單的執行
修改線程組的設置:
但願以20個線程啓動執行,循環10次:
啓動測試執行:
查看聚合報告:
查看結果樹:
在Dubbo-Admin頁面查看到以下:
因爲腳本中作了優化,不會過多建立消費方,僅爲Jmeter執行時啓動的線程數量。