Принцип Java RPC и практическое применение Dubbo

Dubbo

[TOC]

1. Принцип RPC

RPC (удаленный вызов процедур) — это удаленный вызов процедуры, то есть два сервера A и B, одно приложение развернуто на сервере A, и если вы хотите вызвать функцию/метод, предоставленную приложением на сервере B, потому что это не в том же пространстве памяти, вы не можете напрямую. Вызов должен выражать семантику вызова и передавать данные вызова через сеть.

1. Рамочный принцип

В структуре RPC есть три основные роли: поставщик, потребитель и реестр. Как показано ниже:

RPC原理

Описание роли узла:

  • Сервер: поставщик услуг, предоставляющий услугу.

  • Клиент: потребитель службы, который вызывает удаленную службу.

  • Реестр: Реестр для регистрации и обнаружения служб.

2. RPC вызывает процесс

RPC调用流程

1.调用客户端句柄;执行传送参数

2.调用本地系统内核发送网络消息

3.消息传送到远程主机

4.服务器句柄得到消息并取得参数

5.执行远程过程

6.执行的过程将结果返回服务器句柄

7.服务器句柄返回结果,调用远程系统内核

8.消息传回本地主机

9.客户句柄由内核接收消息

10.客户接收句柄返回的数据

3. Регистрация и обнаружение службы

После того, как поставщик услуг запустится, он будет активно регистрировать ip машины, порт и список услуг, предоставляемых центром регистрации;

Когда потребитель услуг запускается, он получает список адресов поставщика услуг из центра регистрации, который может реализовать мягкую балансировку нагрузки и аварийное переключение;

2. Используемые технические точки

1、动态代理

生成 client stub和server stub需要用到 Java 动态代理技术 ,我们可以使用JDK原生的动态代理机制,可以使用一些开源字节码工具框架 如:CgLib、Javassist等。

2、序列化

为了能在网络上传输和接收 Java对象,我们需要对它进行 序列化和反序列化操作。

* 序列化:将Java对象转换成byte[]的过程,也就是编码的过程;

* 反序列化:将byte[]转换成Java对象的过程;

可以使用Java原生的序列化机制,但是效率非常低,推荐使用一些开源的、成熟的序列化技术,例如:protobuf、Thrift、hessian、Kryo、Msgpack

关于序列化工具性能比较可以参考:jvm-serializers

3、NIO

当前很多RPC框架都直接基于netty这一IO通信框架,比如阿里巴巴的HSF、dubbo,Hadoop Avro,推荐使用Netty 作为底层通信框架。

4、服务注册中心

Дополнительные технологии:

  • Redis

  • Zookeeper

  • Consul

  • Etcd

5. Функциональные цели RPC

Основная функциональная цель ПК — упростить создание распределенных вычислений (приложений), предоставляя при этом мощные возможности удаленного вызова без ущерба для семантической простоты локальных вызовов. Для достижения этой цели инфраструктура RPC должна предоставлять прозрачный механизм вызовов, чтобы пользователям не приходилось явно различать локальные вызовы и удаленные вызовы. Ниже мы подробно рассмотрим реализацию тупиковой структуры.

6. Классификация вызовов RPC

Существует два типа вызовов RPC:

1. 同步调用
客户方等待调用执行完成并返回结果。
2. 异步调用
客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。 若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。

7. Разделение структуры RPC

RPC结构拆分

Сервер RPC экспортирует (экспортирует) методы удаленного интерфейса через RpcServer, а клиентская сторона импортирует (импортирует) методы удаленного интерфейса через RpcClient. Клиентская сторона вызывает метод удаленного интерфейса точно так же, как вызов локального метода.Среда RPC предоставляет прокси-реализацию интерфейса, и фактический вызов будет делегирован прокси-серверу RpcProxy. Прокси инкапсулирует информацию о вызове и перенаправляет вызов RpcInvoker для фактического выполнения. RpcInvoker на стороне клиента поддерживает канал RpcChannel с сервером через соединитель RpcConnector и использует RpcProtocol для кодирования протокола (кодирования) и отправки закодированного сообщения запроса на сервер через канал.

Приемник RPC-сервера RpcAcceptor принимает запрос клиента на вызов, а также использует RpcProtocol для выполнения декодирования протокола (декодирования). Информация о декодированном вызове передается RpcProcessor для управления процессом обработки вызова и, наконец, делегирования вызова RpcInvoker для фактического выполнения и возврата результата вызова.

8. Фреймворк RPC, обычно используемый в Java

