Dating front-end-dubbo

Article directory

    • 1. Dubbo’s past and present
    • 2. Quick start of Dubbo
      • 2.1. The basic structure of Dubbo
      • 2.2、Nacos
      • 2.3. Management background
      • 2.4. Getting Started Case
        • 2.4.1. Service Providers
          • build environment
          • Code
          • configuration file
        • 2.4.2. Service consumers
          • build environment
          • Code
          • configuration file
      • 2.5. Code optimization
    • 3. Advanced features of Dubbo
      • 3.2, timeout and retry
      • 3.3. Startup check
      • 3.4, multiple versions
      • 3.5. Load balancing
    • 4. Spring Cloud integrates Dubbo
      • 4.1. Function overview
      • 4.2. Getting Started Case
        • 4.2.1. Extraction interface
        • 4.2.2. Project dependencies
        • 4.2.3. Service provider
        • 4.2.4. Service consumers

1. Dubbo’s past and present life

On October 27, 2011, Alibaba open-sourced Dubbo, the core framework of its SOA service-based governance solution, and the design concepts of service governance and SOA began to be gradually implemented in the domestic software industry and widely used.

  • The early version of dubbo follows the idea of SOA and is an important component of service-oriented architecture.

  • The current version of Dubbo is used as Spring Cloud’s binary communication solution to take advantage of Dubbo’s performance

2. Quick start of Dubbo

2.1, the basic structure of Dubbo

image-20210724230935258

Node role description:

node role description
Provider The service provider of the exposed service.
Consumer The service consumer who calls the remote service.
Registry Registry for service registration and discovery.
Monitor A monitoring center that counts service calls and call times.

Call relationship description:

  1. The service container is responsible for starting, loading, and running the service provider.
  2. When the service provider starts, it registers the services it provides with the registration center.
  3. When a service consumer starts, it subscribes to the registration center for the services it needs.
  4. The registration center returns the service provider address list to the consumer. If there is a change, the registration center will push the change data to the consumer based on the long connection.
  5. Service consumers, from the provider address list, select a provider to call based on the soft load balancing algorithm, and if the call fails, select another provider to call.
  6. Service consumers and providers accumulate the number of calls and call time in memory, and regularly send statistical data to the monitoring center every minute.

2.2, Nacos

Nacos is a product of Alibaba. It is a platform integrating service discovery and configuration management. It is very popular in China.

image-20210727122815029

1. Find the nacos installation package in today’s information

image-20210727122829914

2. Unzip to a directory without Chinese and special characters

3. Enter the bin directory and execute the startup command

#Enter the bin directory
cd bin
#start up
startup.cmd -m standalone

4. Browser viewing: http://127.0.0.1:8848/nacos

2.3, management background

DubboAdmin is a management console provided by Alibaba Management, which can implement functions such as service query, detailed display, and service testing. DubboAdmin can better help developers manage and monitor services

#1. Download code:
git clone https://github.com/apache/dubbo-admin.git
#2. Specify the registration center address in dubbo-admin-server/src/main/resources/application.properties
#3. Build
mvn clean package -D maven.test.skip=true
#4. Start
mvn --projects dubbo-admin-server spring-boot:run
#or
cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar
#5. Visit http://localhost:8080

2.4, entry case

Requirements: Use Dubbo to build a distributed architecture and complete user query based on user id

image-20210727123052273

2.4.1, service provider

Building the environment

(1) Create user-provider module import dependencies

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>

    <!--Dubbo's starting dependency-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>2.7.8</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>2.7.8</version>
    </dependency>
</dependencies>

(2) Write the boot class

package cn.itcast.user;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserProviderApplication {<!-- -->

    public static void main(String[] args) {<!-- -->
        SpringApplication.run(UserProviderApplication.class, args);
    }

}
Code Implementation

(1) UserServiceImpl

package cn.itcast.user.service;


import cn.itcast.user.api.UserService;
import cn.itcast.user.domain.User;
import cn.itcast.user.mapper.UserMapper;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;

