Dubbo和Zookeeper

1|0一. 上节回顾


1. 监控的场景,不推荐LoadRunner自带的监控,使用nmon来监控我们的Linux系统

2. nmon + 分析思路,最后定位到性能问题(mysql数据库的用户表没有加索引导致的性能问题)

3. 生成LoadRunner自带的分析报告,生成了数据的监控,关注TPS和响应时间

2|0二. Dubbo简介


1. Dubbo是什么?

Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案

 

其核心部分包括:

(1) 远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,已经"请求--响应"模式的信息交换方式

(2) 集群容错:提供基于接口方法的透明化远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持

(3) 自动发现:基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使服务提供方可以平滑增加或减少机器

 

2. Dubbo能做什么?

(1) 远程方法调用,只需简单配置,没有任何API接入

(2) 软负载均衡以及容错机制,可以在内网替代F5等硬件负载均衡

(3) 服务自动注册与发现,不需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且平滑增加或减少机器

(4) Dubbo采用全spring配置方式

 

3. Dubbo模型

 

 

Provider:暴露服务的服务提供方

Consumer:调用远程服务的服务消费方

Registry:服务注册于发现的注册中心

Monitor:统计服务的调用次数和调用时间的监控中心

Container:服务运行容器

 

0:服务容器负责启动,加载,运行服务提供者

1:服务提供者在启动时,向注册中心注册自己提供的服务

2:服务消费者在启动时,向注册中心订阅自己所需的服务

3:注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者

4:服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调研,如果调用失败,再选另一台调用

5:服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

 

3|0三. Zookeeper简介


1. 什么是Zookeeper?

Zookeeper作为Dubbo服务的注册中心,是一个分布式的服务框架,是树型的目录服务的数据存储,能够做到集群管理数据

Dubbo能与Zookeeper做到集群部署

 

2. Zookeeper的安装

(1) 下载

在/opt目录下,# wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz

(2) 解压

# tar -zxvf zookeeper-3.4.14.tar.gz

(3) 配置环境变量

# vim /etc/profile

export ZK_HOME=/opt/zookeeper-3.4.14

export PATH=$$PATH:$ZK_HOME/bin

使环境变量生效:# source /etc/profile

(4) 新建data,logs目录

# cd zookeeper-3.4.14

# mkdir data, logs

(5) 修改编辑配置文件

# cd zookeeper-3.4.14/conf

拷贝zoo_sample.cfg并重命名为zoo.cfg

# cp zoo_sample.cfg zoo.cfg

# vim zoo.cfg

 

dataLogDir=/opt/zookeeper-3.4.14/logs

dataDir=/opt/zookeeper-3.4.14/data

我们使用的是单点模式, 所以配置server.1=192.168.0.105:3888

server.1=192.168.0.105:3888

(6) 启动Zookeeper服务

# cd bin

# ./zkServer.sh start

查看服务的状态

# ./zkServer.sh status

也可以通过查看Zookeeper端口2181,验证是否启动

# netstat -anp | grep 2181

(7) 连接到Zookeeper服务

# ./zkCli.sh -server localhost

[zk: localhost(CONNECTED) 0] ls /

[dubbo, zookeeper]

 

4|0四. 开发Dubbo接口


1. 搭建Dubbo服务提供者(这个不需要我们必须掌握,以后开发会有,了解下就可以了)

(1) 新建服务提供者的maven工程:dubbo_pertest_provider

(2) 新建包com.pertest.server

(3) 在server包下新建一个接口类ServerToClient

package com.pertest.server; public interface ServiceToClient { /* 定义一个发短信的接口 @param mobile:手机号 @param content:内容 @param platform:平台,分别对应LIANTONG, YIDONG, DIANXIN @return 正常返回发送成功、失败。这里为了显示发送的手机号和平台内容,直接 */ String sendSMS(String mobile, String content, String platform); }
ServiceToClient.java

(4) 新建包com.pertest.server.impl,在impl包下新建一个接口实现类SMSServerImpl

