Dubbox注解开发详细教程
问题描述:
1,dubbox开发环境是如何搭建的?
2,dubbox 注解开发使用如何使用的?
3,dubbox注解开发之服务超时?
4,dubbox 注解开发之集群失败重试?
5,dubbox注解之高效序列化?
6,dubbox 注解开发之集群负载均衡?
第1章 Dubbox开发环境搭建
1.1 Dubbox下载
dubbx是当当网对原阿里dubbo2.x的升级,并且兼容原有的dubbox。其中升级了zookeeper和spring版本,并且支持restfull风格的远程调用。
dubbox git地址: https://github.com/dangdangdotcom/dubbox
1.2 Dubbox源码编译
下载完毕dubbox源码以后,需要在项目中引入dubbox相关的包文件,此时需要把源码进行编译打包部署到仓库中.
运行maven命令:mvn clean install -Dmaven.test.skip=true
将dubbox的源码打包发布到本地仓库,目的是为了获取:
dubbo-admin-2.8.4.war和dubbo-monitor.war以及相关的dubbox依赖jar包.
1.3 项目依赖
下面的坐标依赖仅仅是项目kryo,jackson序列化优化所需的坐标,项目需要依赖的spring,dubbox集群负载及其他的坐标,自行导入即可.
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.4</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.7</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!-- kryo序列化 -->
<dependency>
<groupId>com.esotericsoftware.kryo</groupId>
<artifactId>kryo</artifactId>
<version>2.24.0</version>
</dependency>
<dependency>
<groupId>de.javakaffee</groupId>
<artifactId>kryo-serializers</artifactId>
<version>0.42</version>
</dependency>
<!-- Jackson序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version> 3.0.7.Final</version>
</dependency>
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.33</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-core</artifactId>
<version>2.6.1</version>
</dependency>
1.4 发布服务
项目发布服务使用批量扫描的方式进行服务器注册.
<dubbo:applicationname="demo-service" />
<dubbo:protocol name="dubbo"port="20880"/>
<dubbo:registry address="zookeeper://192.168.66.66:2181"/>
<!-- 发布服务 -->
<dubbo:annotation package="cn.it"/>
1.5 服务消费
服务消息者也使用批量扫描的方法,引入服务对象.
<!-- 引用dubbo 服务 -->
<dubbo:application name="demo-web"/>
<dubbo:registry address="zookeeper://192.168.66.66:2181"/>
<!-- 引用服务 -->
<dubbo:annotation package="cn.it"/>
dubbox在发布服务和消费服务和dubbo并没有什么本质的变化,但是主要是在一些细节方面有些小的变化,下面在dubbox优化方面来说明他的变化。
1.6 服务测试
1.6.1 项目结构
Service服务提供者,web层服务消费者.interface是发布服务及依赖服务的关键.
1.6.1 启动测试
测试前提是你的linux中zookeeper服务器已经安装成功,此时测试使用的zookeeper注册中心模式来注册服务对象.
第2章 Dubbox注解开发使用
2.1 服务提供者
使用dubbox提供的注解开发结合配置文件dubbox扫描配置,把service服务对象发布到zookeeper注册中心即可.dubbox通过Service注解即可实现服务注册,但是必须注意service直接必须使用dubbox提供的注解.
importcom.alibaba.dubbo.config.annotation.Service;
@Service
public class DemoServiceImpl implements DemoService {
public String findAll(){
String str = "welcome to me!";
return str;
}
}
2.2 服务消费者
服务表现层消费者使用@Reference这个注解来直接引用服务层服务,此注解由dubbox提供.
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.PathVariable;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;
import cn.it.DemoService;
importcom.alibaba.dubbo.config.annotation.Reference;
@Controller
public class DemoController {
@Reference//引入服务
private DemoServicedemoService;
@RequestMapping("/demo/rest/{name}")
@ResponseBody
public String rest(@PathVariable String name){
String str = demoService.findAll();
return str+":"+name;
}
}
第3章 Dubbox性能优化实战
为了更好了解dubbox做了什么优化,及dubbox在项目应用中我们需要做什么优化,提高项目的性能,因此做了一下的测试.
3.1 性能测试
3.1.1 测试环境
· 两台独立服务器
· 4核Intel(R) Xeon(R) CPU E5-2603 0 @1.80GHz
· 8G内存
· 服务器之间网络通过百兆交换机
· CentOS5
· JDK7
· Tomcat7
· JVM参数-server -Xms1g -Xmx1g -XX:PermSize=64M-XX:+UseConcMarkSweepGC
3.1.2 测试脚本
和dubbo自身的基准测试保持接近:
10个并发客户端持续不断发出请求:
· 传入嵌套复杂对象(但单个数据量很小),不做任何处理,原样返回
· 传入50K字符串,不做任何处理,原样返回(TODO:结果尚未列出)
进行5分钟性能测试。(引用dubbo自身测试的考虑:“主要考察序列化和网络IO的性能,因此服务端无任何业务逻辑。取10并发是考虑到http协议在高并发下对CPU的使用率较高可能会先打到瓶颈。”)
3.1.3 测试结果
下面的结果主要对比的是REST和dubbo RPC两种远程调用方式,并对它们作不同的配置,例如:
· “REST: Jetty+XML+GZIP”的意思是:测试REST,并采用jetty server,XML数据格式,启用GZIP压缩。
· “Dubbo: hessian2”的意思是:测试dubbo RPC,并采用hessian2序列化方式。
针对复杂对象的结果如下(响应时间越小越好,TPS越大越好):
远程调用方式 | 平均响应时间 | 平均TPS(每秒事务数) |
REST: Jetty + JSON | 7.806 | 1280 |
REST: Jetty + JSON + GZIP | TODO | TODO |
REST: Jetty + XML | TODO | TODO |
REST: Jetty + XML + GZIP | TODO | TODO |
REST: Tomcat + JSON | 2.082 | 4796 |
REST: Netty + JSON | 2.182 | 4576 |
Dubbo: FST | 1.211 | 8244 |
Dubbo: kyro | 1.182 | 8444 |
Dubbo: dubbo serialization | 1.43 | 6982 |
Dubbo: hessian2 | 1.49 | 6701 |
Dubbo: fastjson | 1.572 | 6352 |
仅就目前的结果,一点简单总结:
1)dubbo RPC(特别是基于高效java序列化方式如kryo,fst)比REST的响应时间和吞吐量都有较显著优势,内网的dubbo系统之间优先选择dubbo RPC。
2)在 REST的实现选择上,仅就性能而言,目前tomcat7和netty最优(当然目前使用的jetty和netty版本都较低)。tjws和sunhttp server在性能测试中表现极差,平均响应时间超过200ms,平均tps只有50左右(为了避免影响图片效果,没在上面列出)。
3)在REST中JSON数据格式性能优于XML(数据暂未在以上列出)。
4)在REST中启用GZIP对企业内网中的小数据量复杂对象帮助不大,性能反而有下降(数据暂未在以上列出)。
根据以上测试结果,对dubbox发布服务以及消费服务做出以下优化。
平均响应时间:
3.2 Dubbox注解之超时
服务超时主要是指服务消费者给服务提供者发送请求,服务提供者迟迟没有回应,超过表现层预期访问的时间,那么表现层服务任务服务超时,就会抛出异常错误.
那么为了防止过快的服务超时,保持一个长连接,因此需要修改超时设置.
@Controller
public class DemoController {
@Reference(timeout=100000) //超时时间为100000ms
private DemoServicedemoService;
@RequestMapping("/demo/rest/{name}")
@ResponseBody
public String rest(@PathVariable String name){
String str = demoService.findAll();
return str+":"+name;
}
}
3.3 Dubbox注解之失败重试
服务失败自动切换,当出现失败,重试其它服务器 。通常用于读操作,但重试会带来更长延迟
可通过 retries="2" 来设置重试次数
表现层设置服务重试
@Controller
public class DemoController {
@Reference(timeout=100000,retries=2)//对所有的service方法都起作用
private DemoServicedemoService;
@RequestMapping("/demo/rest/{name}")
@ResponseBody
public String rest(@PathVariable String name){
String str = demoService.findAll();
return str+":"+name;
}}
服务层设置失败重试:
@Service(retries=2)
public class DemoServiceImpl implements DemoService {
public String findAll(){
String str = "welcome to me!";
return str;
}
}
3.4 Dubbox注解之序列化
从上面性能测试即可看出,dubbox序列化有多种方式,其中kryo序列化是最高效的一种序列化方式.
3.4.1 Kryo序列化实现
<dubbo:applicationname="demo-service"/>
<dubbo:protocolname="dubbo"serialization="kryo"port="20880"/>
<dubbo:registryaddress="zookeeper://192.168.66.66:2181"/>
<!-- 发布服务 -->
<dubbo:annotationpackage="cn.it"/>
必须注意,以上kryo序列化必须在相关坐标依赖的情况下才能进行正确的执行.
3.4.2 Jackson序列化
<dubbo:applicationname="demo-service"/>
<dubbo:protocolname="dubbo"serialization="jackson"port="20880"/>
<dubbo:registryaddress="zookeeper://192.168.66.66:2181"/>
<!-- 发布服务 -->
<dubbo:annotationpackage="cn.it"/>
因此我们发现dubbox高效率的序列化实现非常简单,只需要在dubboprotocol中配置serialization即可实现.
3.5 Dubbox注解开发之集群
3.5.1 负载均衡依赖坐标
Dubbox实现集群配置,必须导入dubbox集群坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-cluster</artifactId>
<version>2.8.4</version>
</dependency>
3.5.2 负载均衡测试服务器
准备3台tomcat服务器,一台表现层服务器,2台服务层服务器,提供负载均衡测试
配置tomcat服务器权限,使用tomcat热部署,必须先配置tomcat权限:
权限配置完毕后,启动所有的tomcat服务器.
3.5.3 服务热部署
配置服务tomcat插件热部署地址.
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 指定端口 -->
<port>8080</port>
<!-- 请求路径 -->
<path>/</path>
<!-- 部署地址 -->
<url>http://192.168.66.66:9001/manager/text</url>
<username>tomcat</username>
<password>tomcat</password>
</configuration>
</plugin>
执行tomcat插件命令即可实现把项目部署到tomcat服务器ROOT目录下:
命令:tomcat:redeploy
3.5.4 集群负载配置
在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用
l Random LoadBalance
Ø 随机,按权重设置随机概率。
Ø 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较
均匀,有利于动态调整提供者权重。
Ø 配置案例
@Service(loadbalance="random",retries=2)//此配置为默认负载策略,可以不配置
public class DemoServiceImpl implements DemoService {
public String findAll(){
String str = "welcome to me!";
return str;
}
}
l RoundRobin LoadBalance
Ø 轮循,按公约后的权重设置轮循比率。
Ø 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台
时就卡在那,久而久之,所有请求都卡在调到第二台上。
Ø 配置案例:
@Service(loadbalance="roundrobin",retries=2)
public class DemoServiceImpl implements DemoService {
public String findAll(){
String str = "welcome to me!";
return str;
}
}
l LeastActive LoadBalance
Ø 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
Ø 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
Ø 配置案例:
@Service(loadbalance="leastactive",retries=2)
public class DemoServiceImpl implements DemoService {
public String findAll(){
String str = "welcome to me!";
return str;
}
}
l ConsistentHash LoadBalance
Ø 一致性 Hash,相同参数的请求总是发到同一提供者。
Ø 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,
不会引起剧烈变动。
Ø 配置案例:
@Service(loadbalance="consistenthash",retries=2)
public class DemoServiceImpl implements DemoService {
public String findAll(){
String str = "welcome to me!";
return str;
}
}
更多资源: 请关注微信公众号: IT核心资源分享(100T高清架构师资源共享)