@DubboService
public class UserServiceImpl implements UserService {<!-- -->

    @Autowired
    private UserMapper userMapper;

//Query user name by id
    public String queryUsername(Long id) {<!-- -->
        return userMapper.findById(id).getUsername();
    }
}
Configuration file
server:
  port: 18081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: user-provider
record:
  level:
    cn.itcast: debug
  pattern:
    dateformat: HH:mm:ss:SSS
dubbo:
  protocol:
    name: dubbo
    port: 20881
  registry:
    address: nacos://127.0.0.1:8848
  scan:
    base-packages: cn.itcast.user.service

2.4.2, service consumers

Building the environment

(1) Create user-consumer module import dependencies

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <!--Dubbo's starting dependency-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>2.7.8</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>2.7.8</version>
    </dependency>
</dependencies>

(2) Configure the boot class

package cn.itcast.user;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class UserConsumerApplication {<!-- -->

    public static void main(String[] args) {<!-- -->
        SpringApplication.run(UserConsumerApplication.class, args);
    }
}
Code Implementation
package cn.itcast.user.controller;


import cn.itcast.user.api.UserService;
import cn.itcast.user.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {<!-- -->

    // reference remote service
    @DubboReference
    private UserService userService;

    @GetMapping("/username/1")
    public String findUserName(@PathVariable("id") Long id) {<!-- -->
        return userService. queryUsername(id);
    }
}
Configuration file
server:
  port: 18080
spring:
  application:
    name: user-consumer
record:
  level:
    cn.itcast: debug
  pattern:
    dateformat: HH:mm:ss:SSS
dubbo:
  registry:
    address: nacos://127.0.0.1:8848

2.5, code optimization

Extract the interface as an independent module, and put all the domains related to the interface into this module

(1) Create a user-api module to introduce dependencies

(2) Import the UserService interface and User object into the user-api module

(3) The User object implements the serialization interface

package cn.itcast.user.domain;

import lombok.Data;

import java.io.Serializable;

@Data
public class User implements Serializable {<!-- -->
    private Long id;
    private String username;
    private String address;
}

3, Dubbo advanced features

3.2, timeout and retry

The service consumer is blocked and waiting when calling the service provider. At this time, the service consumer will wait forever.

At a certain peak moment, a large number of requests are requesting service consumers at the same time, which will cause a large accumulation of threads, which will inevitably cause an avalanche.

  • Dubbo uses the timeout mechanism to solve this problem (use the timeout attribute to configure the timeout period, the default value is 1000, in milliseconds)
  • If the timeout period is short, the request will fail when the network fluctuates. Dubbo avoids such problems through the retry mechanism

Add configuration information to the user-consumer module

dubbo:
  registry:
    address: nacos://127.0.0.1:8848
  consumer:
    timeout: 3000
    retries: 0

3.3, start check

In order to ensure the normal availability of the service, Dubbo will check whether the dependent service is available by default at startup, and will throw an exception if it is not available

image-20210727124027308

This is a very necessary configuration in a formal environment to ensure the smooth operation of the entire calling link

During development, there are often situations where there is no provider. May cause problems with development tests due to startup checks

Can be closed by check=false

Add configuration information to the user-consumer module

dubbo:
  registry:
    address: nacos://127.0.0.1:8848
  consumer:
    check: false

3.4, multiple versions

Grayscale release: When a new function appears, some users will be allowed to use the new function first, and all users will be migrated to the new function when there is no problem with user feedback.

Dubbo provides support for multiple versions of the provider, and smoothly handles project function upgrade deployment

(1) user-provider defines a new service implementation class UserServiceImpl2, specifying the version

@DubboService(version = "2.0.0")
public class UserServiceImpl2 implements UserService {<!-- -->
    …………
}

(2) When the user-consumer consumer calls, the specified version is called

@RestController
@RequestMapping("/user")
public class UserController {<!-- -->
    // reference remote service
    @DubboReference(version = "2.0.0")
    private UserService userService;
    ………
}

