origin

The evolution of application architecture

Single application Architecture

When site traffic is low, only one application is needed to deploy all functions together to reduce deployment nodes and costs. At this point, data access frameworks (ORM) that simplify the work of adding, deleting, modifying and reviewing are key.

Vertical application Architecture

When the volume of traffic gradually increases, the acceleration caused by the increase of a single application machine is getting smaller and smaller. The application is divided into several unrelated applications to improve efficiency. At this point, a Web framework (MVC) for accelerating front-end page development is key.

Distributed Service Architecture

With the increasing number of vertical applications, the interaction between applications is inevitable. Core businesses are extracted as independent services, gradually forming a stable service center, so that front-end applications can respond to changing market demands more quickly. At this point, the distributed Services framework (RPC) for business reuse and integration is key.

Mobile Computing Architecture

As the number of services increases, problems such as capacity evaluation and waste of small service resources gradually emerge. In this case, a scheduling center needs to be added to manage cluster capacity in real time based on access pressure to improve cluster utilization. At this point, a resource scheduling and Governance center (SOA) for improving machine utilization is key.

The concept of RPC (Remote procedure call)

RPC is introduced

Remote Procedure Call, which is the core of distributed architecture, can be divided into the following two response modes:

Synchronous invocation: The client invokes the server method, waits until the server returns a result or times out, and then continues its operation.

Asynchronous invocation: The client sends the message to the middleware, does not wait for the server to return, and continues its operation.

  • It is a form of communication between processes
  • It allows an application to invoke methods in another application on the network
  • For the consumer of the service, there is no need to know the low-level details of the remote invocation and it is transparent

It is important to note that RPC is not a specific technology, but refers to the entire network remote call process.

RPC is a general concept. Strictly speaking, all remote procedure call means belong to RPC. Each development language has its own RPC framework. There are many RPC frameworks in Java, such as RMI, Hessian and Dubbo.

The RPC component

To put it simply, an RPC architecture contains the following four components:

1. Client: the service caller

2. Client Stub: Stores the address information of the service end, packages the request parameters of the Client into network messages, and sends them to the service side through the network

3. The Server Stub accepts the message sent by the client, unpacks the message, and invokes the local service

4. Server: Service provider.

RPC calls

1. A service caller (client) invocation invokes a service locally.

2. After receiving the call, the Client Stub is responsible for assembling methods and parameters into a message body that can be transmitted over the network

In Java, this is serialization

3. The Client stub finds the service address and sends the message to the server over the network.

4. After receiving the message, the Server stub decodes it, which is the process of deserialization in Java.

5. The Server Stub invokes the local service according to the decoding result.

6. Local service execution processing logic;

7. The local service returns the result to the server stub.

8. The Server Stub packages the returned result into a message, which is serialized in Java.

9. The Server Stub sends the packaged message to the consumer over the network.

10. The Client stub receives the message, decodes it, and deserializes it in Java.

11. The service caller (client) gets the final result.

The introduction of dubbo

The Apache Dubbo overview

Introduction of Dubbo

Apache Dubbo is a high-performance Java RPC framework. Its predecessor is a high-performance, lightweight open source Java RPC framework developed by Alibaba, which can be seamlessly integrated with Spring framework.

Dubbo’s website is 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 architecture

The Dubbo architecture diagram (provided by Dubbo) is as follows:

Node roles:

node Character name
Provider The service provider that exposes the service
Consumer Service consumer that invokes the remote service
Registry A registry for service registration and discovery
Monitor A monitoring center that collects statistics on service invocation times and invocation time
Container Service run container

Dotted lines are all asynchronous access, solid lines are all synchronous access blue dotted lines: Functions that are completed at startup Red dotted lines (solid lines) are functions that are performed while the program is running

Call relationship description:

  1. The service container is responsible for starting, loading, and running the service provider.
  2. At startup, service providers register their services with the registry.
  3. At startup, service consumers subscribe to the registry for the services they need.
  4. The registry returns a list of service provider addresses to the consumer, and if there are changes, the registry pushes the change data to the consumer based on the long connection.
  5. The service consumer, from the provider address list, selects one provider to call based on the soft load balancing algorithm. If the call fails, selects another one to call.
  6. Service consumers and providers accumulate calls and call times in memory and regularly send statistics to the monitoring center every minute.

The Zookeeper registry

Dubbo will use the registry, and ZooKeeper is officially recommended

Zookeeper hierarchical namespace:

Process description:

  • When the service Provider is started: to/dubbo/com.foo.BarService/providersWrite your OWN URL address in the directory
  • Service Consumer at launch: Subscribe/dubbo/com.foo.BarService/providersThe provider URL in the directory. And to the/dubbo/com.foo.BarService/consumersWrite your OWN URL address in the directory
  • When Monitor starts: Subscribe/dubbo/com.foo.BarServiceAll provider and consumer urls under the directory

A simple Demo

The directory structure is as follows:



There are three modules

  • helloworld-interface
  • helloworld-provider
  • helloworld-consumer

Helloworld-consumer and HelloWorld-Provider import helloWorld-Interface

There is no interdependence between helloworld-consumer and Helloworld-provider

The implementation uses dubbo to cause the helloController in HelloWorld-Consumer to call the HelloService.sayHello () method in helloWorld-Provider

Pom configuration file

  • Project pom. The XML file

      
