目录
《dubbo入门》
《dubbo管理控制台》
《dubbo超时重传》
《dubbo直连》
《dubbo实现服务降级》
dubbo入门
- 架构
dubbo-architecture.jpg
节点角色.png
调用关系说明
(1). 服务容器负责启动,加载,运行服务提供者。
(2). 服务提供者在启动时,向注册中心注册自己提供的服务。
(3). 服务消费者在启动时,向注册中心订阅自己所需的服务。
(4). 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
(5). 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
(6). 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。 -
入门例子
准备:
导包:zookeeper包、dubbo包、curator-framework包等
启动注册中心zookeeper
zk.png
功能:web层调用service层提供的查询用户是否存在的接口
dubbo-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:context="http://www.springframework.org/schema/context"
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://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="sunpy-service" />
<!-- 使用multicast广播注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="cn.spy.single.service.UserService" ref="userService" timeout="600000"/>
</beans>
spring.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<beans:import resource="classpath:spring-mybatis.xml"/>
<beans:import resource="classpath:dubbo-provider.xml"/>
<context:property-placeholder location="classpath:/config.properties" />
<context:property-placeholder location="classpath:/log4j.properties" />
<context:component-scan base-package="cn.spy"></context:component-scan>
</beans>
提供者:
public class ServiceProvider {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring.xml"});
context.start();
// 为保证服务一直开着,利用输入流的阻塞来模拟
System.in.read();
}
}
dubbo-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:context="http://www.springframework.org/schema/context"
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://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="sunpy-web" />
<!-- 使用multicast广播注册中心暴露发现服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="userService" interface="cn.spy.single.service.UserService" />
</beans>
spring.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<beans:import resource="classpath:dubbo-consumer.xml"/>
<context:property-placeholder location="classpath:/log4j.properties" />
<context:component-scan base-package="cn.spy"></context:component-scan>
消费者:
public class WebConsumer {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring.xml"});
context.start();
UserService userService = (UserService) context.getBean("userService"); // 获取远程服务代理
User user = userService.selectUser("zhangjl01");
System.out.println(user); // 显示调用结果
}
}
结果:

dubbo管理控制台
- 确保成功安装JDK
[root@izuf6ea4rfo45y44oj74jhz WEB-INF]# java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
- 确保成功安装zookeeper
我使用的是在三台机器上的zookeeper集群功能,所以确保zookeeper集群没问题。
[root@izuf6ea4rfo45y44oj74jhz bin]# ./zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/zookeeper/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
[root@izbp1a2dsv8lw7ik396vokz bin]# ./zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /sunpy/zookeeper/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader
[root@instance-2gak1pfv bin]# ./zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/sunpy/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
- 确保安装了tomcat
[root@izuf6ea4rfo45y44oj74jhz bin]# ps -ef|grep tomcat
root 416 32683 0 22:43 pts/2 00:00:00 grep --color=auto tomcat
root 32760 1 3 22:28 pts/2 00:00:29 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/bin/java -Djava.util.logging.config.file=/home/tomcat/apache-tomcat-8.5.35/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /home/tomcat/apache-tomcat-8.5.35/bin/bootstrap.jar:/home/tomcat/apache-tomcat-8.5.35/bin/tomcat-juli.jar -Dcatalina.base=/home/tomcat/apache-tomcat-8.5.35 -Dcatalina.home=/home/tomcat/apache-tomcat-8.5.35 -Djava.io.tmpdir=/home/tomcat/apache-tomcat-8.5.35/temp org.apache.catalina.startup.Bootstrap start
- 下载dubbo管理控制台
链接:https://pan.baidu.com/s/1ggeIIHX 密码:ck4h - 解压放到tomcat的webapps下
配置dubbo-admin-2.6.0/WEB-INF/dubbo.properties
dubbo.registry.address=zookeeper://ip1:2181?backup=ip2:2181,ip3:2181
dubbo.admin.root.password=sunpy
dubbo.admin.guest.password=sunpy

