大白话带你梳理一下Dubbo的那些事儿
首先声明,本文并不是什么代码实战类型的文章,适合于想对dubbo有更加全面认识的读者阅读,文章不会过于深奥,只是将一系列的知识点串通起来,帮助读者温故而知新。
RPC服务的介绍
相信有过一些分布式开发经历的读者都有用过一些RPC框架,通过框架包装好之后提供的API接口调用远程服务,体验感觉起来就和调用本地服务一样轻松。这么方便好用的技术框架,在实际的开发过程中是如何包装的呢?
很早的时候,国外的工程师设计了一种能够通过A计算机调用B计算机上边应用程序的技术,这种技术不需要开发人员对于网络通讯了解过多,并且调用其他机器上边程序的时候和调用本地的程序一样方便好用。
A机器发起请求去调用B机器程序的时候会被挂起,B机器接收到A机器发起的请求参数之后会做一定的参数转换,最后将对应的程序结果返回给A,这就是最原始的RPC服务调用了。
RPC调用的优势
简单
不需要开发者对于网络通信做过多的设置,例如我们在使用http协议进行远程接口调用的时候,总是会需要编写较多的http协议参数(header,context,Accept-Language,Accept-Encode等等),这些处理对于开发人员来说,实际上都并不是特别友好。但是RPC服务调用框架通常都将这类解析进行了对应的封装,大大降低了开发人员的使用难度。
高效
在网络传输方面,RPC更多是处于应用层和传输层之间。这里我们需要先理清楚一个问题,网络分层。RPC是处于会话层的部分,相比处于应用层的HTTP而言,RPC要比Rest服务调用更加轻便。
常见的远程调用技术
rmi
利用java.rmi包实现,基于Java远程方法协议(Java Remote Method Protocol) 和java的原生序列化。
Hessian
是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。基于HTTP协议,采用二进制编解码。
protobuf-rpc-pro
是一个Java类库,提供了基于 Google 的 Protocol Buffers 协议的远程方法调用的框架。基于 Netty 底层的 NIO 技术。支持 TCP 重用/ keep-alive、SSL加密、RPC 调用取消操作、嵌入式日志等功能。
Thrift
是一种可伸缩的跨语言服务的软件框架。它拥有功能强大的代码生成引擎,无缝地支持C + +,C#,Java,Python和PHP和Ruby。thrift允许你定义一个描述文件,描述数据类型和服务接口。依据该文件,编译器方便地生成RPC客户端和服务器通信代码。
最初由facebook开发用做系统内部语言之间的RPC通信,2007年由facebook贡献到apache基金 ,现在是apache下的opensource之一 。支持多种语言之间的RPC方式的通信:php语言client可以构造一个对象,调用相应的服务方法来调用java语言的服务,跨越语言的C/S RPC调用。底层通讯基于SOCKET。
Avro
出自Hadoop之父Doug Cutting, 在Thrift已经相当流行的情况下推出Avro的目标不仅是提供一套类似Thrift的通讯中间件,更是要建立一个新的,标准性的云计算的数据交换和存储的Protocol。支持HTTP,TCP两种协议。
Dubbo
Dubbo是 阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
上边我们说到了RPC的远程调用发展历史,那么下边我们一起来深入探讨一下RPC的服务。
首先我们来看看OSI的网络协议内容。
OSI的七层网络模型
对于OSI的七层网络模型我绘制了下边的这么一张图:
下边是我个人对于这七层协议的理解:
应用层 主要是对于服务接口的格式多定义,例如提供一定的终端接口暴露给外部应用调用。
表示层 处理一些数据传输的格式转换,例如说编码的统一,加密和解密处理。
会话层 管理用户的会话和对话,建立不同机器之间的会话连接。
传输层 向网络层提供可靠有序的数据包信息。
网络层 真正发送数据包信息的层面,提供流和拥塞控制,从而降低网络的资源损耗。
数据链路层 封装对应的数据包,检测和纠正数据包传输信息。
物理层 通过网络通讯设备发送数据
HTTP & RPC
HTTP主要是位于TCP/IP协议栈的应用层部分,首先需要构建三次握手的链接,接着才能进行数据信息的请求发送,最后进行四次挥手断开链接。
RPC在请求的过程中跨越了传输层和应用层,这是因为它本身是依赖于Socket的原因。(再深入的原因我也不知道)。减少了上边几层的封装,RPC的请求效率自然是要比HTTP高效很多。
那么一个完整的RPC调用应该包含哪些部分呢?
通常我们将一个完整的RPC架构分为了以下几个核心组件:
Server
Client
Server Stub
Client Stub
这四个模块中我稍微说下stub吧。这个单词翻译过来称之为存根。
Client Stub 就是将客户端请求的参数,服务名称,服务地址进行打包,统一发送给server方。
Server Stub 我用通俗易懂的语言来解释就是服务端接收到Client发送的数据之后进行消息解包,调用本地方法。(看过netty拆包机制应该会对这块比较了解)。
Dubbo的核心属性
其实Dubbo配置里面的核心内容就是 服务暴露,服务发现,服务治理。
什么是服务暴露,服务发现,服务治理?
下边我们用一段xml的配置来进行讲解:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="dubbo-invoker-provider">
<dubbo:parameter key="qos.port" value="22222"/>
</dubbo:application>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="20880"/>
<bean id="userService" class="com.sise.user.service.UserServiceImpl" />
<dubbo:service interface="com.sise.user.service.UserService" ref="userService" />
</beans>
在dubbo的配置文件里面,通常我们所说的dubbo:service 可以理解为服务暴露,dubbo:refernce 为服务发现,mock是服务治理,timeout属于服务治理的一种(性能调优).
假设dubbo里面希望将一些公共的配置抽取出来,我们可以通过properties文件进行配置,dubbo在加载配置文件的优先顺序如下:
优先会读取JVM -D启动参数后边的内容
读取xml配置文件
读取properties配置文件内容
dubbo默认会读取dubbo.properties配置文件的信息,例如下边这种配置:
dubbo.application.name=dubbo-user-service
dubbo.registry.address=zookeeper://127.0.0.1:2181
假设我们的dubbo配置文件不命名为dubbo.properties(假设命名为了my-dubbo.properties)的时候,可以在启动参数的后边加上这么一段指令:
-Ddubbo.properties.file=my-dubbo.properties
那么在应用程序启动之后,对应的工程就会读取指定的配置文件,这样就可以将一些共用的dubbo配置给抽取了出来。
XML和配置类的映射
在工作中,我们通常都会通过配置xml的方式来设定一个服务端暴露的服务接口和消费端需要调用的服务信息,这些配置的xml实际上在dubbo的源码中都会被解析为对应的实体类对象。
例如说我们常用到的reference配置类,下边我贴出一段代码:
package com.sise.user.config;
import com.sise.user.service.UserService;
import com.sise.user.service.UserServiceImpl;
import org.apache.dubbo.config.*;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/**
* dubbo里面的自定义配置类
*
* @author idea
* @data 2019/12/29
*/
public class DubboSelfDefConfig {
/**
* dubbo的服务暴露
*/
public void server() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-server-config");
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(20880);
protocolConfig.setThreads(200);
UserService userService = new UserServiceImpl();
ServiceConfig<UserService> serviceConfig = new ServiceConfig<>();
serviceConfig.setApplication(applicationConfig);
serviceConfig.setRegistry(registryConfig);
serviceConfig.setProtocol(protocolConfig);
serviceConfig.setInterface(UserService.class);
serviceConfig.setRef(userService);
serviceConfig.export();
} public void consumer() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-client-config");
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<>();
referenceConfig.setApplication(applicationConfig);
referenceConfig.setRegistry(registryConfig);
referenceConfig.setInterface(UserService.class);
UserService localRef = referenceConfig.get();
localRef.echo("idea");
}
public static void main(String[] args) throws InterruptedException, IOException {
DubboSelfDefConfig d = new DubboSelfDefConfig();
d.consumer();
CountDownLatch countDownLatch = new CountDownLatch(1);
countDownLatch.await();
}
}
在这段代码里面,通过案例可以发现有这些信息内容:
UserService localRef = referenceConfig.get();
localRef.echo("idea");
这两行语句是获取具体服务的核心之处,由于我在别处定义了一个叫做UserService 的公共服务接口,因此在服务引用的过程中可以进行转换。
Dubbo2.7的三大新特新
Dubbo的github官方地址为 https://github.com/apache/dubbo
在这里插入图片描述
Dubbo 目前有如图所示的 5 个分支,其中 2.7.1-release 只是一个临时分支,忽略不计,对其他 4 个分支而言,我归纳了一下,分别有如下信息:
2.5.x 近期已经通过投票,Dubbo 社区即将停止对其的维护。
2.6.x 为长期支持的版本,也是 Dubbo 贡献给 Apache 之前的版本,其包名前缀为:com.alibaba,JDK 版本对应 1.6。
3.x-dev 是前瞻性的版本,对 Dubbo 进行一些高级特性的补充,如支持 rx 特性。
master 为长期支持的版本,版本号为 2.7.x,也是 Dubbo 贡献给 Apache 的开发版本,其包名前缀为:org.apache,JDK 版本对应 1.8。
Dubbo 2.7 新特性
Dubbo 2.7.x 作为 Apache 的孵化版本,除了代码优化之外,还新增了许多重磅的新特性,本文将会介绍其中最典型的2个新特性:
异步化改造
三大中心改造
异步化改造
1.异步化调用的方式,在Dubbo2.7版本里面提供了异步化调用的功能,相关案例代码如下所示:
@RestController
@RequestMapping(value = "/test")
public class TestController {
@Reference(async = true)
private UserService userService; @GetMapping("/testStr")
public String testStr(String param){
return userService.testEcho(param);
}
}
但是通过这种异步发送的方式我们通常都是获取不到响应值的,所以这里的return为null。
如果在低于2.7版本的dubbo框架中希望获取到异步返回的响应值还是需要通过RPC上下文来提取信息。
代码案例如下所示:
@GetMapping("/futureGet")
public String futureGet(String param) throws ExecutionException, InterruptedException {
userService.testEcho(param);
Future<String> future= RpcContext.getContext().getFuture();
String result = future.get();
System.out.println("this is :"+result);
return result;
}
通过RPC上下文的方式可以取到对应的响应值,但是这种方式需要有所等待,因此此时的效率会有所降低。假设我们将dubbo的版本提升到了2.7.1之后,通过使用CompletableFuture来进行接口优化的话,这部分的代码实现就会有所变化:
/**
* @author idea
* @date 2019/12/31
* @Version V1.0
*/
public interface DemoService {
String sayHello(String name) ;
default CompletableFuture<String> sayAsyncHello(String name){
return CompletableFuture.completedFuture(sayHello(name));
}
}
调用方代码:
package com.sise.consumer.controller; import com.sise.dubbo.service.DemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author idea
* @date 2019/12/31
* @Version V1.0
*/
@RestController
@RequestMapping(value = "/demo")
public class DemoController { @Reference
private DemoService demoService; @RequestMapping(value = "/testDemo")
public String testDemo(String name){
System.out.println("【testDemo】 this is :"+name);
return demoService.sayHello(name);
}. @RequestMapping(value = "/testAsyncDemo")
public String testAsyncDemo(String name){
System.out.println("【testAsyncDemo】 this is :"+name);
CompletableFuture<String> future = demoService.sayAsyncHello(name);
AtomicReference<String> result = null;
//通过一条callback线程来处理响应的数据信息
future.whenComplete((retValue,exception)->{
if(exception==null){
System.out.println(retValue);
result.set(retValue);
} else {
exception.printStackTrace();
}
});
return "通过一条callback线程来处理响应的数据信息,所以这个时候获取不到信息响应";
}
}
这样的调用是借助了callback线程来帮我们处理原先的数据内容,关于dubbo里面的异步化调用,我借用了官方的一张图来进行展示:
我们上边讲解的众多方法都只是针对于dubbo的客户端异步化,并没有讲解关于服务端的异步化处理,这是因为结合dubbo的业务线程池模型来思考,服务端的异步化处理比较鸡肋(因为dubbo内部服务端的线程池本身就是异步化调用的了)。
当然dubbo 2.6 里面对于接口异步化调用的配置到了2.7版本依旧有效。
三大中心的改造
注册中心
在dubbo2.7之前,dubbo主要还是由consumer,provider ,register组成,然而在2.7版本之后,dubbo的注册中心被拆解为了三个中心,分别是原先的注册中心和元数据中心以及配置中心。
元数据配置
在dubbo2.7版本中,将原先注册在zk上边的过多数据进行了注册拆分,这样能够保证减少对于zk端的压力。具体配置如下:
<dubbo:registry address=“zookeeper://127.0.0.1:2181” simplified="true"/>
简化了相应配置之后,dubbo也只会上传一些必要的服务治理数据了,简化版本的服务数据只剩下下边这些信息:
dubbo://30.5.120.185:20880/com.sise.TestService?
application=test-provider&
dubbo=2.0.2&
release=2.7.0&
timestamp=1554982201973
对于其他的元数据信息将会被存储到一些元数据中心里面,例如说redis,nacos,zk等
元数据配置改造主要解决的问题是:推送量大 -> 存储数据量大 -> 网络传输量大 -> 延迟严重
配置中心
dubbo2.7开始支持多种分布式配置中心的组件。例如说:zk,Spring Cloud Config, Apollo, Nacos,关于这部分的配置网上的资料也比较多,我就不在这里细说了。
大白话带你梳理一下Dubbo的那些事儿的更多相关文章
- net core体系-web应用程序-4net core2.0大白话带你入门-1目录
asp.net core2.0大白话带你入门 本系列包括: 1.新建asp.net core项目2.web项目目录解读3.配置访问地址4.环境变量详解5.配置文件6.日志7.DI容器8.服务的生命周期 ...
- [转帖]插曲:大白话带你认识Kafka
插曲:大白话带你认识Kafka 2019-11-18 21:58:27 从事Java 阅读数 2更多 分类专栏: java Kafaka 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ...
- [源码分析] 带你梳理 Flink SQL / Table API内部执行流程
[源码分析] 带你梳理 Flink SQL / Table API内部执行流程 目录 [源码分析] 带你梳理 Flink SQL / Table API内部执行流程 0x00 摘要 0x01 Apac ...
- JVM 详解,大白话带你认识 JVM
前言 如果在文中用词或者理解方面出现问题,欢迎指出.此文旨在提及而不深究,但会尽量效率地把知识点都抛出来 一.JVM的基本介绍 JVM 是 Java Virtual Machine 的缩写,它是一个虚 ...
- 大白话带你认识 ZooKeeper !重要概念一网打尽!
大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 1. 前言 相信大家对 ZooKeeper 应该不算陌生.但是你真的了解 ZooKeeper 到底有啥用不?如果别人/面试官让你给他讲讲对于 ...
- net core体系-web应用程序-4net core2.0大白话带你入门-7asp.net core日志组件(Logger和Nlog)
asp.net core日志组件 日志介绍 Logging的使用 1. appsettings.json中Logging的介绍 Logging的配置信息是保存在appsettings.json配置 ...
- net core体系-web应用程序-4net core2.0大白话带你入门-4asp.net core配置项目访问地址
asp.net core配置访问地址 .net core web程序,默认使用kestrel作为web服务器. 配置Kestrel Urls有四种方式,我这里只介绍一种.其它方式可自行百度. 在Pr ...
- net core体系-web应用程序-4net core2.0大白话带你入门-3asp.net core项目架构和配置文件解读
asp.net core web项目目录解读 Connected Services 和传统.net web项目相比,它的功能类似于添加webservice或者wcf service的引用.暂时用不 ...
- net core体系-web应用程序-4net core2.0大白话带你入门-2asp.net core新建项目
新建asp.net core项目 开发环境:Windows Server R2 2008 开发工具:Microsoft Visual Studio 2017 新建asp.net core项目 创建 ...
随机推荐
- C# 16 进制字符串转 int
最近在写硬件,发现有一些测试是做 16 进制的字符串,需要把他转换为整形才可以处理. 本文告诉大家如何从 16 进制转整形 如果输入的是 0xaa 这时转换 int 不能使用 Parse 不然会出现异 ...
- Nutch2.3 编译
$ antBuildfile: build.xmlTrying to override old definition of task javac ivy-probe-antlib: ivy-downl ...
- springboot整合mybatis完整示例, mapper注解方式和xml配置文件方式实现(我们要优雅地编程)
一.注解方式 pom <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId& ...
- C# 单例类
单例类 有时候我们不要在一个程序中创建太多的实例.只想用一个全局的实例和一个可以访问点.那么我们需要一个单例类. 因为是单例类啦,所以构造函数肯定是私有的. 需要了解的术语 懒汉式 顾名思义.什么时候 ...
- P1010 数值交换
题目描述 输入两个数 \(a\) 和 \(b\) ,将两个数交换,并输出交换后的 \(a\) 和 \(b\) . 输入格式 输入两个整数 \(a,b(1 \le a,b \le 10^6)\) 输出格 ...
- H3C端口状态迁移
- H3C备份/恢复下次启动配置文件
- linux alloc_pages 接口
为完整起见, 我们介绍另一个内存分配的接口, 尽管我们不会准备使用它直到 15 章. 现 在, 能够说 struct page 是一个描述一个内存页的内部内核结构. 如同我们将见到的, 在内核中有许多 ...
- java.util.Date和jdk1.8新时间API比拼
旧的时间和日期的API的缺陷 Java 的 java.util.Date 和 java.util.Calendar 类易用性差,不支持时区,而且都不是线程安全的. Date如果不格式化,打印出的日期可 ...
- markdown color
深青色 深蓝色 seagreen darkgreen indianred cornflowerblue lightskyblue coral lightcoral darkorange