Source code analysis of the core principle of Dubbo, the RPC framework of the Java underlying architecture

Dubbo is Alibaba's open source distributed service framework. Its biggest feature is that it is structured in a layered manner, which can decouple (or maximize loose coupling) between layers. From the perspective of service model, Dubbo adopts a very simple model, either the provider provides the service or the consumer consumes the service, so based on this, the service provider and the service consumer can be abstracted (Consumer) Two roles.

What is Dubbo

To put it simply, Dubbo is similar to EJB and WebService. When calling a remote service (or JavaBean), there is an interface locally, just like calling a local method. It helps you implement your method at the bottom. The return of parameter transmission and remote service operation results is a kind of encapsulation of RPC~

Of course, this is only the most basic function of Dubbo, its features are:

1. It mainly uses an efficient network framework and serialization framework to make calls between distributed services more efficient.

2. Adopt

Registration Center

Manage many service interface addresses. When you want to call a service, you only need to ask the registration center. You don't need to record the interface calling method for each service like using WebService.

3.

monitoring Center

: Realize the monitoring of the running status between the server and the caller, and also control the priority, authority, weight, online and offline, etc. of the service, making the maintenance and governance of the entire huge distributed service system more convenient.

4. High availability: A service is down? The registry will remove the node from the service list. Or is it called? The client will request another available service node from the registry to call again. The registry is down? The registry can also achieve high availability (ZooKeeper).

5. Load balancing: The soft load balancing algorithm is used to achieve load balancing of requests for multiple nodes with the same service.

Dubbo Registration Center

The zookeeper registration center has been installed and completed. This registration center is mainly responsible for the maintenance of all service address lists of dubbo, and the weight, priority, availability, and availability of this service can be achieved by setting the corresponding values ​​in the ZooKeeper node. Control of routing, permissions, etc.

You can remember first, and then setting and adjusting a bunch of governance policies for services in Dubbo's management console is actually modifying the configuration data corresponding to the service in the registry (that is, modifying the configuration of the node corresponding to the service in zookeeper). data).

Later

Consumer

When the data of the service is requested from the registry, the code execution of the corresponding management configuration parameters can take effect according to the configuration data.

Dubbo sample service development

Here I use maven to build the project and configure Provider and Consumer in the Spring environment.

First describe the dependencies used:

org.springframework

spring-core

4.2.3.RELEASE

org.springframework

spring-beans

4.2.3.RELEASE

org.springframework

spring-context

4.2.3.RELEASE

org.springframework

spring-test

4.2.3.RELEASE

org.springframework

spring-tx

4.2.3.RELEASE

org.springframework

spring-web

4.2.3.RELEASE

org.springframework

spring-webmvc

4.2.3.RELEASE

com.alibaba

dubbo

2.8.4

javassist

javassist

3.12.0.GA

org.jboss.netty

netty

LATEST

com.101tec

zkclient

0.10

org.slf4j

slf4j-log4j12

1.7.12

Provider

Declare the interface of the service:

public interface IMyDemo { String sayHello(String name);

}

Implement the interface (here is the Provider, which needs to be implemented, and after calling the interface on the Consumer side, the implementation code here actually executes the required logic):

public class MyDemo implements IMyDemo { @Override

public String sayHello(String name) {

String hello = "hello " + name;

System.out.println(hello); return hello;

}

}

Test whether this service is available locally. Dubbo has not been used here, but first test whether there is a problem with the Spring container:

@org.junit.Testpublic void testDubbo() throws InterruptedException {

ApplicationContext providerContext = new ClassPathXmlApplicationContext("provider.xml");

IMyDemo demo = providerContext.getBean(IMyDemo.class);

System.out.println(demo.sayHello("world"));

Thread.sleep(60000);

}

Dubbo implementation of RPC

Mainly for three points, dynamic proxy, reflection, socket network programming

I have read a lot of articles on the principle of dubbo, but I always feel that it is too abstract. I accidentally saw a live class teaching the principle of dubbo. Combined with an example of an order on-site brush tool drawing, it is very intuitive. Record the screen shot. (Beijing Shangxuetang of Lao Ma who provided the technical live broadcast, thanks)

The way the client uses a dynamic proxy, "pretends" to implement the createOrder method.

The data related to the method is serialized and entered into the socket server. The socket of dubbo is implemented as Netty.

The server retrieves data from the socket server and finds the "real" service implementation through reflection.

Server-side methods are injected when the service starts.

IMG_4519.PNG

Service discovery layer, zookeeper is available. zookeeper guarantees CP (consistency, partition fault tolerance). Disadvantages: When the master node hangs, it takes time to reselect the master, and the registry will be unavailable during this time.

Note: After the server-side consumer-side registration is successful, the communication only goes through the socket server and does not go through the registration center.

Dubbo

1. Introduction to the core technology of dubbo

The calling process of remote services, dubbo essentially solves this problem.