3.5, load balancing

During cluster deployment, Dubbo provides 4 load balancing strategies to help consumers find the optimal provider and call

  • Random : random by weight, the default value. Set random probability by weight.

  • RoundRobin : round robin by weight

  • LeastActive: The least number of active calls, random with the same number of active calls.

  • ConsistentHash: Consistent Hash, requests with the same parameters are always sent to the same provider.

@RestController
@RequestMapping("/user")
public class UserController {<!-- -->
    // reference remote service
    @DubboReference(loadbalance = "roundrobin")
    private UserService userService;
}

4. SpringCloud integrates Dubbo

Generally speaking, the RPC protocol has better performance than REST. Many developers hope to enjoy the ecology of Spring Cloud while taking into account the efficiency of PRC. SpringCloud Alibaba solves this problem very well.

4.1, function overview

Integrating Dubbo into Spring Cloud is mainly to replace Ribbo or Feign for remote calls. After joining Dubbo, the overall structure is as follows:

image-20210724222206792

4.2, entry case

4.2.1, extraction interface

Define the interface module dubbo-api, and extract the UserService interface to this module

package cn.itcast.dubbo.api;


import cn.itcast.dubbo.domain.User;

public interface UserService {<!-- -->

    User queryById(Long id);
}

4.2.2, project dependencies

Add SpringCloud Alibaba dependency to the parent project

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Consumers and providers introduce nacos registry and Dubbo dependencies

<!--dependence of nacos registration center-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!--springcloud alibaba dubbo dependency -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>

<dependency>
    <groupId>cn.itcast</groupId>
    <artifactId>dubbo-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

4.2.3, service provider

Modify UserService to implement the UserApi interface. And use @DubboService annotation to replace @Service to expose dubbo service externally

package cn.itcast.user.service;

import cn.itcast.dubbo.api.UserService;
import cn.itcast.dubbo.domain.User;
import cn.itcast.user.mapper.UserMapper;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;

@DubboService
public class UserServiceImpl implements UserService {<!-- -->

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) {<!-- -->
        return userMapper.findById(id);
    }
}

Add configuration in application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
#Configure dubbo, registration center, exposed ports and protocols, package scanning of dubbo annotations
dubbo:
  protocol:
    name: dubbo
    port: 20881
  registry:
    address: spring-cloud://localhost #Use the registration center in SpringCloud
  scan:
    base-packages: cn.itcast.user.service #dubbo medium package scanning

4.2.4, service consumers

Introduce dubbo service in OrderController. Call UserService to query users

package cn.itcast.order.controller;

import cn.itcast.dubbo.api.UserService;
import cn.itcast.dubbo.domain.Order;
import cn.itcast.dubbo.domain.User;
import cn.itcast.order.service.OrderService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("order")
public class OrderController {<!-- -->

    @Autowired
    private OrderService orderService;

    @DubboReference
    private UserService userService;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {<!-- -->
        //Query order by id
        Order order = orderService. queryOrderById(orderId);
        // get user id
        Long userId = order. getUserId();
        //query user
        User user = userService. queryById(userId);
        //set user object
        order. setUser(user);
        // Query the order by id and return
        return order;
    }
}

Add dubbo configuration in the module of Order-service

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
#dubbo configuration
dubbo:
  registry:
    address: spring-cloud://localhost #Use cloud's registration center
  consumer:
    check: false #dubbo has startup check by default
    retries: 0 #dubbo built-in retry mechanism
queryOrderById(orderId);
        // get user id
        Long userId = order. getUserId();
        //query user
        User user = userService. queryById(userId);
        //set user object
        order. setUser(user);
        // Query the order by id and return
        return order;
    }
}

Add dubbo configuration in the module of Order-service

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
#dubbo configuration
dubbo:
  registry:
    address: spring-cloud://localhost #Use cloud's registration center
  consumer:
    check: false #dubbo has startup check by default
    retries: 0 #dubbo built-in retry mechanism