前言
本文使用 springboot2.x
来整合dubbo
dubbo工作原理
- 服务启动的时候,provider和consumer根据配置信息,连接到注册中心register,分别向注册中心注册和订阅服务
- register根据服务订阅关系,返回provider信息到consumer,同时consumer会把provider信息缓存到本地。如果信息有变更,consumer会收到来自register的推送
- consumer生成代理对象,同时根据负载均衡策略,选择一台provider,同时定时向monitor记录接口的调用次数和时间信息
- 拿到代理对象之后,consumer通过代理对象发起接口调用
- provider收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现
dubbo负载均衡策略
- 加权随机:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上就可以了。
- 最小活跃数:每个服务提供者对应一个活跃数 active,初始情况下,所有服务提供者活跃数均为0。每收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求。
- 一致性hash:通过hash算法,把provider的invoke和随机节点生成hash,并将这个 hash 投射到 [0, 2^32 - 1] 的圆环上,查询的时候根据key进行md5然后进行hash,得到第一个节点的值大于等于当前hash的invoker。
- 加权轮询:比如服务器 A、B、C 权重比为 5:2:1,那么在8次请求中,服务器 A 将收到其中的5次请求,服务器 B 会收到其中的2次请求,服务器 C 则收到其中的1次请求。
创建项目
创建父工程
打开 idea
点击 File>New>Project 选择Spring Initializr >JDK版本>Next 并创建好父工程 springboot-dubbo-parent
,并删除 src
,.gitignore
,HELP.md
,mvnw
和mvnw.cmd
目录
父工程 pom
依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>springboot-dubbo-public-api-service</module>
<module>springboot-dubbo-api-member-service-impl</module>
<module>springboot-dubbo-order-web</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.baba.wlb</groupId>
<artifactId>springboot-dubbo-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<name>springboot-dubbo-parent</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--springboot 整合web组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
子模块工程
springboot-dubbo-public-api-service
:通用Api接口类,只有接口和Entity类。springboot-dubbo-api-member-service
:为具体的会员接口类,在springboot-dubbo-public-api-service
模块下面springboot-dubbo-api-member-service-impl
:member接口的实现类,依赖于springboot-dubbo-api-member-service
member接口模块。springboot-dubbo-order-web
:order模块依赖于于member接口模块,调用member模块接口。
依照上面的依赖关系构建好项目目录结构如下:
springboot-dubbo-api-member-service
中新建接口:IMemberService.java
package com.baba.wlb.member;
/**
* @Author wulongbo
* @Date 2021/1/5 19:36
* @Version 1.0
*/
public interface IMemberService {
// 会员接口
String getUser();
}
目录结构以及pom依赖如下:
springboot-dubbo-api-member-service-impl
中新建接口的实现类 MemberServiceImpl.java
:
package com.baba.wlb.member.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.baba.wlb.member.IMemberService;
import org.springframework.beans.factory.annotation.Value;
/**
* @Author wulongbo
* @Date 2021/1/5 19:39
* @Version 1.0
*/
@Service
public class MemberServiceImpl implements IMemberService {
@Value("${dubbo.protocol.port}")
private String dubboPort;
// 1.dubbo服务发布的时候采用dubbo 注解方式,使用 dubbo @Service注解 进行发布服务
// 2.dubbo 提供的 @Service 将该接口的实现注册到注册中心上去
// 3.spring 的 @Service 将该类注入到spring容器中
@Override
public String getUser() {
System.out.println("订单服务调用会员服务...dubbo服务端口号:" + dubboPort);
return "订单服务调用会员服务...dubbo服务端口号:" + dubboPort;
}
}
再新建 MemberApplication.java
启动类:
package com.baba.wlb.member.impl;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author wulongbo
* @Date 2021/1/5 19:52
* @Version 1.0
*/
@EnableDubbo
@SpringBootApplication
public class MemberApplication {
public static void main(String[] args) {
SpringApplication.run(MemberApplication.class,args);
}
}
application.yml
配置类:
##服务器端口号
server:
port: 8083
##dubbo 注册到注册中心的名称
dubbo:
application:
name: member
##采用协议方式和端口号
protocol:
## 常用协议:dubbo,http,webService等
name: dubbo
## 发布dubbo端口号为20880
port: 20880
registry:
## dubbo注册中心地址 zookeeper地址
address: zookeeper://39.102.56.91:2181
scan:
## 实现类扫包范围(可以省略,dubbo会自动扫 带了@Service的类)
base-packages: com.baba.wlb.member.impl.MemberServiceImpl
目录结构以及pom依赖如下:
springboot-dubbo-order-web
中新建业务类 OrderController.java
:
package com.baba.wlb.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.baba.wlb.member.IMemberService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author wulongbo
* @Date 2021/1/5 20:01
* @Version 1.0
*/
@RestController
public class OrderController {
// @Reference 提供 获取调用服务
@Reference
private IMemberService imemberService;
@RequestMapping("/orderToMember")
public String orderToMember() {
return imemberService.getUser();
}
}
OrderApplication.java
启动类:
package com.baba.wlb.controller;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author wulongbo
* @Date 2021/1/5 20:05
* @Version 1.0
*/
@EnableDubbo
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
application.yml
配置类:
##服务器端口号
server:
port: 8084
##dubbo 注册到注册中心的名称
dubbo:
application:
name: order
registry:
## dubbo注册中心地址 zookeeper地址
address: zookeeper://39.102.56.91:2181
consumer:
timeout:
目录结构以及pom依赖如下:
启动项目
启动生产者
启动 MemberApplication.java
勾选 Allow paraller run
允许我们并行运行,这样我们就不用新建两个启动类:
修改 application.yml
中 prot
为 8085
dubbo端口号修改为20881
再启动一个生产者
查看 dubbo admin
上生产者:
启动consumer
启动 OrderApplication.java
查看 dubbo admin
上consumer:
Postman接口测试
打开postman 并访问:localhost:8084/orderToMember
我们每点击一次send 请求,会轮询我们两个生产者服务。
如果是随机可以在 dubbo admin
上配置负载均衡策略
至此springboot整合dubbo就完成了!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。