Apache Dubbo basic usage

Distributed RPC framework Apache Dubbo

Introduction to Dubbo

Apache Dubbo is a high-performance Java RPC framework. Its predecessor is Alibaba's open source and lightweight open source Java RPC framework, which can be seamlessly integrated with the Spring framework. In 2018, Alibaba donated this framework to the apache foundation.

What is RPC?

The full name of RPC is remote procedure call, that is, remote procedure call. For example, there are two servers A and B. an application is deployed on server A and an application is deployed on server B. The Application on server A wants to call the methods provided by the application on server B. because the two applications are not in the same memory space and cannot be called directly, it is necessary to express the calling semantics and convey the calling data through the network.

It should be noted that RPC is not a specific technology, but refers to the whole network remote call process.

RPC is a generalized concept. Strictly speaking, all remote procedure call methods belong to the category of RPC. Various development languages have their own RPC framework. There are many RPC frameworks in Java, such as RMI, Hessian, Dubbo, etc.

Dubbo official website address: http://dubbo.apache.org
Dubbo provides three core capabilities: interface oriented remote method invocation, intelligent fault tolerance and load balancing, and automatic service registration and discovery.

Dubbo's architecture


Node role description:
Provider: the service provider that exposes the service
Consumer: the service consumer that calls the remote service
Registry: the registry for service registration and discovery
Monitor: the monitoring center that counts the number and time of service calls
Container: service running container

The dashed lines are asynchronous access, and the solid lines are synchronous access. The blue dashed lines: functions completed at startup. The red dashed lines (solid lines) are functions executed during program operation

Description of calling relationship:
0. The service container is responsible for starting, loading and running the service provider.

  1. When a service provider starts, it registers its services with the registry.
  2. When the service consumer starts, it subscribes to the service it needs from the registry.
  3. The registry returns the service provider address list to the consumer. If there is any change, the registry will push the change data to the consumer based on the long connection.
  4. From the provider address list, the service consumer selects one provider to call based on the soft load balancing algorithm. If the call fails, it selects another provider to call.
  5. Service consumers and providers accumulate call times and call times in memory, and regularly send statistical data to the monitoring center every minute.

Dubbo adopts the full Spring configuration mode, transparently accesses the application, and does not have any API intrusion into the application. It only needs Spring to load Dubbo's configuration, and Dubbo is loaded based on Spring's Schema extension. If you do not want to use Spring configuration, but want to call through API (not recommended)
Dubbo adopts the full Spring configuration mode, transparently accesses the application, and does not have any API intrusion into the application. It only needs Spring to load Dubbo's configuration, and Dubbo is loaded based on Spring's Schema extension.

Service registry Zookeeper

As can be seen from the previous Dubbo architecture diagram, Registry (service registry) plays a vital role. Dubbo officially recommends Zookeeper as the service registry.

Zookeeper introduction

Zookeeper is a sub project of Apache Hadoop. It is a tree type directory service that supports change push. It is suitable to be used as the registry of Dubbo service. It has high industrial intensity, can be used in production environment, and is recommended.
In order to understand Zookeeper's tree directory service, let's take a look at our computer's file system (also a tree directory structure):

My computer can be divided into multiple drive letters (for example, C, D, E, etc.), multiple directories can be created under each drive letter. Files or subdirectories can be created under each directory, and finally a tree structure is formed. Through this tree structure directory, we can store files by categories, which is convenient for us to find later. Moreover, each file on the disk has a unique access path For example: C: \ windows \ KKB \ hello txt.
Zookeeper tree directory service:
Process Description:
When a service provider starts: to / Dubbo / com foo. Write your own URL address in the barservice / providers directory
When a service consumer starts: Subscribe / Dubbo / com foo. The URL address of the provider in the barservice / providers directory. And to / Dubbo / com foo. Write your own URL address in the barservice / consumers directory
When the monitoring center starts: subscribe to / Dubbo / com foo. URL addresses of all providers and consumers under the barservice directory

Installing Zookeeper

Download address: http://archive.apache.org/dist/zookeeper/

The Zookeeper version used here is 3.4 6. After downloading, you can get the name Zookeeper-3.4 6.tar. GZ compressed file.

Step 1: install jdk (omitted)
Step 2: upload the zoomeeper compressed package (zoomeeper-3.4.6. Tar. GZ) to the linux system
Step 3: unzip the compressed package tar -zxvf zookeeper-3.4 6.tar. gz -C /usr
Step 4: enter zookeeper-3.4 6 directory, create the data directory mkdir data
Step 5: enter the conf directory and put zoo_sample.cfg is renamed zoo cfg cd conf
mv zoo_sample.cfg zoo.cfg
Step 6: open zoo Cfg file, modify the data attribute dataDir = / usr / zookeeper3 4.6/data

