Dubbo study notes finishing

Start to organize Dubbo's study notes today, share them in a continuous update, and use them as future reviews.

========>>>>2019 / 02/27 update

1. What is Dubbo ?

Dubbo's predecessor was an open source project of Alibaba. In 2018, Alibaba contributed Dubbo completely to apache as a sub-project of apache. Now, starting from Dubbo's official website: http://dubbo.apache.org/zh-cn /

It can be seen from the explanation on the official website that Dubbo is a high-performance Java RPC (Remote Procedure Call) framework. Then, what is RPC (Remote Procedure Call)?

 

With the development and popularization of the Internet, the innovation of technology and the increasing needs of users, there are more and more functional modules. The previous MVC framework not only caused a certain degree of development waste, but also can no longer meet the needs of development. , Management is also very inconvenient, so the distributed framework came into being.

 

The distributed framework is to split the unified function into n multiple sub-modules to run independently, and can extract the core module as an independent service. At the same time, in order to meet the needs of business scenarios, the interaction between the front-end and the back-end must be very timely and rapid. For services running on different machines to interact in a very timely manner, a very powerful governance (integration) center is needed to provide a management service, which is Dubbo (RPC framework).

 

The functional structure of Dubbo on the official website:

The approximate meaning in the picture is that Dubbo will provide a registry, a service provider, a service consumer and a monitor. When the service provider goes online, it will register its information in the registry. The service consumer needs to go online. When a service is called, it will ask the registration center for the information of the corresponding service provider. If the service exists, the service provider’s service will be called by Dubbo’s internal communication mechanism and returned to the service consumer. At this time, the monitor is Can clearly perceive the data change status of all nodes; when one of the services hangs up, the registry will also perceive and clear the data information in real time, at this time the consumer will no longer call the service; And if there are multiple service providers for a service, Dubbo's internal load balancing mechanism will implement the allocation call to ensure the balanced utilization of resources.

 

Features of Dubbo displayed on the official website:

 

2. A simple example of Dubbo

Download ZooKeeper:

The official recommendation is to use ZooKeeper as the registration center. The download address of zookeeper-3.4.11.tar.gz: https://archive.apache.org/dist/zookeeper/zookeeper-3.4.11/zookeeper-3.4.11.tar.gz

ZooKeeper is also a sub-project under apache, which is a tree-shaped directory structure, as shown below:

Install ZooKeeper under Linux:

After downloading zookeeper-3.4.11.tar.gz, pressurize the tar package, enter the directory of the installation package, create a new data folder, enter the conf directory, rename zoo_sample.cfg to zoo.cfg, edit the zoo.cfg file, Change the path of dataDir to the path under the data directory (used to store ZooKeeper temporary files)

After saving and exiting, enter the bin directory and start ZooKeeper: ./zkServer.sh start, and enter the command ./zkServer.sh status to check the startup status. If the following figure appears, the startup is successful:

Deploy dubbo-admin subproject under Linux:

It needs to be mentioned that in Dubbo versions after 2.6, dubbo-admin has been removed and become a separate module, which is no longer included in the Dubbo installation package, so it needs to be downloaded separately: https://github.com/apache/incubator -dubbo-ops/tree/master , in the previous version, the dubbo-admin module is packaged as war, so it needs to be deployed to tomcat and other containers to run, but in the latest version of the dubbo-admin module, it has been integrated The SpringBoot module is packaged in jar.

 

After the download is complete, enter the dubbo-admin directory, find the resources folder, edit the application.properties file, modify the ZooKeeper ip, the port defaults to 2181, and finally use maven to execute the packaging command: mvn clean package -Dmaven.skip.test=true

 

Enter the Linux system and start the jar package: java -jar <jar package name>

After the startup is successful, visit the dubbo-admin background (the default access port of dubbo-admin is 7001): http://<ip>:7001 , enter the user name and password (account: root, password: root or account: guest, password: guest) The carriage return appears as shown below:

 

 

Use IDEA to implement a simple distributed framework:

Common layer:

UserAddress:

package cn.idea.dubbo.service.bean;

import java.io.Serializable;

public class UserAddress implements Serializable {

    private static final long serialVersionUID = -5410701634982141754L;
    private Integer id;
    private String userAddress; //用户地址
    private String userId; //用户id
    private String consignee; //收货人
    private String phoneNum; //电话号码
    private String isDefault; //是否为默认地址    Y-是     N-否

    public UserAddress() {
    }

    public UserAddress(Integer id, String userAddress, String userId, String consignee, String phoneNum,
                       String isDefault) {
        super();
        this.id = id;
        this.userAddress = userAddress;
        this.userId = userId;
        this.consignee = consignee;
        this.phoneNum = phoneNum;
        this.isDefault = isDefault;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUserAddress() {
        return userAddress;
    }
    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getConsignee() {
        return consignee;
    }
    public void setConsignee(String consignee) {
        this.consignee = consignee;
    }
    public String getPhoneNum() {
        return phoneNum;
    }
    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }
    public String getIsDefault() {
        return isDefault;
    }
    public void setIsDefault(String isDefault) {
        this.isDefault = isDefault;
    }
}

OrderService:

package cn.idea.dubbo.service;

public interface OrderService {

    public void initOrder(String userId);
}

UserService:

package cn.idea.dubbo.service;

import cn.idea.dubbo.service.bean.UserAddress;

import java.util.List;

public interface UserService {

    public List<UserAddress> getUserAddressList(String userId);
}

Service provider:

UserServiceImpl:

package cn.idea.dubbo.service.impl;

import cn.idea.dubbo.service.UserService;
import cn.idea.dubbo.service.bean.UserAddress;

import java.util.Arrays;
import java.util.List;

public class UserServiceImpl implements UserService {

    public List<UserAddress> getUserAddressList(String userId) {
        UserAddress address1 = new UserAddress(1, "中国上海", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(2, "中国广州", "1", "王老师", "010-56253825", "N");
        return Arrays.asList(address1,address2);
    }
}

provider.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!--指定当前应用的名称,随便定义即可,一般跟当前的应用名称相同,不要有重复的服务名称即可
    -->
        <dubbo:application name="demo-service-provider"/>

    <!--指定ZooKeeper的位置
    -->
        <!--<dubbo:registry address="zookeeper://192.168.25.132:2181"/>-->
    <!--或者-->
        <dubbo:registry protocol="zookeeper" address="192.168.25.132:2181"/>

    <!--指定通信规则
    -->
        <dubbo:protocol name="dubbo" port="20880"/>

    <!--指定要暴露的服务
        interface:暴露的是接口
        ref:真正指向的是接口的实现对象(此时需要一个已经加入容器中的bean)
    -->
        <dubbo:service interface="cn.idea.dubbo.service.UserService" ref="userServiceImpl"/>

    <!--将实现类加入容器中
    -->
    <bean id="userServiceImpl" class="cn.idea.dubbo.service.impl.UserServiceImpl"/>

</beans>

MainApplication :

package cn.idea.dubbo.service;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

public class MainApplication {

    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("provider.xml");
        classPathXmlApplicationContext.start();

        System.in.read();
    }
}

Service consumer:

OrderServiceImpl:

package cn.idea.dubbo.service.impl;

import cn.idea.dubbo.service.OrderService;
import cn.idea.dubbo.service.UserService;
import cn.idea.dubbo.service.bean.UserAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 *
 * 步骤:
 * 1.让服务提供者注册到注册中心
 *   ● 引入dubbo的依赖
 *   ● 引入ZooKeeper客户端的依赖(curator)
 *   ● 配置服务提供者
 * 2.让服务消费者订阅注册中心的服务提供者的服务地址
 */
@Service
public class OrderServiceImpl implements OrderService {

    /*
        由于此时userService已经存在与容器中了,
        所以可以通过@Autowired注解来实现注入
     */
    @Autowired
    UserService userService;

