基於jmeter-dubbo協議壓測實踐
背景
為了滿足公司業務發展及效能要求,公司技術架構在很多業務介面呼叫設計中引用到了dubbo協議呼叫方式,對於以前HTTP feign呼叫的介面轉為dubbo泛化呼叫後,介面效能如何?有何影響?需要進行壓測評估。為解決公司RPC dubbo協議呼叫壓測問題,需升級jmeter壓測元件,擴充套件壓測協議支援。
Dubbo泛化呼叫原理
在進行dubbo協議介面壓測實施之前,我們有必要事先了解dubbo泛化呼叫的過程和原理。
所謂dubbo泛化呼叫即通常我們想呼叫別人的dubbo服務時,我們需要在專案中引入對應的jar包。而泛化呼叫的作用是,我們無需依賴相關jar包,也能呼叫到該服務。
dubbo泛化呼叫,主要涉及API方式和Spring方式,下面就是2種dubbo呼叫的簡單程式碼示例:
packagecom.dewu.main.dubbo.provider.service.impl; public interfacedubboHalloService { StringsayHallo(String name); }
API呼叫方式
ReferenceConfig<GenericService>referenceConfig=newReferenceConfig<>(); referenceConfig.setApplication(newApplicationConfig("test")); referenceConfig.setRegistry(newRegistryConfig("8848")); referenceConfig.setInterface("com.dewu.main.dubbo.provider.service.impl.dubboHalloService"); referenceConfig.setGeneric(true); GenericServicegenericService=referenceConfig.get(); Objectresult=genericService.$invoke( "hallo", newString[]{"java.lang.String"}, newObject[]{"1234"}); System.out.println(result);
Spring呼叫方式
xml配置設定
<dubbo:reference id="dubboHalloService" interface="com.dewu.main.dubbo.provider.service.impl.dubboHalloService" generic="true" />
注入使用
@Service publicclassPersonService{ @Resource(name="halloService") privateGenericServicegenericService; publicvoidsayHallo(){ Objectresult=genericService.$invoke( "hallo", newString[]{"java.lang.String"}, newObject[]{"1234"}); System.out.println(result); } }
在兩種呼叫方式中,我們都需要使用被呼叫介面的字串引數生成GenericService,通過GenericService的$invoke間接呼叫目標介面的介面。
public interface GenericService{ Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException; }
泛化呼叫和直接呼叫在消費者者端,在使用上的區別是,我們呼叫服務時使用的介面為GenericService,方法為$invoker。在底層的區別是,消費者端發出的rpc報文發生了變化。
在使用上,不管哪種配置方式,我們都需要配置generic=true,設定generic=true後,RefereceConfig的interfaceClass會被強制設定為GenericService。
Jmeter壓測元件實踐使用
安裝準備
從https://github.com/thubbo/jmeter-plugins-for-apache-dubbo/releases/tag/2.7.8下載dubbo外掛jmeter-plugins-dubbo-2.7.8-jar-with-dependencies.jar放置jmeter \lib\ext目錄,或者下載使用jmeter-plugins-dubbo.jar,但此種方式需要引入如下相關依賴JAR包。
dubbo-2.5.3.jar
javassist-3.15.0-GA.jar
zookeeper-3.4.6.jar
zkclient-0.1.jar
jline-0.9.94.jar
netty-3.7.0-Final.jar
slf4j-api-1.7.5.jar
log4j-over-slf4j-1.7.5.jar
注意:此兩種方式不能同時使用,否則會產生JAR包衝突
使用步驟
1.建立執行緒組->新增Dubbo Sample請求
2.配置註冊中心地址,填寫壓測請求介面和方法以及請求體引數
3.點選執行,檢視響應結果
元件詳解
註冊中心型別
- Protocol=none為直連方式
- Protocol=zookeeper使用zk註冊中心
- Protocol=使用nacas註冊中心
- Protocol=multicast為廣播方式
- Protocol=redis使用redis註冊中心
- Protocol=simple使用simple註冊中心
請求引數描述
- 當使用zk,address填入zk地址(叢集地址使用","分隔),使用dubbo直連,address填寫直連地址和服務埠。
- timeout:服務方法呼叫超時時間(毫秒)。
- version:服務版本,與服務提供者的版本一致。
- retries:遠端服務呼叫重試次數,不包括第一次呼叫,不需要重試請設為0。
- cluster:叢集方式,可選方式型別:failover/failfast/failsafe/failback/forking。
- group: 服務分組,當一個介面有多個實現,可以用分組區分,必需和服務提供方一致。
- interface需要填寫介面型別完整名稱,含包名。
- 引數支援任何型別,包裝類直接使用java.lang下的包裝類,小型別使用:int、float、shot、double、long、byte、boolean、char,自定義類使用類完全名稱。
- 引數值,基礎包裝類和基礎小型別直接使用值,例如:int為1,boolean為true等,自定義類與List或者Map等使用json格式資料。
引數型別示例
Java型別 |
paramType |
paramValue |
int |
int |
1 |
int[] |
int[] |
[1, 2] |
double |
double |
1.2 |
double[] |
double[] |
[1.2, 1.3] |
short |
short |
1 |
short[] |
short[] |
[1, 2] |
float |
float |
1.2 |
float[] |
float[] |
[1.2, 1.3] |
long |
long |
1 |
long[] |
long[] |
[1, 2] |
byte |
byte |
位元組 |
byte[] |
byte[] |
位元組 |
boolean |
boolean |
true false |
boolean[] |
boolean[] |
[true, false] |
char |
char |
A,如果字元過長取值為:"STR".charAt(0) |
char[] |
char[] |
[A, B] |
java.lang.String |
java.lang.String String string |
"foo" foo |
java.lang.String[] |
java.lang.String[] String[] string[] |
["foo1", "foo2"] |
java.lang.Integer |
java.lang.Integer Integer integer |
1 |
java.lang.Integer[] |
java.lang.Integer[] Integer[] integer[] |
[1, 2] |
java.lang.Double |
java.lang.Double Double |
1.2 |
java.lang.Double[] |
java.lang.Double[] Double[] |
[1.2, 1.3] |
java.lang.Short |
java.lang.Short Short |
1 |
java.lang.Short[] |
java.lang.Short[] Short[] |
[1, 2] |
java.lang.Long |
java.lang.Long Long |
1 |
java.lang.Long[] |
java.lang.Long[] Long[] |
[1, 2] |
java.lang.Float |
java.lang.Float Float |
1.2 |
java.lang.Float[] |
java.lang.Float[] Float[] |
[1.2, 1.3] |
java.lang.Byte |
java.lang.Byte Byte |
位元組 |
java.lang.Byte[] |
java.lang.Byte[] Byte[] |
位元組 |
java.lang.Boolean |
java.lang.Boolean Boolean |
true false |
java.lang.Boolean[] |
java.lang.Boolean[] Boolean[] |
[true, false] |
JavaBean |
com.your.package.BeanName |
{"att1":"foo","att2":"foo2"} |
JavaBean[] |
com.your.package.BeanName |
[{"att1":"foo"}, {"att1":"foo2"}] |
java.util.Map以及子類 |
java.util.Map以及子類 |
{"att1":"foo","att2":"foo2"} |
java.util.Map<String,JavaBean> |
java.util.Map |
{"keyName":{"att1":"foo"}} |
java.util.HashMap<Object,Object> |
java.util.HashMap |
{"keyName":{"att1":"foo"}} |
java.util.Collection以及子類 |
java.util.Collection以及子類 |
["a","b"] |
java.util.List<String> |
java.util.List |
["a", "b"] |
java.util.List<JavaBean> |
java.util.List |
[{"att1":"foo1"}, {"att1":"foo2"}] |
java.util.List<Map<Object, JavaBean>> |
java.util.List |
[{"keyName1":{"att1":"foo1"}}, {"keyName2":{"att1":"foo1"}}] |
java.util.List<Long> |
java.util.List |
[1, 2, 3] |
java.util.ArrayList<Object> |
java.util.ArrayList |
["foo" , 1, true] |
踩坑指南
1.jar包衝突
2.缺少protostuff jar包依賴
3.引數格式問題導致呼叫報錯
4.provide服務提供者註冊出現問題導致連線拒絕