目录
什么是Dubbo?
环境要求
Dubbo架构
基于注解的代码实现:
供应者配置
消费者配置
Dubbo 高级特性
序列化
地址缓存
超时与重试
多版本
负载均衡(必须有集群的环境)
集群容错
延伸阅读
1. 消费端是怎么找到服务端的?
2. 消费端是如何发起请求的?
Dubbo实现多种语言,为所有主流语言提供对等的微服务开发体验
作为一款微服务框架,最重要的是向用户提供跨进程的 RPC 远程调用能力。如上图所示,Dubbo 的服务消费者(Consumer)通过一系列的工作将请求发送给服务提供者(Provider)。
在数据面,Dubbo作为一款微服务框架最重要的是向用户提供跨进程的 RPC 远程调用能力,在控制面,作为微服务的抽象控制面,Dubbo由一系列可选的微服务治理组件构成,负责Dubbo集群的服务发现,流量管控,可视化监测等
Dubbo官方推荐使用Zookeeper作为注册中心
系统:Windows、Linux、MacOS
JDK 8 及以上(推荐使用 JDK17)
Git
IntelliJ IDEA(可选)
Docker (可选)
节点角色说明:
首先,必须有一个提供程序的整体配置:
配置:
dubbo.application.name=samples-annotation-provider
dubbo.registry.address=zookeeper://121.37.118.193:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.provider.token=true
配置类
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.annotation.impl")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration {
}
@EnableDubbo
将使 Spring 包能够找到任何由 Dubbo 注释注释的内容。org.apache.dubbo.samples.annotation.impl
作为提供程序,接口实现类必须由以下项注释:@DubboService
@DubboService
public class AnnotatedGreetingService implements GreetingService {
public String sayHello(String name) {
System.out.println("greeting service received: " + name);
return "hello, " + name;
}
}
消费者的整体配置对提供商来说非常温和:
配置:
dubbo.application.name=samples-annotation-consumer
dubbo.registry.address=zookeeper://121.37.118.193:2181
配置类 :
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.annotation.action")
@PropertySource("classpath:/spring/dubbo-consumer.properties")
@ComponentScan(value = {"org.apache.dubbo.samples.annotation.action"})
static class ConsumerConfiguration {
}
您可以使用注释将提供程序自动连接到使用者:@DubboReference
@Component("annotatedConsumer")
public class GreetingServiceConsumer {
@DubboReference
private GreetingService greetingService;
...
}
依赖配置:
1.8
1.8
3.2.0
4.3.30.RELEASE
4.13.1
3.7.0
3.8.0
org.springframework
spring-framework-bom
${spring.version}
pom
import
org.apache.dubbo
dubbo-bom
${dubbo.version}
pom
import
org.apache.dubbo
dubbo-dependencies-zookeeper-curator5
${dubbo.version}
pom
org.apache.zookeeper
parent
${zookeeper_version}
pom
import
org.apache.dubbo
dubbo
org.apache.dubbo
dubbo-dependencies-zookeeper-curator5
pom
junit
junit
${junit.version}
test
org.springframework
spring-test
test
com.github.spotbugs
spotbugs-annotations
true
commons-cli
commons-cli
org.eclipse.jetty
jetty-server
org.eclipse.jetty
jetty-servlet
org.eclipse.jetty
jetty-client
jline
jline
io.dropwizard.metrics
metrics-core
org.xerial.snappy
snappy-java
javax.annotation
[1.11,)
javax.annotation
javax.annotation-api
1.3.2
org.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}
${target.level}
dubbo 内部已经将序列化和反序列化的过程内部封装了,我们只需要在定义pojo类时实现Serializable接口即可,一般会定义一个公共的pojo模块,让生产者和消费者都依赖该模块。
注册中心挂了,服务是否可以正常访问?
可以,因为dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心。当服务提供者地址发生变化时,注册中心会通知服务消费者。
服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
dubbo 利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
使用timeout属性配置超时时间,默认值1000,单位毫秒。
设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
如果出现网络抖动,则这一次请求就会失败。
Dubbo 提供重试机制来避免类似问题的发生。
通过 retries 属性来设置重试次数。默认为 2 次
供应端代码:(建议配置在供应端)
@Service(timeout = 3000,retries = 2)//当前服务3秒超时,重试2次,一共3次
public class UserServiceImpl implements UserService {
int i = 1;
public String sayHello() {
return "hello dubbo hello!~";
}
public User findUserById(int id) {
System.out.println("服务被调用了:"+i++);
//查询User对象
User user = new User(1,"zhangsan","123");
//数据库查询很慢,查了5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
}
消费者代码
@RestController
@RequestMapping("/user")
public class UserController {
//注入Service
//@Autowired//本地注入
/*
1. 从zookeeper注册中心获取userService的访问url
2. 进行远程调用RPC
3. 将结果封装为一个代理对象。给变量赋值
*/
@Reference(timeout = 1000)//远程注入
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
/**
* 根据id查询用户信息
* @param id
* @return
*/
int i = 1;
@RequestMapping("/find")
public User find(int id){
new Thread(new Runnable() {
public void run() {
while (true){
System.out.println(i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return userService.findUserById(id);
}
@Service(version = "v2.0")
public class UserServiceImpl2 implements UserService {
...
}
@Reference(version = "v2.0")//远程注入
private UserService userService;
负载均衡策略(4种) :
@Service(weight = 100)
public class UserServiceImpl implements UserService {
...
}
@Reference(loadbalance = "random")//远程注入
private UserService userService;
@Reference(cluster = "failover")//远程注入
private UserService userService;
集群容错模式:
Failover Cluster:失败重试。默认值。当出现失败,重试其它服务器 ,默认重试2次,使用 retries 配置。一般用于读操作
Failfast Cluster :快速失败,只发起一次调用,失败立即报错。通常用于写操作。
Failsafe Cluster :失败安全,出现异常时,直接忽略。返回一个空结果。
Failback Cluster :失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster :并行调用多个服务器,只要一个成功即返回。
Broadcast Cluster :广播调用所有提供者,逐个调用,任意一台报错则报错
服务提供者会向注册中心中写入自己的地址,供服务消费者获取。
在 Dubbo 的调用模型中,起到连接服务消费者和服务提供者的桥梁是接口。
服务提供者通过对指定接口进行实现,服务消费者通过 Dubbo 去订阅这个接口。服务消费者调用接口的过程中 Dubbo 会将请求封装成网络请求,然后发送到服务提供者进行实际的调用。
// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java
package org.apache.dubbo.samples.api;
public interface GreetingsService {
String sayHi(String name);
}
服务消费者通过 Dubbo 的 API 可以获取这个 GreetingsService
接口的代理,然后就可以按照普通的接口调用方式进行调用。得益于 Dubbo 的动态代理机制,这一切都像本地调用一样。
// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java
// 获取订阅到的 Stub
GreetingsService service = reference.get();
// 像普通的 java 接口一样调用
String message = service.sayHi("dubbo");