Remote server call process

1. The client initiates an interface call

2. Service middleware for routing address: find the service address implemented by the specific interface

3. The client encodes the request information (serialization: method name, interface name, parameters, version number, etc.)

4. Establish communication with the server (not the dispatch center, but the direct connection between the client and the server)

5. The server de-encodes (deserializes) the received information

6. Find the interface implementation class of the server according to the information

7. Feedback the execution result to the client

For the above calling process, combined with the service architecture of dubbo, do you have a deeper understanding of dubbo? Students can also implement a simple remote call according to the above process when they are free. The following are some of the core modules of dubbo. Technology, you can make some knowledge reserves in advance.

Core Technology

1.java multithreading

2.JVM

3. Network Communication (NIO)

4. Dynamic proxy

5. Reflection

6. Serialization

7. Routing node management (zookeeper)

2. Common configuration of dubbo in practice

Some common business scenarios and dubbo configurations.

subcontract

It is recommended to put the service interface, service model, service exception, etc. in the API package, because the service model and exception are also part of the API. At the same time, doing so is also in line with the principle of subcontracting: reuse release equivalence principle (REP), common reuse principle (CRP)

If necessary, you can also consider placing a spring reference configuration in the API package, so that the user only needs to refer to this configuration during the Spring loading process. The configuration is recommended to be placed in the package directory of the module to avoid conflicts, such as: com/alibaba/china/xxx/dubbo-reference.xml

granularity

The service interface should be as granular as possible, and each service method should represent a function, not a step of a function, otherwise it will face distributed transaction problems. Dubbo does not provide distributed transaction support yet.

It is recommended to divide service interfaces in units of business scenarios, and abstract similar businesses to prevent the explosion of the number of interfaces

It is not recommended to use too abstract general interfaces, such as: Map query (Map), such interfaces do not have clear semantics, which will bring inconvenience to later maintenance.

Version

Each interface should define a version number to provide the possibility for subsequent incompatible upgrades, such as:

It is recommended to use a two-digit version number, because the third-digit version number usually indicates a compatible upgrade, and the service version needs to be changed only if it is not compatible.

When incompatible, first upgrade half of the providers to the new version, then upgrade all consumers to the new version, and then upgrade the remaining half of the providers to the new version.

compatibility

Adding methods to the service interface or adding fields to the service model can be backward compatible, but deleting methods or deleting fields will be incompatible, and adding fields to enumeration types is also incompatible, and needs to be upgraded by changing the version number.

The compatibility of each protocol is different, see: Service Agreement

enumeration value

If it is a complete set, you can use Enum, for example: ENABLE, DISABLE.

If it is a business type, it will obviously increase the type in the future. It is not recommended to use Enum, but String can be used instead.

If Enum is used in the return value and an Enum value is added, it is recommended to upgrade the service consumer first, so that the service provider will not return the new value.

If an Enum is used in the incoming parameters and an Enum value is added, it is recommended to upgrade the service provider first, so that the service consumer will not pass in the new value.

Serialization

It is recommended to use POJO objects for service parameters and return values, that is, objects that represent properties through set and get methods.

It is not recommended to use interfaces for service parameters and return values, because the abstraction of the data model is of little significance, and serialization requires the meta information of the interface implementation class, which does not serve the purpose of hiding the implementation.

The service parameters and return values ​​must be byValue, not byRef. The parameters or return value references of the consumer and the provider are not the same, but the values ​​are the same. Dubbo does not support referencing remote objects.

abnormal

It is recommended to use exceptions to report errors instead of returning error codes. Exception messages can carry more information and have more friendly semantics.

If you are concerned about performance issues, if necessary, you can override the fillInStackTrace() method of the exception class to an empty method so that it does not copy the stack information.

It is not recommended to throw checked exceptions in the query method, otherwise the caller will have too many try...catch when querying, and it cannot be processed effectively.

The service provider should not throw DAO or SQL exceptions to the consumer, and should package the exceptions that the consumer does not care about in the service implementation, otherwise the consumer may not be able to deserialize the corresponding exception.

transfer

Don't try-catch a call just because it's a Dubbo call. Try-Catch should be added to the appropriate rollback boundaries.

The validation logic for input parameters must be on the Provider side. If there are performance considerations, service implementers can consider adding a service Stub class to the API package to complete the verification.

version control

It is mentioned in the best practice of dubbo that all interfaces should define a version. There are a few points to note here. If the interface service is updated frequently and is compatible with the old version, it is not recommended to change the version number, because the dubbo side does not support the removal of Version numbers other than * are matched by exact matching. That is, if the version number of the server is upgraded from 1.0 to 1.1, and the original 1.0 service is not retained, the client must also upgrade the service version number to 1.1, otherwise it will not be able to match the remote service.

The version usage rules for bloggers in their own projects are as follows, for reference only:

•The version number uses two digits, the first xx of xx indicates that an incompatible upgrade is required, and the second digit indicates a compatible upgrade.