    public void initOrder(String userId) {

        List<UserAddress> userAddressList = userService.getUserAddressList(userId);
        for(UserAddress userAddress:userAddressList){
            System.out.println(userAddress.getUserAddress());
        }
    }
}

consumer.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!--配置包扫描
    -->
    <context:component-scan base-package="cn.idea.dubbo.service.impl"/>

    <!--消费方的引用名称
    -->
    <dubbo:application name="demo-service-consumer"/>

    <!--注册中心地址
    -->
    <dubbo:registry address="zookeeper://192.168.25.132:2181"/>

    <!--远程服务代理
        引用服务提供方暴露的服务
    -->
    <dubbo:reference interface="cn.idea.dubbo.service.UserService" id="userService"/>
</beans>

MainApplication :

import cn.idea.dubbo.service.OrderService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

public class MainApplication {

    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("consumer.xml");

        OrderService orderService = classPathXmlApplicationContext.getBean(OrderService.class);
        orderService.initOrder("1");
        System.in.read();
    }
}

The pom.xml files of the service provider and the service consumer need to introduce the following dependencies:

<dependencies>
        <dependency>
            <groupId>cn.idea.dubbo</groupId>
            <artifactId>demo-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!--引入dubbo的依赖
        -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.2</version>
        </dependency>

        <!--引入ZooKeeper客户端的依赖
        -->
        <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>
    </dependencies>

 

========>>>>2019 / 03/03 update

3. SpringBoot integrates Dubbo

☞ The first step is to use IDEA to create a SpringBoot project

    ○ Due to the particularity of IDEA, a parent project was created first: boot-user-service-parent

    ○ Create submodule boot-user-service-interface (packaged into jar package)

    ○ Create submodule boot-order-service-consumer ( wrapped into war package )

    ○ Create a submodule boot-user-service-provider (type into a jar)

☞ The second step is to write the program code of the submodule boot-user-service-interface

    ○ " Common Layer " with the same code as above

☞ The third step, configure the submodule boot-user-service-provider, and write the program code

    ○ Add dependency

<dependency>
            <groupId>cn.idea.boot.dubbo</groupId>
            <artifactId>boot-user-service-interface</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba.boot/dubbo-spring-boot-starter -->
        <!--如果是SpringBoot1.x,则使用0.1.0版本的Dubbo
            如果是SpringBoot2.x,则使用0.2.0版本的Dubbo-->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

    ○ Configure application.properties

#服务名称随便定义(服务的名称不可重复),一般取模块名称即可
dubbo.application.name=boot-user-service-provider
#定义使用的协议:这里使用zookeeper
dubbo.registry.protocol=zookeeper
#注册中心的地址,根据自己zookeeper的所在地址来配置
dubbo.registry.address=192.168.25.132:2181
#协议名称为dubbo,根据官方文档来的
dubbo.protocol.name=dubbo
#协议端口为20880,根据官方文档来的
dubbo.protocol.port=20880
#监控器的协议,配置成使用注册中心的即可
dubbo.monitor.protocol=registry

    ○ Write UserServiceImpl

package cn.idea.boot.dubbo.service.impl;

import cn.idea.boot.dubbo.UserService;
import cn.idea.boot.dubbo.bean.UserAddress;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;


@Service  //暴露服务,是Dubbo包下的Service注解
@Component
public class UserServiceImpl implements UserService {

    public List<UserAddress> getUserAddressList(String userId) {
        UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
        return Arrays.asList(address1,address2);
    }
}

    ○ Configure startup annotations

package cn.idea.boot.dubbo;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo  //开启基于注解的Dubbo功能
@SpringBootApplication
public class BootUserServiceProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootUserServiceProviderApplication.class, args);
    }

}

    ○ Run the main method to access the monitoring station

 

 

☞ The fourth step, configure the submodule boot-order-service-consumer, write the program code

    ○ Same as the third step to introduce Dubbo's dependency

    ○ Configure application.properties