- 本地启动应用向zookeeper集群注册服务
本地dubbo应用配置zookeeper集群(消费者和提供者)
<dubbo:registry protocol="zookeeper" address="ip1:2181,ip2:2181,ip3:2181"/>
-
启动本地应用
start.png
-
通过管理控制台查看应用和服务
应用服务.png
dubbo超时重传问题
- 场景
今天单元测试时,发现新增的一条记录插入了两次,多亏写了业务校验,要不然数据库平白无故多了一条记录。 - 查看dubbo文档
http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-provider.html
timeout
远程服务调用超时时间,默认值为1000毫秒。
retries
远程服务调用重试次数,不包括第一次调用,默认值为2次。 - 解决办法
将timeout时间调大,retries重传次数改为0就解决问题(注意:对于接口中写方法必须控制重传次数为0,防止出现多条重复记录)。
- 额外的总结
问题:
单元测试还发现,dubbo参数验证异常,但是项目却没有捕获到,也没有发现日志。
思路:
经过排查发现,业务代码专门捕获自定义异常,记录了自定义异常的日志,而没有捕获dubbo参数验证异常。
总结:
对于异常处理,既不要吞噬异常,更不要抛弃异常。
dubbo直连
- 配置dubbo直连
<?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:context="http://www.springframework.org/schema/context"
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://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="demo-web" />
<!-- 使用multicast广播注册中心暴露发现服务地址 -->
<dubbo:registry group="sunpy" protocol="zookeeper" address="zookeeper://106.15.95.37:2181?backup=47.99.197.133:2181,106.12.42.149:2181"/>
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="userService" interface="cn.spy.single.service.UserService" url="dubbo://106.15.95.37:20880"/>
</beans>
- 测试
删除注册中心zookeeper中注册的节点/sunpy信息,让其直接引用调用者
[zk: localhost:2181(CONNECTED) 0] ls /
[cluster, controller, controller_epoch, brokers, zookeeper, admin, isr_change_notification, consumers, log_dir_event_notification, latest_producer_id_block, config]
dubbo控制台:

没有设置直连测试结果:
Caused by: java.lang.IllegalStateException: Failed to check the status of the service cn.spy.single.service.UserService. No provider available for the service cn.spy.single.service.UserService from the url zookeeper://106.15.95.37:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-web&dubbo=2.6.2&interface=cn.spy.single.service.UserService&methods=selectUser&pid=7184®ister.ip=192.168.0.103&side=consumer×tamp=1554303504905 to the consumer 192.168.0.103 use dubbo version 2.6.2
at com.alibaba.dubbo.config.ReferenceConfig.createProxy(ReferenceConfig.java:422)
at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:333)
at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163)
at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:66)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:144)
测试代码:
public class WebConsumer {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring.xml"});
context.start();
UserService userService = (UserService) context.getBean("userService");
UserQuery hq = new UserQuery();
hq.setName("def982");
List<User> userList = userService.selectUser(hq);
if (!CollectionUtils.isEmpty(userList)) {
for (User user : userList) {
System.out.println(user);
}
}
}
}
结果:

dubbo实现服务降级
- 什么是服务降级
服务降级就是当服务器压力剧增的条件下,根据当前的业务情况及流量对一些服务和页面有策略地进行降级,主要以释放服务器资源保证核心任务的正常运行。 - dubbo实现服务降级的策略
dubbo使用mock配置实现服务降级。
(1)第一种:配置boolean值,默认为false。如果配置为true,那么默认采用类名+Mock后缀。
(2)第二种:配置为return null(忽略异常)。 - 用法
<dubbo:reference id="userService" interface="cn.spy.single.service.UserService" timeout="3000" mock="true"/>
- 在api包中实现UserServiceMock完成自定义的提示
public class UserServiceMock implements UserService {
@Override
public List<User> selectUser(UserQuery query) throws Exception {
System.out.println("进入UserServiceMock...");
return new ArrayList<User>();
}
}
- 模拟超时(让当前线程等待)
@Service("userService")
public class UserServiceImpl extends BaseService implements UserService{
@Resource
private UserMapper userMapper;
public List<User> selectUser(UserQuery query) throws Exception {
Thread.sleep(1000*60*24);
return userMapper.selectByName(query);
}
}
结果:

网友评论