<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>org.example</groupId>
    <artifactId>dubbo-helloworld-demo</artifactId>
    <version>1.0 the SNAPSHOT</version>
    <modules>
        <module>helloworld-interface</module>
        <module>helloworld-provider</module>
        <module>helloworld-consumer</module>
    </modules>

    <packaging>pom</packaging>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.1.6. RELEASE</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo</artifactId>
                <version>2.6.2</version>
            </dependency>

            <dependency>
                <groupId>org.apache.curator</groupId>
                <artifactId>curator-framework</artifactId>
                <version>2.12.0</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>
Copy the code
  • Hello – the provider pom. The XML file

      
<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">
    <parent>
        <artifactId>dubbo-helloworld-demo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0 the SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>helloworld-provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>helloworld-interface</artifactId>
            <version>1.0 the SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
    </dependencies>
</project>
Copy the code
  • The helloworld – consumer pom. The XML file

      
<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">
    <parent>
        <artifactId>dubbo-helloworld-demo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0 the SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>helloworld-consumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>helloworld-interface</artifactId>
            <version>1.0 the SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
    </dependencies>


</project>
Copy the code

helloworld-interface

HelloService .java

public interface HelloService {
    public String sayHello(String name);
}
Copy the code

helloworld-provider

  • spring-provider.xml

      
<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <! -- Provider application information for calculating dependencies -->
    <dubbo:application name="provider"/>
    <! Expose the service address using the ZooKeeper broadcast registry -->
    <dubbo:registry address=Zookeeper: / / "127.0.0.1:2181"/>
    <! -- Exposed service on port 12880 with dubbo
    <dubbo:protocol name="dubbo" port="12880"/>

    <bean id="helloService" class="com.kehao.service.impl.HelloServiceImpl"/>
    <! Declare the service interface to be exposed -->
    <dubbo:service interface="com.kehao.service.HelloService" ref="helloService"/>

</beans>
Copy the code
  • HelloServiceImpl.java
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        System.out.println("service:hello!");
        return "Hello,"+name; }}Copy the code
  • ProviderApplication.java
public class ProviderApplication {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-provider.xml");
        context.start();
        System.out.println("Provider startup complete!"); System.in.read(); }}Copy the code

helloworld-consumer

  • spring-consumer.xml

      
<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <! -- Consumer application name, used to calculate dependencies, not matching conditions, not the same as provider -->
    <dubbo:application name="provider"/>
    <! Expose discovery service address using zooKeeper broadcast registry -->
    <dubbo:registry address=Zookeeper: / / "127.0.0.1:2181"/>
    <! Create a remote service proxy that can use demoService as a local bean -->
    <dubbo:reference interface="com.kehao.service.HelloService" id="helloService"/>

    <bean id="helloController" class="com.kehao.controller.HelloController">
        <property name="helloService" ref="helloService"/>
    </bean>

</beans>
Copy the code
  • HelloController.java
public class HelloController {

    private HelloService helloService;

    public void sayHello(a){
        String sentence = helloService.sayHello("kehao");
        System.out.println(sentence);
    }

    public void setHelloService(HelloService helloService) {
        this.helloService = helloService; }}Copy the code
  • ConsumerApplicaiton.java
public class ConsumerApplication {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-consumer.xml");
        HelloController helloController = context.getBean(HelloController.class);
        helloController.sayHello();
        System.out.println("Provider runs complete"); System.in.read(); }}Copy the code

Running results:



Dubo-helloworld-demo complete code: dubo-helloworld-demo

Configuration method for Dubbo annotations

Make some changes based on the above code

The modification of consumer

Modify spring-privider. XML to change the configuration specific interface exposure to a scanning approach

    <! Declare the service interface to be exposed -->
<! -- <dubbo:service interface="com.kehao.service.HelloService" ref="helloService"/>-->
    <dubbo:annotation package="com.kehao.service.impl"/>
Copy the code

Add @ Service comments here on HelloServiceImpl class @ Service annotations, is not under the spring package, but com. Alibaba. Dubbo. Config. The annotation. Service

import com.alibaba.dubbo.config.annotation.Service;
import com.kehao.service.HelloService;

@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        System.out.println("service:hello!");
        return "Hello,"+name; }}Copy the code

The provider of modified

Modify the spring-provider. XML file to change the original bean object acquisition to annotation scan acquisition and helloService object acquisition to dubbo scan injection

<! -- <dubbo:reference interface="com.kehao.service.HelloService" id="helloService"/>-->
    <dubbo:annotation package="com.kehao.controller"/>

    <context:component-scan base-package="com.kehao.controller"/>

<! -- <bean id="helloController" class="com.kehao.controller.HelloController">-->
<! -- <property name="helloService" ref="helloService"/>-->
<! -- </bean>-->
Copy the code

Modify the HelloController class by adding @Component annotations to the class and @Reference to the member variables for injection

import com.alibaba.dubbo.config.annotation.Reference;
import com.kehao.service.HelloService;
import org.springframework.stereotype.Component;

@Component
public class HelloController {

    @Reference
    private HelloService helloService;

    public void sayHello(a){
        String sentence = helloService.sayHello("kehao");
        System.out.println(sentence);
    }

    public void setHelloService(HelloService helloService) {
        this.helloService = helloService; }}Copy the code

Dubo-helloworld-demo-anno complete code: dubo-helloworld-demo-anno