dubbo.application.name=demo-service-consumer
dubbo.registry.address=zookeeper://192.168.25.132:2181
dubbo.monitor.protocol=registry

    ○ Write OrderServiceImpl, and need to enable Dubbo-based annotation function in the startup class

package cn.idea.boot.dubbo.service.impl;

import cn.idea.boot.dubbo.OrderService;
import cn.idea.boot.dubbo.UserService;
import cn.idea.boot.dubbo.bean.UserAddress;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class OrderServiceImpl implements OrderService {


    @Reference  //Dubbo的注解,用于远程调用服务
    UserService userService;

    public List<UserAddress> initOrder(String userId) {

        return userService.getUserAddressList(userId);
    }
}

    ○ Run the main method and call the result remotely

4. Dubbo configuration file

The attribute configuration coverage order given on the official website is as follows:

As can be seen from the above figure, the effective priority of dubbo's configuration properties is VM property configuration (system-level configuration at project startup)> application.properties (SpringBoot engineering configuration file)> dubbo.properties (dubbo global configuration file)

    ○ System level configuration

    ○ application.properties configuration (system-level configuration removed)

    ○ Global configuration of dubbo (when application.properties is not configured)

☞ Configured application scenarios (in non-SpringBoot environment)

    ● Check at startup. The default logic of dubbo is that when the consumer starts, it will automatically go to the registry to find out whether the server is started. If the required server does not exist, an error will be reported.

Official document: http://dubbo.apache.org/zh-cn/docs/user/demos/preflight-check.html 

Official document: http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-consumer.html

    ● Timeout attribute, when the server cannot give feedback to the consumer for a long time, a timeout period can be configured. The default timeout period is 1 second

Configured for 5 seconds:

rule:

    ▶ Accuracy first

    ▶ The consumer has priority over the provider

Official document: http://dubbo.apache.org/zh-cn/docs/user/configuration/xml.html

Set the delay to 4 seconds here on the service provider. If the timeout time of the method level (dubbo:method tag) takes effect at this time, an error will be reported; if the timeout time of the interface level (dubbo:reference tag) takes effect, you can get the return Value  // dubbo: consumer is global configuration

After testing, the timeout time of the method level takes effect and an error is reported

When the level is the same, the consumer has priority over the provider

Consumer:

provider:

If the provider is valid, an error will be reported; if the consumer has priority, no error will be reported; after testing, no error will be reported

ps: If they are not at the same level, follow the precise priority rule. That is, if the provider is accurate to a method that sets the timeout time to 3000 milliseconds, and the consumer only sets the timeout time to 5000 milliseconds at the non-method level, since the delay of the program is 4000 milliseconds, the program will report an error according to the principle of precision first. The official graphic clearly specifies this:

    ● The number of retries ( not including the first call ), if the call fails due to some reasons (such as timeout), you can set the number of retries to let the program try more times

Configure the number of timeouts for the consumer (the default is 1 second if the timeout period is not configured):

Print the provider's information (the first call is not included, so a total of 4 times):

 

If there are multiple providers, the call of Dubbo consumer will not hang on a tree, it will automatically try to call other providers

 concept:

Idempotent: In the same situation, no matter how many times the method is called, the effect achieved is the same (such as: query, modify, delete data)

Non-idempotent: In the same situation, no matter how many times the method is called, the effect achieved may or must be different (such as: adding data)

ps: idempotent can set the number of retries, non-idempotent can not set the number of retries

    ● Multiple versions

If a new feature needs to be launched, but it cannot be launched all at once, you can choose to launch it for some users. At this time, you need to use the multi-version version

Provider’s configuration:

Consumer configuration:

Test Results:

Consumer reconfiguration:

Re-test (randomly call the old and new versions, which can be adapted to some people to upgrade the new version):

    ● Local stub

Official document: http://dubbo.apache.org/zh-cn/docs/user/demos/local-stub.html

☞ The first step is to write stub code

package cn.idea.dubbo.service.impl;

import cn.idea.dubbo.service.UserService;
import cn.idea.dubbo.service.bean.UserAddress;
import org.springframework.util.StringUtils;

