1、Dubbo基础架构解析
架构的演进
要了解Dubbo框架,我们首先需要了解框架的由来和演进,了解为什么要引入这种框架。
架构的演进:单体架构---->垂直应用架构---->分布式应用架构---->微服务架构
单体架构是将所有功能都部署在一个应用上,适合网站流量很小的时候,减少部署节点和成本,此时用于简化增删改查工作量的数据访问框架(ORM)是关键。但是它的缺点也是非常显著的,比如:
1、有一个功能不能使用,其它功能也不能幸免,安全指数低
2、更新维护成本非常高,有一个功能需要下线更新,必须将整个应用进行下线,而且整个发布流程非常麻烦
3、提升的性能是有限的,当访问量逐渐增大,由于单台机器性能较低,单一应用也不能及时处理请求给出响应
4、成本过高,没有办法针对某一个具体的模块做性能的提升
为了解决上述问题,提出了垂直应用架构,垂直应用架构是将应用扩展成多个互不相干的应用,多个功能通过业务的边界拆分开来,此时,用于加速前端页面开发的Web框架(MVC)是关键。但是随着垂直应用越来越多,它的缺点也显现出来:
1、每个独立部署的服务之间,公共的部分需要部署多份。对公共部分的修改、部署、更新都需要重复操作,维护成本较大
为了解决这个问题,将交互业务核心从应用中抽取出来作为独立的服务,逐渐形成稳定的服务中心,其它服务通过网络通信直接调用服务中心中需要使用的服务,这种框架称为分布式服务架构,用于提高业务复用及整合的分布式服务框架(RPC)是关键。但是当服务中心越来越多时,它的问题也显现出来了:
1、服务越来越多,服务如何被发现?
2、服务越来越多,服务如何被治理?
3、服务之间如何实现高效通信?
为了解决上述问题,引入了微服务架构概念,微服务框架引入了一台注册中心服务器存放所有的服务提供者信息,当服务器启动时,便会自动将自己的信息传送给注册中心进行注册。注册中心会将服务提供者信息返回给服务消费者,服务消费者根据信息以及负载均衡策略调用相应服务提供者上的服务
RPC
rpc是在应用层之上的一种远程调用(remote procudure call)协议,规定了通信双方(不同服务器间通过的网络通信)进行通信的数据格式是什么样的,以及数据如何传输(可以是使用http协议、dubbo协议等规范),解决不同服务器之间服务的调用过程:
- 指明调用的类或接口
- 指明调用的方法及参数,通常还会包含额外控制数据,如单次请求的序列化方式、超时时间、压缩方式和鉴权信息等
- 有服务降级、流量控制的功能,保证服务的高可用
一个完整的RPC架构里面包含了四个核心的组件:
- Client:客户端,服务消费者
- Server:服务提供者
- Client Stub:存放服务端的地址消息,将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务端
- Server Stub:接收客户端发送过来的消息,将消息解包,并调用本地的方法
RPC调用远程通信流程:
-
服务消费者以本地调用方式调用服务
-
client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体(此时需遵循指定的协议,如http协议、或者dubbo协议等),并将相关信息序列化成二进制形式
-
client stub找到服务地址,并将消息发送到服务端(此时通信大多数是采取基于netty的IO通信框架形)
-
server stub收到消息后进行解码(反序列化,将二进制形式转变为对象),根据解码结果调用本地的服务
-
本地服务执行并将结果返回给server stub
-
server stub将返回结果再次序列化后打包成消息并发送至消费方
-
client stub接收到消息,并进行解码
-
服务消费方得到最终结果
RPC框架两个核心模块(决定RPC的性能和效率):通讯,序列化
目前RPC框架有很多种:dubbo、gRPC、Thrift、HSF
Dubbo
Apache Dubbo 是一款微服务开发框架,它提供了RPC通信与微服务治理两大关键能力。使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求(官网原话)
优点特性:
- 面向接口代理的高性能RPC调用:服务以接口为粒度,无需关心远程调用的底层细节
- 智能负载均衡:根据多台服务器访问压力,智能分配服务器的访问量,比如用户业务A服务器访问量为100,B为10,c为2,则之后的请求将集中分配给B和C,以减轻A的压力,达到ABC三台服务器的负载分配均匀
- 服务自动注册与发现:将服务自动注册到服务中心进行统一管理,可定时检测到不可用服务,以及可用服务
- 高度可扩展能力:基于微内核+插件原则,几乎所有东西都可进行扩展
- 运行期流量调度:通过配置不同的路由规则,轻松实现灰度发布。灰度发布指将线上部分服务器先升级到新版本,待稳定后,再逐步将其他服务器也升级到新版本
- 可视化的服务治理与运维:提供界面,进行服务治理、查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数
Dubbo包括三大中心化组件:
- 注册中心。协调 Consumer 与 Provider 之间的地址注册与发现
- 配置中心。
- 存储 Dubbo 启动阶段的全局配置,保证配置的跨环境共享与全局一致性
- 负责服务治理规则(路由规则、动态配置等)的存储与推送。
- 元数据中心。
- 接收 Provider 上报的服务接口元数据,为 Admin 等控制台提供运维能力(如服务测试、接口文档等)
- 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展
spring中使用dubbo简单example
工程目录
org.example.api.SiteService.java
package org.example.api;
public interface SiteService {
String getName(String name);
}
org.example.service.Impl.SiteServiceImpl.java
package org.example.service.Impl;
import org.example.api.SiteService;
public class SiteServiceImpl implements SiteService {
@Override
public String getName(String name) {
return "hello:"+name;
}
}
\my-dubbo-service-provider\pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>my-dubbo-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-dubbo-service-provider</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>my-dubbo-interfaces</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-alpha2</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!-- zk -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
</dependencies>
</project>
src/main/resources/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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 定义服务的名称,提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="site-service-provider" />
<!-- 指明注册中心的地址,使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://172.16.253.55:2181" />
<!-- 指明使用的协议,用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20881" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="org.example.api.SiteService" ref="siteService" />
<!-- 服务具体实现的bean,和本地bean一样实现服务 -->
<bean id="siteService" class="org.example.service.Impl.SiteServiceImpl" />
</beans>
org.example.service.Impl.provider.java
package org.example.service.Impl;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class provider {
public static void main(String[] args){
// 加载 Spring
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"provider.xml"});
context.start();
try{
// 按任意键退出
System.in.read();
}catch(IOException e){
e.printStackTrace();
}
}
}
src/main/resources/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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 定义消费方应用名 -->
<dubbo:application name="site-service-consumer" />
<!-- 定义注册中心的地址 -->
<dubbo:registry address="multicast://172.16.253.55:2181" />
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="siteService" interface="org.example.api.SiteService" />
</beans>
org.example.Consumer.java
package org.example;
import org.example.api.SiteService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Consumer {
public static void main(String[] arg){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"consumer.xml"});
context.start();
// 从ioc容器中获取SiteService服务提供者的远程服务代理对象
SiteService siteService = (SiteService)context.getBean("siteService");
// 执行远程方法
String name = siteService.getName("world");
System.out.println( name ); // 显示调用结果
}
}
springBoot中使用dubbo简单example
工程目录:
com.qf.boot.api.SiteService
package com.qf.boot.api;
public interface SiteService {
String getName(String name);
}
my-boot-service-provider/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>my-boot-service-</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>my-boot-service-provider</name>
<description>my-boot-service-provider</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.qf</groupId>
<artifactId>my-boot-qf-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.3</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.qf</groupId>
<artifactId>my-boot-qf-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
src/main/resources/application.yml
server:
port: 9001
dubbo:
application:
name: site-services-boot-provider
registery:
address: zookeeper://172.16.253.55:2181
protocol:
name: dubbo
port: 20882
com.qf.my.boot.service.procider.impl.SiteServiceImpl
package com.qf.my.boot.service.procider.impl;
import com.qf.boot.api.SiteService;
import org.apache.dubbo.config.annotation.Service;
@Service
public class SiteServiceImpl implements SiteService {
@Override
public String getName(String name){
return "hello boot:"+name;
}
}
com.qf.my.boot.service.procider.MyBootServiceProviderApplication
package com.qf.my.boot.service.procider;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// EnableDubbo标签会去扫描所有其他标签,如Service、RestController标签等
@EnableDubbo
@SpringBootApplication
public class MyBootServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(MyBootServiceProviderApplication.class, args);
}
}
my-boot-service-consumer/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>my-boot-service-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>my-boot-service-consumer</name>
<description>my-boot-service-consumer</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.qf</groupId>
<artifactId>my-boot-qf-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.3</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.qf</groupId>
<artifactId>my-boot-qf-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
my-boot-service-consumer\src\main\resources\application.yml
server:
port: 8001
dubbo:
application:
name: site-service-boot-consumer
registry:
address: zookeeper://172.16.253.55:2181
com.qf.my.boot.service.consumer.controller.SiteController
package com.qf.my.boot.service.consumer.controller;
import com.qf.boot.api.SiteService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/site")
public class SiteController {
// 相当于spring配置中的<dubbo:reference ....>
// 用途: 1、服务启动时向注册中心订阅SiteService服务地址列表 2、生成SiteService服务的代理对象
@Reference
private SiteService siteService;
@GetMapping("/name")
public String getName(String name){
return siteService.getName(name);
}
}
com.qf.my.boot.service.consumer.MyBootServiceConsumerApplication
package com.qf.my.boot.service.consumer;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// EnableDubbo标签会去扫描所有其他标签,如Service、RestController标签等
@EnableDubbo
@SpringBootApplication
public class MyBootServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(MyBootServiceConsumerApplication.class, args);
}
}
2、telnet测试Dubbo接口
了解Telnet协议
Telnet协议是TCP/IP协议族的其中之一,是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力,在终端使用者的电脑上使用telnet程序,用它连接到服务器。。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法(百度官网原话)。有些时候Ping命令也不好使,比如因防火墙禁止或访问策略限制等,则可使用telnet测试映射端口或远程访问主机
Telnet配置以及简单测试
参考:https://jingyan.baidu.com/article/ae97a646b22fb6bbfd461d19.html
注意:目前windows10已经弃用了Telnet远程访问服务,没有下图Telnet服务器选项
步骤一:配置Telnet(没有进行配置会出现“telnet不是内部或外部命令”问题)点击“开始”—>设置—>查找“Windows功能”—>选择“启动或关闭Windows功能(或者直接选择‘程序’,再选择程序和功能下的“启动或关闭Windows功能“)—>勾选Telnet服务器和客户端—>点击‘确定’
我的电脑–>右键,选择’管理’—>
步骤二:检验Telnet服务是否安装成功,命令行输入:
telnet -help
telnet 127.0.0.1
telnet 127.0.0.1 23
telnet 127.0.0.1 80
步骤三:使用telnet远程访问某主机(目前Windows10已经不支持Telnet服务端了,据说是因为这种远程访问不安全,所以下面的都来自百度摘录)
背景介绍:若使用Telnet协议远程访问主机,其访问主机和被访问主机都必须安装相应Telnet服务,被访问主机需将用户组中某个用户添加为隶属于TelnetClinets组,其访问主机输入用户名和密码才可访问被访问主机。
在被访问主机上添加某个用户隶属于TelnetClients组
操作过程:右击桌面"计算机"→"管理"→"系统工具–本地用户和组–用户"→右击用户在其菜单栏中点击"属性"→"隶属于–添加"→在"输入对象名称来选择(示例)“中输入"TelnetClients"→最后依次"确定”。
步骤四:ping被访问主机的IP,检测网络是否正常
网络正常时Telnet IP发起远程访问主机。
输入:telnet 10.0.0.31敲回车;
进入Telnet Client客户端界面,问"您想发送吗(y/n):"输入y敲回车;
进入Telnet Service服务界面,输入(被访问主机)用户名和密码敲回车;
最后进入被访问主机的命令提示符目录下,即成功使用Telnet远程访问主机。
使用telnet对dubbo接口进行测试
步骤一:进入dubbo
telnet 对应服务器ip 端口号
步骤二:查看该服务器下的所有服务信息
dubbo> ls -l
步骤三:查看该服务下的某个服务的基本信息,包括方法以及传参
dubbo> ls -l 指定服务
步骤四:调用某个具体服务下的具体dubbo接口
dubbo> invoke 服务.方法(参数1,参数二,...,参数N)
其它telnet命令:
# 显示服务端口列表
dubbo> ps
# 显示服务地址列表
dubbo> ps -l
# 显示端口上的连接信息
dubbo> ps 30000
# 显示端口上的连接详细信息
dubbo> ps -l 30000
# 跟踪 1 次服务任意方法的调用情况
dubbo> trace com.melot.sop.sms.api.IsvSmsService
# 跟踪 10 次服务任意方法的调用情况
dubbo> trace com.melot.sop.sms.api.IsvSmsService 10
# 跟踪 1 次服务方法的调用情况
dubbo> trace com.melot.sop.sms.api.IsvSmsService.getSmsData(参数)
# 跟踪 10 次服务方法的调用情况
dubbo> trace com.melot.sop.sms.api.IsvSmsService.getSmsData(参数) 10
3、Jmeter测试Dubbo
步骤一:Jmeter下载相关插件,Jmeter本身并不支持dubbo接口的测试,需要下载第三方插件,然后将Jar包放入${JMETER_HOME}\lib\ext路径下,重启即可
需下载的jar包:jmeter-plugins-dubbo-1.0.0-SNAPSHOT-jar-with-dependencies.jar
以及导入所测接口的依赖jar包
步骤二:Jmeter新建线程组—>新建DubboSample,进行配置
配置参数:
参数 | 内容 |
---|---|
Protocol Address | 协议,包括zookeeper和dubbo协议: 1、选择zookeeper协议:Address填写zk地址,集群地址用","分隔 2、选择dubbo协议:Address填写dubbo直连地址,IP:PORT |
Timeout | 服务方法调用超时时间(毫秒) |
Version | 服务版本,与服务提供者版本一致 |
Retries | 远程服务调用次数,不包括第一次调用,不需要重试可设为0 |
Cluster | 集群方式,可选:failover、failfast、failsafe、failback、forking |
Interface | 填写类型完全名称,含包名,如:com.qf.HelloServiceImpl |
Methods | 调用的方法名 |
paramType | 基础包装类和基础小类型直接使用值,例如:int为1,boolean为true等,自定义类与List或者Map等使用json格式数据 |
步骤三:运行测试,查看结果树
4、Jmeter二次开发(结合java代码测Dubbo接口)
主要功能:提供一个Java代码的执行sampler,可以通过编写javaSampler在执行jmeter本身不支持协议的性能测试
步骤一:编写工程时,引入jmeter的lib\ext目录下的jar包:
ApacheJMeter_components.jar
ApacheJMeter_core.jar
ApacheJMeter_java.jar
jorphan.jar
logkit.jar
avalon-framework-4.1.4.jar
以及引入服务提供者的代码jar包和依赖,没有的话让开发提供,如:user-service-provider-1.0-SNAPSHOT.jar (可参考dubbo环境搭建中的代码部分)
步骤二:二次开发代码
目录
模拟消费端,初始化数据,连接zookeeper
src/main/java/InitData.java
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.utils.ReferenceConfigCache;
import gmall.bean.UserService;
public class InitData {
public static UserService getUserService(){
ApplicationConfig application = new ApplicationConfig();
application.setName("order-service-consumer");
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("127.0.0.1:2181");
//如果服务端没有设置分组参数,调用的时候也不需要设置分组
// registryConfig.setGroup("dubbo_test");
//指定dubbo使用的注册中心版本
registryConfig.setProtocol("zookeeper");
// 设置连接zookeeper的客户端
registryConfig.setClient("zkclient");
ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<UserService>();
referenceConfig.setInterface(UserService.class);
referenceConfig.setTimeout(5000);
referenceConfig.setRetries(3);
referenceConfig.setVersion("*");
referenceConfig.setStub("gmall.bean.UserServiceStub");
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setCheck(false);
consumerConfig.setTimeout(5000);
MonitorConfig monitorConfig = new MonitorConfig();
monitorConfig.setProtocol("registry");
referenceConfig.setApplication(application);
referenceConfig.setRegistry(registryConfig);
referenceConfig.setConsumer(consumerConfig);
referenceConfig.setMonitor(monitorConfig);
//缓存referenceConfig,防止出现多个连接
ReferenceConfigCache cache = ReferenceConfigCache.getCache();
UserService userService = referenceConfig.get();
return userService;
}
}
调用服务端,运行相关测试用例
src/main/java/TestDubboSampler.java
import com.alibaba.dubbo.common.json.JSON;
import gmall.bean.UserAddress;
import gmall.bean.UserService;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
public class TestDubboSampler extends AbstractJavaSamplerClient {
UserService userService;
//初始化数据
@Override
public void setupTest(JavaSamplerContext context) {
userService = InitData.getUserService();
super.setupTest(context);
}
//设置入参
@Override
public Arguments getDefaultParameters() {
Arguments args = new Arguments();
args.addArgument("userId","2");
return args;
}
//执行用例
@Override
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
//获取入参
String user_id = javaSamplerContext.getParameter("userId");
UserAddress userAddress = userService.getUserAddressList(user_id).get(0);
//可查得出start_time至end_time的时间
long start = System.currentTimeMillis();
SampleResult result = SampleResult.createTestSample(start,System.currentTimeMillis());
//等同于
/*
SampleResult result = new SampleResult();
//开始统计响应时间
result.sampleStart();
//结束统计响应时间
result.sampleEnd();
*/
result.setSampleLabel("Dubbo-test");
result.setDataEncoding("utf-8");
result.setResponseCodeOK();;
//查看结果树的响应数据
result.setResponseData(userAddress.toString(),"utf-8");
//响应成功
result.setSuccessful(true);
return result;
}
//调试
public static void main(String[] args) {
TestDubboSampler tds = new TestDubboSampler();
Arguments argument = new Arguments();
argument.addArgument("userId", "2");
JavaSamplerContext jsc = new JavaSamplerContext(argument);
tds.setupTest(jsc);
tds.runTest(jsc);
}
}
步骤三:编辑相关测试代码,完成后,将编译好的代码打成jar包,放置在 /jmeter的lib/ext下
由于JmeterDubboTest中使用到了自己编写的gmall-interface,所以在打包前需要将gmall-interface-1.0-SNAPSHOT.jar上传到私有库中(JmeterDubboTest中依赖得下载地址),或者安装到自己的本地依赖下载仓库
1、将gmall-interface依赖下载到自己本地:
在控制台中运行以下语句
mvn install:install-file -Dfile="D:/Workspace/MyIdeaProjects/Dubbo-example-test/gmall-interface/target/gmall-interface-1.0-SNAPSHOT.jar" '-DgroupId=org.example' '-DartifactId=gmall-interface' '-Dversion=2.0-SNAPSHOT' '-Dpackaging=jar'
运行后可在本地仓库查看到gmall-interface,证明本地上传成功:
2、对JmeterDubboTest进行打包:mvn clean package
3、将JmeterDubboTest-1.0-SNAPSHOT.jar、gmall-interface-1.0-SNAPSHOT.jar 放置在 /jmeter的lib/ext下
步骤四:打开Jmeter,选择 TestDubboSampler,填写相关参数:userId 2 ,运行并查看结果树(注:服务端必须是可以调用成功的,意味着zookeeper、服务提供端都需要可连通)
5、python进行Dubbo接口测试
# 作者:yaxin.liang
# 日期:2022/4/22 12:49
# python版本:3
import telnetlib
import time
class DubboClient(telnetlib.Telnet):
prompt = 'dubbo'
# 通过telnet登录到dubbo服务
def __init__(self, host=None, port=20880, timeout=2000):
super().__init__(host,port)
self.write(b"\n")
# cmd命令执行 telnet语句
def executecmd(self,cmdstr):
data = self.read_until(self.prompt.encode())
self.write(cmdstr.encode() + b"\n")
return data
def req(self,service_name,method_name,params):
# 拼接方法参数
args_str = ''
for item in params:
if self.isNumber(item) or type(item).__name__ == 'dict':
args_str = args_str + str(item) + ","
else:
# args_str = args_str + "'" +item + "'" + ","
args_str = "\'{0}'".format(item)+","
# 去除掉拼接参数最后的逗号
args_str = args_str[0:len(args_str) -1]
# 拼接telnet语句
# cmdstr = "invoke {0}.{1}({2})".format(service_name, method_name, "'20211026902526655753355264',1")
cmdstr = "invoke {0}.{1}({2})".format(service_name, method_name, args_str)
# 调用cmd执行telnet命令
data = self.executecmd(cmdstr)
time.sleep(0.05)
data = self.read_until(self.prompt.encode())
# 提取返回结果
data = data.decode().replace(cmdstr,'')
# data = data.split('\n'[1].strip())
data = data.split('\r\n')[1]
return data
# 退出telnet,释放连接
def close_telnet(self):
self.write(b"exit\n")
def isNumber(self, val):
if isinstance(val,int):
return True
else:
return False
if __name__ == '__main__':
# 此处ip给出的是错误的,需要结合开发那边的ip和service、method进行测试
host_ip = '30.1.32.70'
port = '30000'
service = 'com.melot.sop.sms.api.IsvSmsService'
method = 'getTemplateConfig'
args = ['20211026902526655753355264',1]
telnet_client = DubboClient(host_ip, port)
ret = telnet_client.req(service, method, args)
print(ret)
telnet_client.close_telnet()
结果: