一、实战
1 . Springboot整合
1.1 服务提供者
1.1.1 依赖
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.10</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-zookeeper-spring-boot-starter</artifactId>
<version>3.2.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
</exclusions>
</dependency>
1.1.2 配置
dubbo:
protocol:
name: tri
port: 50051
application:
name: lyl-dubbo-server
logger: slf4j
registry:
address: zookeeper://localhost:2181
1.1.3 开启dubbo
@EnableDubbo 使用该注释,开启dubbo
@SpringBootApplication
@EnableDubbo
public class ServerApp
{
public static void main( String[] args )
{
SpringApplication.run(ServerApp.class, args);
System.out.println("server started!");
}
}
1.1.4 服务暴露(服务注册)
@DubboService 使用该注释,进行服务暴露(注册到注册中心)
package com.doumi.service;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
@DubboService
@Service
public class DemoServiceImpl implements DemoService {
@Override
public String hello(String name) {
return "i am server hello " + name;
}
}
1.2 服务消费者
1.2.1 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.8</version>
</dependency>
<!-- dubbo 依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.10</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-zookeeper-spring-boot-starter</artifactId>
<version>3.2.10</version>
</dependency>
1.2.2 配置
dubbo:
protocol:
name: tri
port: 50052
application:
name: lyl-dubbo-client
logger: slf4j
registry:
address: zookeeper://localhost:2181
1.2.3 开启dubbo
package com.doumi;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
/**
* 服务调用端!
*
*/
@SpringBootApplication
@RestController
@EnableDubbo
public class ClientApp
{
public static void main( String[] args )
{
SpringApplication.run(ClientApp.class, args);
System.out.println( "client start!" );
}
}
1.2.4 使用服务
@DubboReference 使用该注解,调用dubbo服务
package com.doumi.controller;
import com.doumi.service.DemoService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class MyRestController {
/**
* mock 容错处理,返回null
* mock = true
*/
@DubboReference(mock = "true")
private DemoService demoService;
@GetMapping(path = "/hello")
public String hello(@RequestParam String name) {
return demoService.hello(name);
// return "i am client, hello "+name;
}
}
2、高级特性
2.1 序列化
package com.doumi.service;
import com.doumi.pojo.User;
public interface DemoService {
String hello(String name);
User find(Integer id);
}
package com.doumi.service;
import com.doumi.pojo.User;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String hello(String name) {
return "i am server hello " + name;
}
@Override
public User find(Integer id) {
User user = new User(id, "user-" + id);
return user;
}
}
package com.doumi.controller;
import com.doumi.pojo.User;
import com.doumi.service.DemoService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class MyRestController {
/**
* mock 容错处理,返回null
* mock = true
*/
@DubboReference(mock = "false")
private DemoService demoService;
@GetMapping(path = "/hello")
public String hello(@RequestParam String name) {
return demoService.hello(name);
}
@GetMapping(path = "/find")
public User find(@RequestParam Integer id) {
return demoService.find(id);
}
}
当返回是个对象时,该对象必须进行序列化,因为该对象需要在两台服务器间(网络)传输
pojo定义如下:
package com.doumi.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
public User() {
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
当对象没有序列化的时候,报错如下:
org.apache.dubbo.rpc.StatusRpcException: INTERNAL : Serialize response failed
at org.apache.dubbo.rpc.TriRpcStatus.asException(TriRpcStatus.java:213) ~[dubbo-3.2.10.jar:3.2.10]
at org.apache.dubbo.rpc.protocol.tri.call.UnaryClientCallListener.onClose(UnaryClientCallListener.java:53) ~[dubbo-3.2.10.jar:3.2.10]
2.2 地址缓存
注册中心挂了,服务是否可以正常访问?
- 可以,因为dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后再调用,则不会访问注册中心。
- 当服务提供者地址发生变化时,注册中心会通知服务消费者。
2.3 超时
- 服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这时候,服务消费者会一直等待下去。
- 在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
- dubbo利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
- 使用timeout属性配置超时时间,默认值1000,单位毫秒。
服务端配置超时时间
package com.doumi.service;
import com.doumi.pojo.User;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService(timeout = 3000)//服务端配置超时时间
public class DemoServiceImpl implements DemoService {
@Override
public String hello(String name) throws InterruptedException {
Thread.sleep(5000);
return "i am server hello " + name;
}
int i ;
@Override
public User find(Integer id) throws InterruptedException {
System.out.println("调用服务端"+i++);
User user = new User(id, "user-" + id);
Thread.sleep(5000);
return user;
}
}
客户端配置超时时间
package com.doumi.controller;
import com.doumi.pojo.User;
import com.doumi.service.DemoService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class MyRestController {
/**
* mock 容错处理,返回null
* mock = true
*/
@DubboReference(mock = "true",timeout = 6000) //客户端设置超时时间,服务端设置成3s,服务调用实际时间是5s,此时可以调用成功
private DemoService demoService;
@GetMapping(path = "/hello")
public String hello(@RequestParam String name) throws InterruptedException {
timer();
return demoService.hello(name);
}
@GetMapping(path = "/find")
public User find(@RequestParam Integer id) throws InterruptedException {
timer();
return demoService.find(id);
}
int i = 1;
public void timer() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
}
2.4 重试
设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
如果出现网络抖动,则这次请求就会失败。
dubbo提供重试机制,来避免类似问题的发生。
通过retries属性来设置重试次数,默认为2次。
@RestController
@RequestMapping("/users")
public class MyRestController {
/**
* mock 容错处理,返回null
* mock = true
*/
@DubboReference(mock = "true",timeout = 1000,retries = 5) 当前服务1秒超时,重试5次,共调用6次
private DemoService demoService;
2.5 多版本
2.5.1 使用场景
- 灰度发布:当出现新功能时,会让一部分用户先试用新功能,用户反馈没问题时,再将所有用户迁移到新功能。
- dubbo中使用version属性来设置和调用同一个接口的不同版本
2.5.2 实现方式
服务端两个版本的实现,分别标识 version = "v1.0" version = "v2.0"
客户端使用version = "v1.0" 和version = "v2.0",控制具体使用哪个版本
package com.doumi.service;
import com.doumi.pojo.User;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService(timeout = 3000,retries =1,version = "v1.0")
public class DemoServiceImpl implements DemoService {
@Override
public String hello(String name) throws InterruptedException {
Thread.sleep(5000);
return "i am server hello " + name;
}
int i ;
@Override
public User find(Integer id) throws InterruptedException {
System.out.println("old 调用服务端"+i++);
User user = new User(id, "user-" + id);
Thread.sleep(5000);
return user;
}
}
package com.doumi.service;
import com.doumi.pojo.User;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService(timeout = 3000,retries =1,version = "v2.0" )
public class DemoServiceImpl2 implements DemoService {
@Override
public String hello(String name) throws InterruptedException {
Thread.sleep(5000);
return "i am server hello " + name;
}
int i ;
@Override
public User find(Integer id) throws InterruptedException {
System.out.println("new 调用服务端 "+i++);
User user = new User(id, "user-" + id);
Thread.sleep(5000);
return user;
}
}
@RestController
@RequestMapping("/users")
public class MyRestController {
/**
* mock 容错处理,返回null
* mock = true
*/
@DubboReference(mock = "true",timeout = 1000,retries = 5,version = "v1.0") //当前服务1秒超时,重试5次,共调用6次
private DemoService demoService;
2.6 负载均衡
负载均衡策略:(4种)
- Random:按权重随机,默认值,按权重设置随机概率
- RoundRobin:按权重轮询
- LeastActive:最少活跃调用数,相同活跃数的随机
- ConsistantHash:一致性Hash,相同参数的请求总是发到同一提供者
@RestController
@RequestMapping("/users")
public class MyRestController {
/**
* mock 容错处理,返回null
* mock = true
*/
@DubboReference(loadbalance ="RandomLoadBalance" ) //负载均衡策略
private DemoService demoService;
2.7 集群容错
集群容错模式:
FailOver Cluster:失败重试,默认值。当出现失败,重试其他
FailFast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于写操作。
FailSafe Cluster:失败安全,出现异常时,直接忽略。返回一个空结果。
FailBack Cluster:失败自动恢复,后台记录失败请求,定时重发。
Forking Cluster:并行调用多个服务器,只要有一个成功即返回。
// @DubboReference(cluster = "failover",version = "v1.0")//失败重试
// @DubboReference(cluster = "failfast",version = "v1.0")//快速失败,失败了直接返回错误
// @DubboReference(cluster = "failsafe",version = "v1.0")//失败了返回一个空结果,防止出现异常
// @DubboReference(cluster = "failback",version = "v1.0")//失败自动恢复,后台记录失败请求,定时重发。
@DubboReference(cluster = "forking",version = "v1.0")//并行调用多个服务器,只要有一个成功即返回。
private DemoService demoService;
2.8 服务降级
服务降级方式:
- mock=force:return null :表示消费方对该服务的方法的调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
- mock=fail:return null 表示消费方对该服务的方法调用在失败后,再返回null值,不抛出异常。用来容忍不重要服务不稳定时,对调用方的影响。
//@DubboReference(mock = "force:return null")//不会发起调用,直接失败,用于服务降级的场景,保证重点服务可用,非重点服务直接失败
@DubboReference(mock = "fail:return null",version="v1.0")//表示消费方对该服务的方法调用在失败后,再返回null值,不抛出异常。用来容忍不重要服务不稳定时,对调用方的影响。
private DemoService demoService;