当前系统是使用 spring boot + spring cloud feign 作为系统间的调用。使用 amazon 的 aws 的负载均衡调用。不能够做到服务调用的治理以及监控。基于以上缺点所以决定引用 dubbo 来做服务间的调用。
1、Why Dubbo
比较流行的有 spring cloud 和 dubbo,为什么选择 dubbo。
功能特性
Spring Cloud Netfix
Apache Dubbo
分布式配置
Archaius
Nacos/Zookeeper
服务注册与发现
Eueka
Nacos/Zookeeper
服务路由
Zuul
Dubbo Proxy
服务调用
OpenFeign
Dubbo
负载均衡
Ribbon
Dubbo LB
服务熔断
Hystrix
Sentinel
分布式消息
RabbitMQ/Kafka
RocketMQ
Spring Cloud 特性比较强依赖 Netflix OSS,后者大量组件却处于维护状态,SpringCloud 的命运存在着不确定性。
2、Dubbo 架构
以下是 dubbo 的官方架构图:
dubbo 节点角色说明:
节点
角色说明
Provider
暴露服务的服务提供方
Consumer
调用远程服务的服务消费方
Registry
服务注册与发现的注册中心
Monitor
统计服务的调用次数和调用时间的监控中心
Container
服务运行容器
调用关系说明:
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
3、Provider 暴露 Dubbo 服务
3.1 引入 dubbo 依赖
引入 dubbo 需要依赖的 Jar 包。由于我们项目使用的是 Spring Boot,所以可以使用 dubbo 官方提供的 dubbo-spring-boot-starter。服务的注册中心选择使用的是 Zookeeper,所以可以直接引入 dubbo 提供的 dubbo 依赖 zookeeper 的 pom 包 就可以了。 dubbo-metadata-report-zookeeper 是把元数据报告给 zookeeper 元数据中心,以供服务治理 dubbo-admin 使用。
<!-- dubbo -->
<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-metadata-report-zookeeper</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
注意:为了让大家能够如丝般顺滑的接入 dubbo 服务。大家需要注意一下以上的 dubbo-spring-boot-starter 依赖的是 spring boot 2.x+。如果 Consumer(也就是服务接入方) 项目引用的 spring boot 1.x +。只需要在项目中最顶级 pom.xml 中引入你需要的 spring boot 版本的 spring-boot-starter-parent 版本即可。dubbo-spring-boot-starter 是兼容 spring boot 1.x 与 2.x 的版本。比如你使用的是 spring boot 1.5.6-RELEASE,只需要在项目中引入以下配置:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
3.2 配置 Dubbo Provider 信息
provider 端需要在配置文件当中配置 dubbo 服务的信息如下:
## Dubbo Config
zookeeper.address=localhost:2181
# Dubbo application
dubbo.application.name=dubbo provider service
dubbo.application.owner=carl
dubbo.application.organization=csdn
# Dubbo Protocol
dubbo.protocol.name=dubbo
dubbo.protocol.port=20881
# Dubbo Registry
dubbo.registry.address=zookeeper://${zookeeper.address}
dubbo.registry.file = ${user.home}/dubbo-cache/${dubbo.application.name}/dubbo.cache
dubbo.registry.timeout=30000
dubbo.registry.simplified=true
# Dubbo Metadata Report
dubbo.metadata-report.address=zookeeper://${zookeeper.address}
dubbo.metadata-report.cycle-report=false
# Dubbo Config Center
dubbo.config-center.address=zookeeper://${zookeeper.address}
dubbo.config-center.timeout=30000
dubbo 应用配置
dubbo 应用配置 的时候注意填写当服务名称、当前服务的应用负责人以及组织名称,这样可以达到服务治理的作用。
dubbo 协议配置
协议: dubbo 需要配置协议为 dubbo
端口: dubbo 是通过 Netty 进行 socket 暴露 Socket 服务(默认是 20880),如果本地同时暴露 2 个 dubbo 服务就会端口冲突。
dubbo 注册中心配置
注册中心: 注册中心推荐使用 zookeeper 或者 Nacos,本文使用的是 zookeeper。
注册中心缓存文件: 同时注册中心文件缓存位置的配置地址需要有可读可写权限,当 zookeeper 注册中心挂掉的时候,当前机器还可以读取文件缓存的注册中心达到高可用的目的。
dubbo 元数据中心、配置中心
配置 dubbo 元数据中心与配置中心主要是 dubbo-admin
可以获取元数据这样方便做服务测试与服务 mock。现在它们的地址一般配置与注册中心一致使用 zookeeper。
3.3 Providre 提供的服务
首先配置需要暴露 dubbo 服务需要扫描哪些包:
@EnableDubbo(scanBasePackages = "cn.carlzone.demo.service.impl")
@SpringBootApplication
public class Bootstrap {
private static final Logger log = LoggerFactory.getLogger(Bootstrap.class);
public static void main(String[] args) {
log.info("demo dubbo service started...");
SpringApplication springApplication = new SpringApplication(Bootstrap.class);
springApplication.run(args);
log.info("demo dubbo service started successful");
}
}
然后在需要暴露的服务实现类上标注 org.apache.dubbo.config.annotation.Service 注解。
import javax.annotation.Resource;
@Service
public class DemoServiceImpl implements DemoService {
@Override
public void sayHello(String name) {
System.out.println("hello, " + name);
}
}
4、接入 dubbo 服务常见异常
以下列举一下 dubbo 在接入过程中出现的常见错误及解决办法。
4.1 连接注册中心失败
异常描述:
解决方法:
1、检查 zookeeper 是否成功启动,如果没有启动注册中心需要把注册中心启动起来。
2、如果注册中心已经启动可以查看当前服务是否能够连接注册中心。
3、如果当前机器能够连接注册中心,可以设置 zookeeper 的超时时间。
# Dubbo Registry
#dubbo.registry.timeout=600000
# Dubbo Config
#dubbo.config-center.timeout=600000
4.2 端口冲突
异常描述:
解决办法:
dubbo 暴露的默认端口 28080 端口,如果你没有修改端口。然后另启动一台服务的时候发现:本地 IP + 28080 端口已经被使用了,所以就报了:Address already in use。
只需要把 dubbo 的暴露端口修改一下,也就是 dubbo.protocol.port,比如:
dubbo.protocol.port=28081
4.3 interface not allow null
异常描述:
解决办法:
这是由于你定义扫描需要暴露 Dubbo 接口 @EnableDubbo(scanBasePackages = "cn.carlzone.demo.service.impl")
需要扫描的暴露接口实现时。这个注解扫描的暴露接口包中的类它的类上标注不是 Dubbo 提供的 org.apache.dubbo.config.annotation.Service
注解而是 Spring 框架提供的 org.springframework.stereotype.Service
注解。
所以把注解修改成 Dubbo 框架提供的注解就可以解决这个问题了。
5、Consumer 接入 dubbo
5.1 引入 Provider Api Jar 包
引入 provider 提供的暴露接口的接口 Jar 包,Consumer 就可以使用 Jar 包里面提供的接口直接调用。provider 在暴露服务的时候同时也需要把 Jar 上传到 Maven 私服。
<dependency>
<groupId>cn.carlzone.dubbo</groupId>
<artifactId>dubbo-service-api</artifactId>
</dependency>
5.2 引入 dubbo 依赖
引入 dubbo 需要依赖的 Jar 包。由于我们项目使用的是 Spring Boot,所以可以使用 dubbo 官方提供的 dubbo-spring-boot-starter。服务的注册中心选择使用的是 Zookeeper。
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
同要的为了让大家能够如丝般顺滑的接入 dubbo 服务。大家需要注意一下以上的 dubbo-spring-boot-starter 依赖的是 spring boot 2.x+。如果 Consumer(也就是服务接入方) 项目引用的 spring boot 1.x +。只需要在项目中最顶级 pom.xml 中引入你需要的 spring boot 版本的 spring-boot-starter-parent 版本即可。dubbo-spring-boot-starter 是兼容 spring boot 1.x 与 2.x 的版本。比如你使用的是 spring boot 1.5.6-RELEASE,只需要在项目中引入以下配置:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
5.3 配置 Dubbo Consumer 信息
consumer 端需要在配置文件当中配置 dubbo 服务的信息如下:
## dubbo application
# 当前应用名称(你的应用名称)
dubbo.application.name=demo-service-conuser
# 应用负责人
dubbo.application.own=carl
# 组织名称
dubbo.application.organization=csdn
## dubbo registry
# 注册中心服务器地址
dubbo.registry.address=zookeeper://localhost:2181
# 使用文件缓存注册中心地址列表及服务提供者列表,应用重启时将基于此文件恢复
dubbo.registry.file=${user.home}/dubbo-cache/${dubbo.application.name}/dubbo.cache
## dubbo consumer
# 远程服务调用超时时间(毫秒)
dubbo.consumer.timeout=15000
# 远程服务调用重试次数,不包括第一次调用
dubbo.consumer.retries=0
# 检测 dubbo 服务提供者是否存在
dubbo.consumer.check=false
大家在配置的时候需要注意几点:
dubbo 应用配置
dubbo 应用配置 注意填写当服务名称、当前服务的应用负责人以及组织名称,这样可以达到服务治理的作用。
dubbo 注册中心配置
注册中心地址 这里使用是的 dubbo。
注册中心缓存文件: 同时注册中心文件缓存位置的配置地址需要有可读可写权限,当 zookeeper 注册中心挂掉的时候,当前机器还可以读取文件缓存的注册中心达到高可用的目的。
dubbo 服务调用方配置
超时时间: 服务调用方根据自己的业务场景需要配置超时时间, dubbo 默认的超时时间是 1 秒。显然有一些服务是达不到这个要求的。
重试次数: 远程服务调用的重试次数默认是 2 次(不包括第一次调用),大家可以根据业务场景来设置重试次数。
检测服务是否存在: 对于是否在启动的时候检测 dubbo 服务是否存在默认值是 true。但是建议大家都配置成 false,这样在发布的时候就可以平滑的发布。
5.4 Consumer 调用 Providre 提供的服务
@SpringBootApplicatoin
public class ConsumerBootstrap {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Reference
private DemoService demoService;
public static void main(String[] args) {
SpringApplication.run(ConsumerBootstrap.class).close();
}
@Bean
public ApplicationRunner runner() {
return args -> logger.info(demoService.sayHello("mercyblitz"));
}
}
6、Consumer 接入 dubbo 服务常见异常
以下列举一下 dubbo 在接入过程中出现的常见错误及解决办法。
6.1 连接注册中心失败
异常描述:
解决方法:
- 检查 zookeeper 是否成功启动,如果没有启动注册中心需要把注册中心启动起来。
- 如果注册中心已经启动可以查看当前服务是否能够连接注册中心。
- 如果当前机器能够连接注册中心,可以设置 zookeeper 的超时时间。
Dubbo Registry
#dubbo.registry.timeout=600000
Dubbo Config
#dubbo.config-center.timeout=600000
6.2 No provider
异常描述:
解决办法:
- 通过 dubbo-admin ,或者 zkCli 查看服务是否已经启动,如果没有启动需要启动服务。
- 如果已经启动,可以通过 dubbo-admin 检查服务的治理规则,看是否治理规则是否对服务进行拦截了。
6.3 TimeoutException
异常描述:
解决办法:
通过以下配置提高 consumer 服务调用的超时时间(单位毫秒):
dubbo.consumer.timeout=20000