基本使用
添加依赖
<artifactId>dubbo</artifactId>
<packaging>pom</packaging>
<modules>
<module>provider</module>
<module>consumer</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<dubbo.version>3.0.6</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- 此pom适用于以前的版本,现在已经包含在 dubbo-dependencies-zookeeper
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.1</version>
</dependency>-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<!-- apache zookeeper 默认使用了 slf4j 门面的 log4j 实现。排除后就没有配置文件的警告⚠️-->
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 要么使用zk,要么使用nacos,二选一
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
</plugins>
</build>
添加配置
server:
port: 8086 # 生产/消费端的port需不同
spring:
application:
name: consumer # 生产/消费端的name需不同
dubbo:
application:
name: ${spring.application.name}
registry:
protocol: zookeeper
address: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
# address: nacos://127.0.0.1:8848
# 注册中心是否检查
# check: false
scan:
base-packages: com.howeres.service
protocol: # 这里使用了dubbo协议
name: dubbo
port: 20882 # 生产/消费端的通讯port需不同
consumer:
# 全局消费者默认是否检查
check: false
retries: 3
使用注解
- 提供端
@DubboService(methods = {@Method(name = "getInfo", timeout = 3000)},version = "1.0.0")
public class MessageServiceImpl implements MessageService {
@Override
public String getInfo(String info) {
try { TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) { e.printStackTrace();}
return info + "已经抵达上车点";
}
}
- 消费端
@Service
public class DriverServiceImpl implements DriverService {
/**
* dubbo的注册中心宕机了依然能连,是因为本地还有缓存。
*
* <p>没有注册中心也能调用服务:dubbo直连,reference使用url参数 (ip+port);
*
* <p>检查单独检查是否连接:check,也可以设置参数{@code dubbo.consumer.check=false}
*
* <p>版本:version,灰度发布通配符:*;*不能与dubbo直连一起使用。因为dubbo直连绕过了注册中心,所以无法对版本进行负载均衡,也就无法使用通配符
*
* <p>本地存根:stub,全限定名+全参构造器
*
* <p>重试次数:retries,方法级、service级都行
*/
@DubboReference(
methods = @Method(name = "getInfo", timeout = 3000, retries = 3),
// url = "127.0.0.1:20881", // dubbo 直连不能搭配版本通配符 *
check = false,
version = "*",
stub = "com.howeres.service.impl.MessageServiceStub")
MessageService messageService;
public String pickUp(String info) {
return messageService.getInfo(info);
}
}
- 消费端本地存根
public class MessageServiceStub implements MessageService {
private final MessageService messageService;
public MessageServiceStub(MessageService messageService) {
this.messageService = messageService;
}
@Override
public String getInfo(String info) {
if (info == null) {
return null;
}
return messageService.getInfo(info);
}
}
基本配置
- dubbo的注册中心宕机了依然能连,是因为本地还有缓存。
- 没有注册中心也能调用服务:dubbo直连,reference使用url参数 (ip+port);
- 检查单独检查是否连接:check,也可以设置参数dubbo.consumer.check=false
- 版本:version,灰度发布通配符:*;*不能与dubbo直连一起使用。推测是因为直连是精确到某一个服务,而多版本适合多个微服务,所以必须指定版本
- 本地存根:stub,全限定名+全参构造器
- 超时时间:timeout,官方推荐放在提供端。因为多个消费端同时消费时,实际执行时间只有提供端知道。
- 重试次数:retries,方法级、service级都行
高可用
使用负载均衡
推荐放在消费端:
@DubboReference(loadbalance = LeastActiveLoadBalance.NAME)
MessageService messageService;
总共有5种:
- RandomLoadBalance 基于权重的随机负载均衡机制
- RoundRobinLoadBalance 轮询
- LeastActiveLoadBalance 最少活跃数
- ShortestResponseLoadBalance
- ConsistentHashLoadBalance 一致性hash(方法名和参数都一致,老熟人方式)
两种降级(底层是zk):
-
直接降级:mock=force:return+null直接返回为null值,不发起远程调用。用来屏蔽(block)不重要服务不可用时对调用端的影响,在消费端手动屏蔽提供者。
-
失败降级:mock=fail:return+null调用失败后返回null值,不抛异常。用来屏蔽不重要服务不稳定时对调用端的影响,设置容错。(不容错的情况下,超时会有一个控制台类型的页面报错)
集群容错模式:默认是:failover Cluster;
failover Cluster:失败自动切换,当出现失败,重试其他服务器;
failfast Cluster:适合新增等非幂等的写操作;
failsafe Cluster:适合日志写入操作,出现异常直接忽略;
failback Cluster:适合一定要成功的操作,失败记录下来,隔一段时间重试一次;
forking Cluster:并行调用,一个成功即返回,适合实时性要求高的读操作。比较浪费资源;
broadcast Cluster:广播调用,一台报错就报错。适合同步更新缓存或日志等本地资源信息;
容错结合Hystrix
- spring-cloud-starter-netflix-hystrix maven依赖引入
- @EnableHystrix
- 提供端@HystrixCommand,让目标方法被hystrix代理
- 消费端@HystrixCommand(fallbackMethod=“methodName”)
dubbo实现(netty)
nio:相比于bio(blocking)使用Socket单开线程然后阻塞,nio用了channel,使用buffer传输,多路复用selector
启动
-
标签解析:BeanDefinitionParser#parse 标签解析挨个解析配置文件里面的《标签名+Config》或者通过scan.base-package下声明注解的类以及对应接口进行加载。
-
服务暴露:ServiceBean「initializingBean+ApplicationListener」解析过程中ServiceBean做了:容器创建完操作+监听ContextRefreshedEvent操作(触发ContextRefreshEvent时,执行export()暴露服务)。注册中心等信息不仅全局保存了,每个暴露的服务也进行了保存。暴露协议doExportUrls->doExportUrlsFor1Protocol代理工厂暴露接口,协议包含dubbo协议和registry注册中心的协议。最后dubbo协议以及端口底层是用netty提供的接口进行绑定。最后将这些暴露的信息放到注册中心。
ProviderConsumerRegTable
注册表类中两个并发hashmap,存了<url, Set对应的执行器们> 方便以后调用。 -
服务引用:ReferenceBean「FactoryBean」调用getObject方法,ReferenceConfig,ProxyFactory根据map(里面包含信息)创建代理ref=createProxy(map),返回一个invoker代理封装远程的调用信息
-
服务调用:消费端实际调用的是封装的代理,MockClusterInvoker接口FailoverClusterInvoker对象,选择负载均衡对象。
Reference
dubbo官网:https://dubbo.apache.org/en/docs/v2.7/dev/design/