Более того, в среде Java RPC есть свои особенности, там широко используются RMI, Hessian, Dubbo и другие.

8. Отличный фреймворк RPC с открытым исходным кодом

2. Фреймворк Даббо

1. Введение в фреймворк

1.1 Основное введение

Dubbo — это основная структура решения управления на основе сервисов SOA от Alibaba.Он поддерживает более 3 000 000 000 посещений в день для более чем 2 000 сервисов и широко используется на различных сайтах-членах Alibaba Group. Dubbo[] — это инфраструктура распределенных сервисов, предназначенная для предоставления высокопроизводительных и прозрачных решений удаленного вызова RPC-сервисов, а также решений для управления сервисами SOA.

Его основные части включают в себя:

  • Удаленный коммуникация: Предоставление различных кадра NIO-пакета длины пакета абстрактная модель соединения содержит множество нитей, сериализацию и - режим обмена информацией «Запрос-ответ».
  • Отказоустойчивость кластера: обеспечивает прозрачные удаленные вызовы процедур на основе методов интерфейса, включая поддержку нескольких протоколов и поддержку кластера, такую ​​как программная балансировка нагрузки, отказоустойчивость, маршрутизация адресов и динамическая конфигурация.
  • Автоматическое обнаружение: на основе службы каталогов реестра потребитель службы может динамически находить поставщика услуг, делая адрес прозрачным, чтобы поставщик услуг мог плавно увеличивать или уменьшать количество компьютеров.

1.2 Предыстория

С развитием Интернета масштаб веб-приложений продолжает расширяться, и традиционная вертикальная архитектура приложений больше не может справляться.Обязательны архитектура распределенных услуг и архитектура мобильных вычислений, и срочно необходима система управления для обеспечения упорядоченной эволюции архитектура.

Когда сервисов становится все больше и больше, управление конфигурацией URL-адресов сервисов становится очень сложным, а единая точка давления на аппаратный балансировщик нагрузки F5 также увеличивается.

С дальнейшим развитием зависимости между услугами становятся сложными и неправильно понятыми, и даже не ясно, какое применение должно быть запущено, прежде чем приложение, и архитекторы не могут полностью описать архитектурные отношения приложения.

Затем объем вызовов службы увеличивается, и возникает проблема пропускной способности службы. Сколько машин требуется для этой службы? Когда следует добавить машину?

1.3Архитектура Дуббо

Dubbo结构

Dubbo架构

Dubbo

Описание роли узла:

  • Поставщик: поставщик услуг, предоставляющий услугу.
  • Потребитель: потребитель службы, который вызывает удаленную службу.
  • Реестр: Реестр для регистрации и обнаружения служб.
  • Монитор: центр мониторинга, который подсчитывает время вызова и время вызова службы.
  • Контейнер: запуск контейнерных сервисов. Связь вызова Описание
0. 服务容器负责启动,加载,运行服务提供者。

1. 服务提供者在启动时,向注册中心注册自己提供的服务。

2. 服务消费者在启动时,向注册中心订阅自己所需的服务。

3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

В-третьих, пример проекта

1.1 Введение в проект

Этот проект основан на SpringBoot, интегрирует aliaba dubbo-spring-boot-stater, не использует последний инкубационный проект Apache Dubbo в качестве среды построения и использует стиль внедрения. может быть введен в узел zookeeper. Полный исходный код проекта Адрес GitHub:Dubbo-SpringBoot

1.2 Описание модуля проекта

Модули проекта разделены на три модуля: dubbo-api, springBoot-dubbo-consumer и springboot-dubbo-provider.Интерфейс извлекается как dubbo-api, который удобно использовать потребителям и реализовывать провайдеру. Структура проекта показана на следующем рисунке:

AoKy8g.png
Подробное описание структуры выглядит следующим образом:

.Dubbo
├── dubbo-api
│   ├── dubboapi.iml
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   └── test
│   └── target
│       ├── classes
│       ├── generated-sources
│       └── maven-status
├── Dubbo.iml
├── pom.xml
├── springboot-dubbo-consumer
│   ├── HELP.md
│   ├── pom.xml
│   ├── springboot-dubbo-consumer.iml
│   ├── src
│   │   ├── main
│   │   └── test
│   └── target
│       ├── classes
│       ├── generated-sources
│       ├── generated-test-sources
│       ├── maven-archiver
│       ├── maven-status
│       ├── springboot-dubbo-consumer-0.0.1-SNAPSHOT.jar
│       ├── springboot-dubbo-consumer-0.0.1-SNAPSHOT.jar.original
│       ├── surefire-reports
│       └── test-classes
└── springboot-dubbo-provider
    ├── HELP.md
    ├── pom.xml
    ├── springboot-dubbo-provider.iml
    ├── src
    │   ├── main
    │   └── test
    └── target
        ├── classes
        ├── generated-sources
        ├── generated-test-sources
        ├── maven-archiver
        ├── maven-status
        ├── springboot-dubbo-provider-0.0.1-SNAPSHOT.jar
        ├── springboot-dubbo-provider-0.0.1-SNAPSHOT.jar.original
        ├── surefire-reports
        └── test-classes