package com.pertest.server.impl; import com.pertest.server.ServiceToClient; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; @Service //这个注释是暴露给消费者使用 @Component public class SMSServiceImpl implements ServiceToClient { public String sendSMS (String mobile, String content, String platform) { try { Thread.sleep(3000); return String.format("发送结果: %s, 手机号码: %s, 内容: %s, 平台%s", "SUCCESS", mobile, content, platform); } catch (InterruptedException e) { e.printStackTrace(); } return null; } }
SMSServiceImpl.java

(5) 在resources下创建配置文件applicationProvider.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 "> <!--应用名称--> <dubbo:application name="hello-world" /> <!-- 注册地址 --> <dubbo:registry address="192.168.0.105:2181" protocol="zookeeper"/> <!-- 用dubbo协议在28080端口暴露服务 --> <dubbo:protocol name="dubbo" port="28080"/> <!-- 接口的位置 --> <dubbo:service interface="com.pertest.server.ServiceToClient" ref="demoService" executes="10" /> <!-- 实现bean,客户端应用的bean就以这个id名称为主 --> <bean id="demoService" class="com.pertest.server.impl.SMSServiceImpl" /> </beans>
applicationProvider.xml

创建日志配置文件log4j2.xml

<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> </Console> </Appenders> <Loggers> <Logger name="com.opensymphony.xwork2" level="info"/> <Logger name="org.apache.struts2" level="info"/> <Logger name="org.demo.rest" level="debug"/> <Root level="info"> <AppenderRef ref="STDOUT"/> </Root> </Loggers> </Configuration>
log4j2.xml

(6) 新建com.pertest.main包,在此包下新建执行类MyMainPertest