import java.util.List;

public class UserServiceStub implements UserService {

    private final UserService userService;

    /**
     * 有参构造器用于Dubbo传入远程的代理对象
     *
     * @param userService
     */
    public UserServiceStub(UserService userService) {
        this.userService = userService;
    }

    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("本地存根被调用...");
        if(!StringUtils.isEmpty(userId)){
            return userService.getUserAddressList(userId);
        }
        return null;
    }
}

☞ The second step, configure the reference stub

Test Results:

☞ Three ways to integrate SpringBoot and Dubbo

● The first

Same as above, add dubbo-starter dependency, configure properties in application.properties, use @Service (exposed service) and @Reference (reference service)

ps: Need to use @EnableDubbo in the startup class to enable the annotation function or configure the scan package in the application.properties file (dubbo.scan.base-packages=[package path])

● The second

The first method cannot be controlled at the method level. In order to be able to control the method level, you need to add the dubbo-starter dependency while retaining the dubbo.xml configuration file, and use @ImportResource(locations = "[包Path]") annotation to import

● The third

Use the annotation API to manually add each component to the container

Official document: http://dubbo.apache.org/zh-cn/docs/user/configuration/api.html

                  http://dubbo.apache.org/zh-cn/docs/user/configuration/annotation.html

Example: Create a configuration class

package cn.idea.boot.dubbo.config;

import cn.idea.boot.dubbo.UserService;
import com.alibaba.dubbo.config.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class MyDubboConfig {

    @Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("boot-user-service-provider");
        return applicationConfig;
    }

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("192.168.25.132:2181");
        return registryConfig;
    }

    @Bean
    public ProtocolConfig protocolConfig(){
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20880);
        return protocolConfig;
    }

    @Bean
    public ServiceConfig<UserService> userServiceServiceConfig(UserService userService){
        ServiceConfig<UserService> userServiceServiceConfig = new ServiceConfig();
        userServiceServiceConfig.setInterface(UserService.class);
        userServiceServiceConfig.setRef(userService);
        userServiceServiceConfig.setVersion("1.0.0");

        //配置method信息
        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("getUserAddressList");
        methodConfig.setTimeout(5000);

        //将method的设置保存到userServiceServiceConfig中
        List<MethodConfig> methodConfigs = new ArrayList<>();
        methodConfigs.add(methodConfig);
        userServiceServiceConfig.setMethods(methodConfigs);
        
        return userServiceServiceConfig;

    }
}

Other configurations can be added according to this method, and finally combine the annotation @EnableDubb or @DubboComponentScan in the startup class with the package path.

Attached

☞ High availability and direct connection to Dubbo (usually asked in interviews)

When ZooKeeper goes down, there will be a cache locally, so normal access can still be made without connecting to the ZooKeeper registry

You can also use Dubbo direct connection to achieve access without using ZooKeeper (use SpringBoot for testing)

● The first step is to close ZooKeeper (./zkServer.sh stop)

● The second step is to manually specify the address of the service provider

● The third step is to run the service provider and service consumer, and visit the results:

☞ Dubbo's load balancing mechanism

● Load balancing mechanism based on random weights (Dubbo's default load balancing strategy)

 

● Load balancing mechanism based on weighted polling

● Load balancing mechanism with the least active number

● Load balancing mechanism of consistent hashing

To change the load balance mechanism, please refer to the official document: http://dubbo.apache.org/zh-cn/docs/user/demos/loadbalance.html

The weight of the service can be adjusted on the console, as shown below:

☞ Dubbo's service degradation mechanism

A simple understanding is to reduce part of the non-core business resource output for processing more core business, there are two degradation mechanisms

The first is to return null directly on the client

The second, when the call fails, it returns null

Both of these mechanisms can be set in the ZooKeeper console, as shown below:

Shielding belongs to the first type, and fault tolerance belongs to the second type 

Finish!

Guess you like

Origin blog.csdn.net/ip_JL/article/details/87996952