Start and stop Zookeeper

Enter the bin directory of Zookeeper and start the service command/ zkServer.sh start
Stop service command/ zkServer.sh stop
View service status:/ zkServer.sh status
Client connection
./zkCli.sh

Dubbo quick start

As an RPC framework, Dubbo's core function is to realize cross network remote call. This section is to create two applications, one as a service provider and the other as a service consumer. Dubbo enables the service consumer to remotely call the method of the service provider.

Service provider development

  1. Create a maven project (packaged as war) dubcodemo_provider, and import the following coordinates in the pom.xml file
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wh</groupId>
    <artifactId>dubbodemo-provider</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.0.5.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- dubbo relevant -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.7</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
    </dependencies>
    <build>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
    <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <configuration>
    <!-- Specify port -->
        <port>8081</port>
        <!-- Request path -->
        <path>/</path>
    </configuration>
    </plugin>
    </plugins>
    </build>
</project>
  1. Configure web XML file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>Archetype Created Web Application</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>
  1. Create service interface
public interface HelloService {
    public String sayHello(String name);
}
  1. Create service implementation class
@Service
public class HelloServiceImpl implements HelloService {
    public String sayHello(String name) {
        return "hello " + name;
    }
}

Note: the Service annotation used on the Service implementation class is provided by Dubbo and is used to publish services

  1. Create ApplicationContext service under src/main/resources 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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- The current application name is used to calculate the dependency between applications in the registry. Note: the application names of consumers and providers are different -->
    <dubbo:application name="dubbodemo_provider" />
    <!-- Connect service registry zookeeper ip by zookeeper Server ip address-->
    <dubbo:registry address="zookeeper://192.168.229.128:2181"/>
    <!-- Registration agreement and port -->
    <dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
    <!-- Scan the specified package and join@Service Annotated classes are published as services -->
    <dubbo:annotation package="com.wh.service.impl" />
</beans>
  1. Start service
    tomcat7:run

Service consumer development

  1. Create a maven project (packaged as war) dubnodemo_consumer. The pom.xml configuration is the same as the above service provider. You only need to change the port number of Tomcat plug-in to 8082
  2. Configure web XML file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>Archetype Created Web Application</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- Specify the configuration file to load through parameters contextConfigLocation load -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext-web.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. Copy the HelloService interface in the service provider project to the current project

  2. Write Controller

@Controller
@RequestMapping("/demo")
public class HelloController {
    @Reference
    private HelloService helloService;
    @RequestMapping("/hello")
    @ResponseBody
    public String getName(String name){
//Remote call
        String result = helloService.sayHello(name);
        System.out.println(result);
        return result;
    }
}

Note: the @ Reference annotation provided by Dubbo is used to inject HelloService into the Controller

  1. Create ApplicationContext web under src/main/resources 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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- The current application name is used to calculate the dependency between applications in the registry. Note: the application names of consumers and providers are different -->
    <dubbo:application name="dubbodemo_consumer" />
    <!-- Connect service registry zookeeper ip by zookeeper Server ip address-->
    <dubbo:registry address="zookeeper://192.168.229.128:2181"/>
    <!-- Scan the specified package and join@Service Annotated classes are published as services -->
    <dubbo:annotation package="com.wh.controller" />
</beans>
  1. Run test
    tomcat7:run start
    Enter in the browser http://localhost:8082/demo/hello.do?name=Jack , view the browser output

    View console results

Dubbo management console

During development, we need to know which services are registered in the Zookeeper registry and which consumers consume these services. We can do this by deploying a management center. In fact, the management center is a web application, which can be deployed to tomcat.

install

Installation steps:
(1) Copy the dubbo-admin-2.6.0.war file to the webapps directory of tomcat
(2) Start tomcat and the war file will be decompressed automatically
(3) Modify the dubbo.properties file under WEB-INF. note that the value corresponding to dubbo.registry.address needs to correspond to the ip address and port number of the Zookeeper currently used
dubbo.registry.address=zookeeper://192.168.xxx.xxx:2181 dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
(4) Restart tomcat

use

visit http://localhost:8080/dubbo-admin-2.6.0 /, enter the user name (root) and password (root)

Start the service provider project and the service consumer project to view the corresponding information


Dubbo configuration description