package com.pertest.main; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyMainPertest { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationProvider.xml"}); context.start(); System.out.println("按任意键退出"); System.in.read(); } }
View Code

运行main方法,测试一下,如果能看到控制台打印:按任意键退出,说明服务已经运行成功了

2. 搭建客户端(这个是必须要掌握的)

(1) 为什么需要java request?

不是所有接口都是HTTP协议(比如RPC底层调用,thrift协议),Dubbo协议或者thrift协议都有需要我们自己定制化开发jar包,jmeter只是一个封装好的工具

(2) java request是什么?

a. 纯java程序,实现了jmeter中提供接口Javasamplerclient

b. 将java程序集成到jmeter中,通过java request实现调用

c. java程序实现与压测目标的交互

d. jmeter控制java程序的生命周期、并发调度、收集结果报告等处理

(3) java request优势VS我们自己的短板

优势:

a. 自己写程序,流程控制比较灵活

b. 只要java程序可以实现的,就能够支持

(4) 编写客户端的步骤

a. 创建客户端工程dubbo_pertest_customer(这里新建的工程是和dubbo_pertest_provider并列的,在同一个window打开)

b. 在客户端代码里需要使用到服务端的jar包,在pom.xl里面需要这样引入

<!--继承提供者的jar包--> <dependencies> <dependency> <groupId>com.lemon.org</groupId> <artifactId>dubbo_pertest_provider</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
View Code

c. 我们需要和jmeter交互,因此要继承jmeter里面的接口方法,需要jmeter的一些jar包。由于客户端pom.xml依赖了服务端的jar包,所以我们将jmeter的jar包的依赖写在服务端的pom.xml中

<!-- https://mvnrepository.com/artifact/org.apache.jmeter/ApacheJMeter_java --> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_java</artifactId> <version>5.0</version> <exclusions> <exclusion> <artifactId>quartz</artifactId> <groupId>org.quartz-scheduler</groupId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.jmeter/ApacheJMeter_core --> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_core</artifactId> <version>5.0</version> </dependency>
pom.xml

d. 需要一个测试方法,看能不能调用服务端,进行信息返回:在src.main.java包下新建一个客户端类CustomerApplicationTests,在里面加入测试方法GetStringTest

//写一个测试方法 public static String GetStringTest(String mobile, String content, String platform) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"customer.xml"}); context.start(); ServiceToClient serviceToClient = (ServiceToClient) context.getBean("demoService"); String result = serviceToClient.sendSMS(mobile, content, platform); return result; }
View Code

调用这个测试方法,运行查看结果

public static void main(String[] args) { String mobile = "13524015547"; String content = "test dubbo"; String platform = "phone"; String result = GetStringTest(mobile, content, platform); System.out.println(result); }
View Code

e. 通过上面的调用,说明服务端已经可以使用了,怎么来改造jmeter的jar?

我们需要继承jmeter提供的抽象类AbstractJavaSamplerClient,这个类里面有setupTest,teardownTest,getDefaultParameters方法,而它实现了JavaSamplerClient类,这个类里runTest方法

f. getDefaultParameters方法为参数化内容,可以在jmeter的界面上显示出来要输入哪些参数,如果返回为null,则不显示

//此方法为参数化内容,可以在GUI模式下显示,如果返回为null,则不显示 @Override public Arguments getDefaultParameters() { Arguments params = new Arguments(); //参数化名字,自定义 params.addArgument("mobile", ""); params.addArgument("content", ""); params.addArgument("platform", ""); return params; }
View Code

g. 执行初始化内容,每个线程执行一次,通常建议再该方法中获取参数值,而不是在RunTest方法中使用,以便尽可能减少测试开销

// 执行初始化内容,每个线程执行一次,通常建议在该方法中获取参数值,而不是RunTest方法中使用,以便尽可能减少测试开销 public void setupTest(JavaSamplerContext context){ mobile = context.getParameter("mobile"); content = context.getParameter("content"); platform = context.getParameter("platform"); }
View Code

h. 每次执行的内容部分

//每次需要执行的内容部分 public SampleResult runTest(JavaSamplerContext context) { SampleResult sr = new SampleResult(); //在查看结果树里面显示的名称 sr.setSampleLabel("JmeterDubboTest"); //事务开始,开始计算时间 sr.sampleStart(); try { //调用java接口 String result = GetStringTest(mobile, content, platform); //输入方法的结果 sr.setResponseData("From dubbo provider back result: "+ result,null); //输入结果保存内容 sr.setDataType(SampleResult.TEXT); //在jmeter控制台终端显示 System.out.println(result); //设置测试结果为true sr.setSuccessful(true); } catch (Throwable e) { sr.setSuccessful(false); } finally { //事务的结束 sr.sampleEnd(); } return sr; }
View Code

i. 在测试运行结束时进行本次测试所需的清理工作,也是一个线程执行一次

// 在测试运行结束时进行本次测试所需的清理工作,也是一个线程执行一次 public void teardownTest(JavaSamplerContext context) { }
View Code

j. 在resources下编写客户端的配置文件customer.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 "> <!--应用名称--> <dubbo:application name="hello-world" /> <!-- 注册地址 --> <dubbo:registry address="192.168.0.105:2181" protocol="zookeeper"/> <!-- 用dubbo协议在28080端口暴露服务 --> <dubbo:protocol name="dubbo" port="28080"/> <!-- 接口的位置 --> <dubbo:service interface="com.pertest.server.ServiceToClient" ref="demoService" executes="10" /> <!-- 实现bean,客户端应用的bean就以这个id名称为主 --> <bean id="demoService" class="com.pertest.server.impl.SMSServiceImpl" /> </beans>
customer.xml

客户端的log4j2.xml

<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> </Console> </Appenders> <Loggers> <Logger name="com.opensymphony.xwork2" level="info"/> <Logger name="org.apache.struts2" level="info"/> <Logger name="org.demo.rest" level="debug"/> <Root level="info"> <AppenderRef ref="STDOUT"/> </Root> </Loggers> </Configuration>
log4j2.xml

3. 将客户端打包成jar包

注意:客户端的pom.xml中还需要加入bulid相关的依赖,否则构建出来的jar包会有问题

<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.fxc.rpc.impl.member.MemberProvider</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
pom.xml

点击右侧Maven,在对应的工程名下的Lifecycle中,点击install可以打成jar包

4. 在jmeter中调用dubbo接口

将jar包拷贝到jmeter的lib/ext目录下,重启jmeter

新建一个Java Request取样器,输入参数后运行

查看结果树

 


__EOF__

本文作者cnhkzyy
本文链接https://www.cnblogs.com/my_captain/p/12661041.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cnhkzyy  阅读(417)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示