Dubbo接口测试学习笔记
-
关于dubbo:
-
- why:
-
- 为了解决,随着互联网发展,而日益增长的业务复杂度,网站应用规模不断扩大,且常规的垂直应用架构也无法应付前提下,提出的解决方案.
- 架构发展角度:
-
- 单一应用架构
-
- 网站流量很小时,将所有功能都部署在一个应用,节省部署节点和成本.此时,重点是简化增删改查工作量的数据访问框架ORM(图源https://www.jianshu.com/p/92ca0bfbd52f)
- 单体架构相关资料:
-
- 单体架构指应用代码都作为同一个进程,部署和运行在单一节点中.
-
- 单一节点服务器中,整体中的所有的模块都组装到单一的内存镜像中,作为一个进程运行在单一节点上.
- 其中,如果将应用程序部署到多个服务器(如在水平扩展上下文中),它仍然是一个整体。
- https://herbertograca.com/2017/07/31/monolithic-architecture/
- https://sunnycoding.cn/2018/07/28/monolithic-and-microservices-part1/
- https://microservices.io/patterns/monolithic.html
- 垂直应用架构
-
- 访问量逐渐增大,单一应用增加机器(通过在负载均衡器后端运行多个拷贝,实现多个扩展)带来的加速度越来越小,于是需要将应用拆成互不相干的几个应用来提升效率,此时的重点是用于加速前端页面开发的Web框架(MVC).
- 分布式服务架构
-
- 为了应对增长的业务量,一台机器的性能已经无法满足,需要多台机器才能应对大规模的应用场景,同时也为了提高整个系统架构的可用性,消除单点故障,而垂直或水平拆分业务系统为多个应用.
- 当垂直应用越来越多,应用之间需要交互,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求.此时,重点是解决进程间通信问题和提高业务复用及整合的分布式服务框架RPC.
- 流动计算架构
-
- 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需要增加一个调度中心基于访问实时管理集群容量,提高集群利用率.此时,重点是提高机器利用率的资源调度和治理中心SOA.
- 在大规模服务化之前,应用可能只是通过 RMI 或 Hessian 等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过 F5 等硬件进行负载均衡。当服务越来越多时,服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。
-
- 需要服务调用方能自动感知到服务提供方的地址,而对服务提供方进行横向扩展的时候,服务调用方能自动感知到
- 因此需要一个服务注册中心,动态地注册和发现服务, 通过消费方获取服务提供方地址列表,实现软负载均衡和 Failover,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。
- 解决清晰描述错综复杂的服务依赖关系的问题
- 服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器? 为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阈值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
- what:
-
- 一个远程服务调用的分布式框架,调用协议通常包含传输协议和序列化协议。
- Dubbo本身支持多种远程调用方式,例如Dubbo RPC(二进制序列化 + tcp协议)、http invoker(二进制序列化 + http协议)、hessian(二进制序列化 + http协议)、WebServices (文本序列化 + http协议)等。
- 架构说明:
-
- 官网介绍地址
- 节点角色说明
节点 角色说明 Provider 暴露服务的服务提供方 Consumer 调用远程服务的服务消费方 Registry 服务注册与发现的注册中心 Monitor 统计服务的调用次数和调用时间的监控中心 Container 服务运行容器 -
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
-
管理控制台的编译安装:
-
- 新版管理控制台主要的作用:服务查询,服务治理(包括Dubbo2.7中新增的治理规则)以及服务测试、配置管理
- 步骤:
# 克隆项目到本地,并编译安装和启动(如果是Windows下,则在powershell进行) git clone https://github.com/apache/incubator-dubbo-ops.git # 切到项目根目录 cd incubator-dubbo-admin-develop # 编译构建 mvn clean package # 修改配置文件,指定注册中心地址 dubbo-admin-server/src/main/resources/application-production.properties # 主要的配置有: admin.config-center=zookeeper://127.0.0.1:2181 admin.registry.address=zookeeper://127.0.0.1:2181 admin.metadata-report.address=zookeeper://127.0.0.1:2181 # 启动服务 cd dubbo-distribution/target java -jar dubbo-admin-0.1.jar # 或以下命令启动服务 mvn --projects dubbo-admin-server spring-boot:run 启动完成后,直接访问http://localhost:8080
-
-
- 如何测试dubbo接口:
- Python :
- hessian+http的方式调用(python-hessian库):
- Python :
- 如何测试dubbo接口:
1、dubbo项目中,增加hessian方式序列化,及相关依赖。下图为xml配置方式示例。
2、获取接口地址(可在管理台查看)、方法及方法的入参。
3、安装 python-hessian
python -m pip install python-hessian
4、编写Python脚本调用接口 (参考:pyhessian官方调用例子)
# coding=utf-8 import pytest from pyhessian.client import HessianProxy class TestDubbo(object): url = "http://169.254.210.145:1234/" interface = "com.xxx.user.service.UserService" full_url = url + interface # full_url = "http://169.254.210.145:8888/com.xxx.user.service.FileService" def testsayHelloWithSpec(self): params = u"什么我调用成功了吗" # 创建连接对象 service = HessianProxy(self.full_url) # 重载方法__call()__里发送二进制数据进行请求,调用方法 res = service.sayHello(params) assert "什么我调用成功了吗" in res print(res) # @pytest.mark.skip() def testsayHelloWithInt(self): params = 123 service = HessianProxy(self.full_url) res = service.sayHello(params) assert 123 in res print(res) if __name__ == "__main__": pytest.main(["-q","TestDubbo.py"])
- 使用dubbo-client:
- dubbo项目中,provicer.xml增加jsonrpc协议
- 官方地址:https://github.com/dubbo/dubbo-client-py
config = ApplicationConfig('test_rpclib') service_interface = 'com.ofpay.demo.api.UserProvider' #Contains a connection to zookeeper, which needs caching. registry = ZookeeperRegistry('192.168.59.103:2181', config) user_provider = DubboClient(service_interface, registry, version='1.0') for i in range(1000): try: print user_provider.getUser('A003') print user_provider.queryUser( {u'age': 18, u'time': 1428463514153, u'sex': u'MAN', u'id': u'A003', u'name': u'zhangsan'}) print user_provider.queryAll() print user_provider.isLimit('MAN', 'Joe') print user_provider('getUser', 'A005') except DubboClientError, client_error: print client_error time.sleep(5)
- java:
-
- XML配置文件方式:
- 拿到服务的jar包或maven依赖
- 在resources下创建consumer.xml,配置好注册中心地址,接口名全称(有包名限定),每个接口有其唯一的标识reference id
- 调用测试方法中,使用springframework提供的方法加载consumer.xml配置文件,得到context对象,调用start方法启动
- 调用context对象的getBean方法,传入接口标识作为实参,获取接口的具体实现对象,这步会进行远程过程调用
- 通过获取的对象调用其提供的方法
- XML配置文件方式:
1 import com.xxx.user.service.UserService; 2 import org.junit.BeforeClass; 3 import org.junit.Test; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; 6 public class ConsumerTest { 7 static ClassPathXmlApplicationContext context; 8 static UserService userService; 9 @BeforeClass 10 public static void beforeClass(){ 11 if(context==null) { 12 // 默认从类路径中加载配置文件 13 context = new ClassPathXmlApplicationContext("consumer.xml"); 14 System.out.println("load"); 15 // 在Spring中还提供了Lifecycle接口,Lifecycle中包含start/stop方法,实现此接口后Spring保证在启动的时候调用其start方法开始生命周期,主要用于控制异步处理过程 16 context.start(); 17 // System.out.println("start"); 18 } // 创建接口实例(定义接口的引用变量,再引用实现了该接口的实例) 19 userService=(UserService) context.getBean("userService"); 20 21 } 22 @Test 23 public void consumerTestCase1(){ // 调用方法 24 String hello = userService.sayHello("world"); 25 assertThat(hello,containsString("world"); 26 System.out.println(hello); 27 } 28 29 }
-
- 调用GenericService 这个接口提供的名为 $invoke方法,它接受三个参数,分别为方法名、方法参数类型数组和参数值数组;
- 对于方法参数类型数组:
- 如果是基本类型,如 int 或 long,可以使用 int.class.getName()获取其类型;
- 如果是基本类型数组,如 int[],则可以使用 int[].class.getName();
- 如果是 POJO,则直接使用全类名,如 com.alibaba.dubbo.samples.generic.api.Params。
- 参数值数组:
- 如果是POJO,则转成Map,再将转换后的Map作为参数传入
- 对于方法参数类型数组:
- 调用GenericService 这个接口提供的名为 $invoke方法,它接受三个参数,分别为方法名、方法参数类型数组和参数值数组;
1 @Test 2 public void test2(){ 3 ApplicationConfig application = new ApplicationConfig(); 4 application.setName("api-generic-consumer"); 5 # 使用RegistryConfig,动态配置注册中心地址 6 RegistryConfig registry = new RegistryConfig(); 7 registry.setAddress("zookeeper://127.0.0.1:2181"); 8 application.setRegistry(registry); 9 10 ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); 11 // 弱类型接口名 12 reference.setInterface("com.ymxdclass.user.service.UserService"); 13 // 声明为泛化接口 14 reference.setGeneric(true); 15 16 reference.setApplication(application); 17 18 // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用 19 GenericService genericService = reference.get(); 20 21 String name = (String) genericService.$invoke("sayHello", new String[]{String.class.getName()}, new Object[]{"who am i"}); 22 System.out.println(name); 23 }