4

前言

本文使用 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。

image

  • 加权轮询:比如服务器 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,mvnwmvnw.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模块接口。

依照上面的依赖关系构建好项目目录结构如下:

image.png


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依赖如下:
image.png


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依赖如下:
image.png


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依赖如下:
image.png

启动项目

启动生产者

启动 MemberApplication.java
勾选 Allow paraller run 允许我们并行运行,这样我们就不用新建两个启动类:
image.png
修改 application.ymlprot8085 dubbo端口号修改为20881
再启动一个生产者
image.png
查看 dubbo admin 上生产者:
image.png

启动consumer

启动 OrderApplication.java
image.png
查看 dubbo admin 上consumer:
image.png

Postman接口测试

打开postman 并访问:localhost:8084/orderToMember
我们每点击一次send 请求,会轮询我们两个生产者服务。
image.png
如果是随机可以在 dubbo admin 上配置负载均衡策略
image.png

至此springboot整合dubbo就完成了!


isWulongbo
228 声望26 粉丝

在人生的头三十年,你培养习惯,后三十年,习惯铸就你