1.3 Строительство проекта

  • Step1:

Idea создает пустой проект maven, создает модуль maven dubbo-api и создает интерфейс RemoteUserService в dubbo-api для вызовов потребителей и реализаций провайдеров.

package com.yongliang.dubbo.api;

/**
 * @version 1.0.0
 */
public interface RemoteUserService {
    String sayHello(String name);
}
  • Step 2:

Создайте модуль springBoot springboot-dubbo-provider и настройте информацию pom.xml следующим образом:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yongliang.dubbo</groupId>
    <artifactId>springboot-dubbo-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-dubbo-provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>
        <!-- dubbo依赖 -->
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>Dubbo</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>25.1-jre</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Отредактируйте файл application.properties и добавьте параметры конфигурации dubbo.

server.port=8082
server.servlet.context-path=/DubboProvider
## dubbo 
spring.dubbo.application.id=dubbo-provider
spring.dubbo.application.name=dubbo-provider
#spring.dubbo.provider.filter=dubboLogFilter
# zookeeper 注册信息
spring.dubbo.registry.address=zookeeper://10.18.33.158:2181
spring.dubbo.server=true
通信协议
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20880

Добавить автоматические аннотации dubbo в запись запуска

package com.yongliang.dubbo.provider;

import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubboConfiguration
@SpringBootApplication
public class SpringbootDubboProviderApplication {

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

}

Реализовать интерфейс RemoteUserService в модуле провайдера

package com.yongliang.dubbo.provider.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yongliang.dubbo.api.RemoteUserService;
import org.springframework.stereotype.Component;

/**
 * @author zhangyongliang
 * @create 2019-04-08 18:44
 **/
@Service(interfaceClass = RemoteUserService.class,retries = 0,version = "1.0.0")
@Component
public class RemoteServiceimpl implements RemoteUserService {
    @Override
    public String sayHello(String name) {
        return "Hello"+name;
    }
}

Повторяет логотип, повторяет количество раз после сбоя. Версия представляет реализацию интерфейса, этот номер версии соответствует фактическим зависимостям потребителя.

  • Step3:

Создать Transboot-Dubbo-потребительский модуль потребительского потребителя, информация о конфигурации POM.XML выглядит следующим образом:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yongliang.dubbo</groupId>
    <artifactId>springboot-dubbo-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-dubbo-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>Dubbo</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Измените файл application.properties и добавьте соответствующую информацию о конфигурации dubbo.

server.port=8081
server.servlet.context-path=/DubboConsumer
## dubbo
spring.dubbo.application.name=dubbo-consumer
spring.dubbo.application.id=dubbo-consumer
spring.dubbo.registry.address=zookeeper://10.18.33.158:2181
spring.dubbo.consumer.check=false
spring.dubbo.reference.check=false

Добавьте аннотации автоматической настройки dubbo в запись запуска.

package com.yongliang.dubbo.consumer;

import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubboConfiguration
@SpringBootApplication
public class SpringbootDubboConsumerApplication {

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

}

Реализуйте класс управления Rest и реализуйте вызовы методов:

package com.yongliang.dubbo.consumer.rest;

import com.alibaba.dubbo.config.annotation.Reference;
import com.yongliang.dubbo.api.RemoteUserService;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhangyongliang
 * @create 2019-04-08 18:48
 **/
@RestController
public class RemoteUserRest  {
    @Reference(version = "1.0.0")
    private RemoteUserService remoteUserService;

    @GetMapping("/dubboTest")
    public String dubboTest() {
        return remoteUserService.sayHello("dubbo");
    }
}

打开浏览器访问:localhost:8081/DubboConsumer/dubboTest

Возврат после успешного запроса: HelloDubbo доказывает, что интеграция Dubbo прошла успешно. Этот процесс не описывает информацию о конфигурации родительского pom.xml, и читатели сами обращаются к организации исходного кода.