• Bug fix level upgrades do not change the version number

• When the version is upgraded, ensure the continued use of the old version of the service, and deploy the new and old versions at the same time. After the client is fully upgraded, consider removing the old version of the service.

•The version can be configured to specific interfaces, but we recommend to control the version number with a general configuration

Tuning the service

There are many default configurations for dubbo's service calls. These configurations may cause errors in the service call business. Special attention should be paid to the following points:

otimeout, the call timeout time, the default is 1000 milliseconds, that is, if no data is returned for more than 1000 milliseconds, the retry mechanism will be executed

oretries, the number of failed retries, the default is 2, that is, the number of retries after failure (timeout)

oconnections, the maximum number of connections for each provider, the default is 100, it is recommended to adjust according to the server configuration

oloadbalance, load balancing strategy, the default is random

oasync, whether to execute asynchronously, the default is false

odelay, delay the registration service time, the default is 0, it is recommended to stagger the exposure service time for different interfaces to avoid the error of dubbo explosion port being occupied (bloggers have suffered from it)

For the above points, if both the server and the client are configured at the same time, the client has a higher priority.

The following are some common configurations based on our server performance and business needs.

When the execution time of an interface is very long, there are three common ways to deal with it:

•Ignore the return value, configure return to true

• Configured to be asynchronous

• Configured as a callback method

Server configuration:

Interface implementation:

package com.lijian.dubbo.service.impl;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import com.lijian.dubbo.listener.MyListener;

import com.lijian.dubbo.service.CallbackService;

public class CallbackServiceImpl implements CallbackService {

private final Maplisteners = new ConcurrentHashMap();

public CallbackServiceImpl() {

Thread t = new Thread(new Runnable() {

public void run() {

while (true) {

try {

for (Map.Entryentry : listeners

.entrySet()) {

try {

entry.getValue().changed(

getChanged(entry.getKey()));

} catch (Throwable t) {

listeners.remove(entry.getKey());

}

}

Thread.sleep(5000); // Timely trigger change notification

} catch (Throwable t) { // defensive fault tolerance

t.printStackTrace();

}

}

}

});

t.setDaemon(true);

t.start();

}

public void addListener(String key, MyListener listener) {

listeners.put(key, listener);

listener.changed(getChanged(key)); // send change notification

}

private String getChanged(String key) {

return "Changed: "

+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")

.format(new Date());

}

}

Check the parameters

Students who use spring will definitely not be unfamiliar with the @Validated annotation, and they can perform format verification on request parameters:

controller code:

@RequestMapping(value = {""},method = RequestMethod.POST)

@ResponseBody

public GeneralResult addAdvertising(@Validated @RequestBody AdvertisingForm form){

return GeneralResult.newBuilder().setResult(advertisingService.addAdvertising(form));

}

AdvertisingForm part of the code:

public class AdvertisingForm {

@NotEmpty(message = "Title cannot be empty")

private String title;

@NotEmpty(message = "Photo cannot be empty")

private String photo;

...

In dubbo, you can also use the validate function for format verification.

The User class that needs to be verified:

package com.lijian.dubbo.beans;

import java.io.Serializable;

import javax.validation.constraints.Min;

import org.hibernate.validator.constraints.NotEmpty;

public class User implements Serializable{

private static final long serialVersionUID = 8332069385305414629L;

@NotEmpty(message="Name cannot be empty")

private String name;

@Min(value=18,message="Age must be greater than 18")

private Integer age;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

Dubbo's validate configuration:

The interface service is called as follows:

package com.lijian.dubbo.consumer.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.lijian.dubbo.beans.User;

import com.lijian.dubbo.consumer.action.UserAction;

public class ValidateMainClass {

@SuppressWarnings("resource")

public static void main(String[] args){

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

context.start();

UserAction userAction = context.getBean(UserAction.class);

User user = new User();

// If the age is less than 18, Caused by: javax.validation.ConstraintViolationException: Failed to validate service: com.lijian.dubbo.service.ValidateService, method: insert, cause: [ConstraintViolationImpl{interpolatedMessage='The age must be greater than 18 age', propertyPath=age, rootBeanClass=class com.lijian.dubbo.beans.User, messageTemplate='age must be greater than 18'}]

// user.setAge(19);

user.setAge(17);

// If name is empty, Caused by: javax.validation.ConstraintViolationException: Failed to validate service: com.lijian.dubbo.service.ValidateService, method: insert, cause: [ConstraintViolationImpl{interpolatedMessage='Name cannot be empty ', propertyPath=name, rootBeanClass=class com.lijian.dubbo.beans.User, messageTemplate='Name cannot be empty'}]

user.setName("I'm a handsome guy");

System.out.println(userAction.addUser(user));

}

}

I hope everyone can become a better Java programmer and reach the pinnacle of life as an architect!

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324939314&siteId=291194637