Packet scanning

<dubbo:annotation package="com.wh.service" />

Both service providers and service consumers need to be configured to represent package scanning, which is used to scan classes under specified packages (including sub packages).
If package scanning is not used, services can also be published through the following configuration:

<bean id="helloService" class="com.wh.service.impl.HelloServiceImpl" />
<dubbo:service interface="com.wh.api.HelloService" ref="helloService" />

As a service consumer, services can be referenced through the following configuration:

<!-- Generate a remote service proxy, which can communicate with local bean Same use helloService -->
<dubbo:reference id="helloService" interface="com.wh.api.HelloService" />

The above method publishes and references services. A configuration item (dubbo:service, dubbo:reference) can only publish or reference one service. If there are multiple services, this method is cumbersome. Package scanning is recommended.

agreement

<dubbo:protocol name="dubbo" port="20880"/>

Generally, it is configured on the service provider side, and the protocol name and port number can be specified.
The protocols supported by Dubbo include Dubbo, rmi, hessian, http, webservice, rest, redis, etc. Dubbo protocol is recommended.
dubbo protocol adopts
Single long connection and NIO asynchronous communication are suitable for small amount of data, large amount of concurrent service calls, and the number of service consumer machines is much larger than that of service provider machines. It is not suitable for services that transmit large amounts of data, such as files and videos, unless the request volume is very low.
Multiple protocols can also be configured in the same project. Different services can use different protocols, for example:

<!-- Multi protocol configuration -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />
<!-- use dubbo Protocol exposure service -->
<dubbo:service interface="com.wh.api.HelloService" ref="helloService"
protocol="dubbo" />
<!-- use rmi Protocol exposure service -->
<dubbo:service interface="com.wh.api.DemoService" ref="demoService"
protocol="rmi" />

load balancing

Load Balance: in fact, requests are allocated to multiple operating units for execution, so as to complete work tasks together
Business.
In cluster load balancing, Dubbo provides a variety of balancing strategies (including random, polling, minimum number of active calls, and consistency)
Hash), the default is random.
The load balancing policy can be configured either on the service provider side or on the service consumer side, as follows:

@Controller
@RequestMapping("/demo")
public class HelloController {
	//Configure the load balancing policy on the service consumer side
	@Reference(check = false,loadbalance = "random")
	private HelloService helloService;
	
	@RequestMapping("/hello")
	@ResponseBody
	public String getName(String name){
		//Remote call
		String result = helloService.sayHello(name);
		System.out.println(result);
		return result;
	}
}
//Configure load balancing on the service provider side
@Service(loadbalance = "random")
public class HelloServiceImpl implements HelloService {
	public String sayHello(String name) {
		return "hello " + name;
	}
}

You can observe the effect of Dubbo load balancing by starting multiple service providers.
Note: since we start multiple service providers on one machine, we need to modify the port number of tomcat and the port number of Dubbo service to prevent port conflict.
In the actual production environment, multiple service providers are deployed on different machines, so there is no port conflict.

Solve the problem that Dubbo cannot publish the Service proxied by the transaction

We have completed the introduction case of Dubbo. Through the introduction case, we can see that the package can be scanned through the label configuration provided by Dubbo, and the classes scanned to the @ Service annotation can be published as services.
However, if we add the @ Transactional transaction control annotation to the service provider class, the service will not be published successfully. The reason is that the underlying principle of transaction control is to create a proxy object for the service provider class. By default, Spring creates a proxy object based on JDK dynamic proxy, and the complete class name of this proxy object is com sun. proxy.$ Proxy42 (the last two digits are not fixed), which makes Dubbo unable to complete the package matching before publishing the service, so it does not publish the service.

Solution:
(1) Modify the applicationContext-service.xml configuration file. When the transaction control annotation support is enabled, specify the proxy target class attribute with the value of true. Its purpose is to create a proxy object for the Service class using the cglib proxy method

<!--Enable annotation support for transaction control-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-targetclass="true"/>

(2) Modify the HelloServiceImpl class and add the interfaceClass attribute in the Service annotation with the value HelloService.class to specify the interface type of the Service

@Service(interfaceClass = HelloService.class)
@Transactional
public class HelloServiceImpl implements HelloService {
	public String sayHello(String name) {
		return "hello " + name;
	}
}

This must also be modified. Otherwise, the published service interface will be SpringProxy instead of HelloService interface, as follows:

Keywords: Java Dubbo Spring IDEA

Added by serious1234 on Mon, 20 Dec 2021 17:52:14 +0200