Dubbo 中的 URL 统一模型

定义

在不谈及 dubbo 时,我们大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 (RFC1738――Uniform Resource Locators (URL))应该是最广为人知的一个 RFC 规范,它的定义也非常简单

因特网上的可用资源可以用简单字符串来表示,该文档就是描述了这种字符串的语法和语
义。而这些字符串则被称为:“统一资源定位器”(URL)

** 一个标准的 URL 格式 ** 至多可以包含如下的几个部分

1
protocol://username:password@host:port/path?key=value&key=value

设计 RPC 接口时,你有考虑过这些吗?

RPC 框架的讨论一直是各个技术交流群中的热点话题,阿里的 dubbo,新浪微博的 motan,谷歌的 grpc,以及不久前蚂蚁金服开源的 sofa,都是比较出名的 RPC 框架。RPC 框架,或者一部分人习惯称之为服务治理框架,更多的讨论是存在于其技术架构,比如 RPC 的实现原理,RPC 各个分层的意义,具体 RPC 框架的源码分析…但却并没有太多话题和“如何设计 RPC 接口”这样的业务架构相关。


【千米网】从跨语言调用到 dubbo2.js

dubbo2.js千米网 贡献给 dubbo 社区的一款 nodejs dubbo 客户端,它提供了 nodejs 对原生 dubbo 协议的支持,使得 nodejs 和 java 这两种异构语言的 rpc 调用变得便捷,高效。

微服务跨语言调用

微服务架构已成为目前互联网架构的趋势,关于微服务的讨论,几乎占据了各种技术大会的绝大多数版面。国内使用最多的服务治理框架非阿里开源的 dubbo 莫属,千米网也选择了 dubbo 作为微服务治理框架。另一方面,和大多数互联网公司一样,千米的开发语言是多样的,大多数后端业务由 java 支撑,而每个业务线有各自开发语言的选择权,便出现了 nodejs,python,go 多语言调用的问题。


深入理解 RPC 之集群篇

上一篇文章分析了服务的注册与发现,这一篇文章着重分析下 RPC 框架都会用到的集群的相关知识。

集群 (Cluster) 本身并不具备太多知识点,在分布式系统中,集群一般涵盖了负载均衡(LoadBalance),高可用(HA),路由(Route)等等概念,每个 RPC 框架对集群支持的程度不同,本文着重分析前两者 – 负载均衡和高可用。


深入理解 RPC 之服务注册与发现篇

在我们之前 RPC 原理的分析中,主要将笔墨集中在 Client 和 Server 端。而成熟的服务治理框架中不止存在这两个角色,一般还会有一个 Registry(注册中心)的角色。一张图就可以解释注册中心的主要职责。

注册中心的地位

  • 注册中心,用于服务端注册远程服务以及客户端发现服务
  • 服务端,对外提供后台服务,将自己的服务信息注册到注册中心
  • 客户端,从注册中心获取远程服务的注册信息,然后进行远程过程调用

目前主要的注册中心可以借由 zookeeper,eureka,consul,etcd 等开源框架实现。互联网公司也会因为自身业务的特性自研,如美团点评自研的 MNS,新浪微博自研的 vintage。

本文定位是对注册中心有一定了解的读者,所以不过多阐述注册中心的基础概念。


深入理解 RPC 之协议篇

协议(Protocol)是个很广的概念,RPC 被称为远程过程调用协议,HTTP 和 TCP 也是大家熟悉的协议,也有人经常拿 RPC 和 RESTFUL 做对比,后者也可以被理解为一种协议… 我个人偏向于把“协议”理解为不同厂家不同用户之间的“约定”,而在 RPC 中,协议的含义也有多层。

Protocol 在 RPC 中的层次关系

翻看 dubbo 和 motan 两个国内知名度数一数二的 RPC 框架(或者叫服务治理框架可能更合适)的文档,他们都有专门的一章介绍自身对多种协议的支持。RPC 框架是一个分层结构,从我的这个《深入理解 RPC》系列就可以看出,是按照分层来介绍 RPC 的原理的,前面已经介绍过了传输层,序列化层,动态代理层,他们各自负责 RPC 调用生命周期中的一环,而协议层则是凌驾于它们所有层之上的一层。简单描述下各个层之间的关系:

protocol 层主要用于配置 refer(发现服务) 和 exporter(暴露服务) 的实现方式,transport 层定义了传输的方式,codec 层诠释了具体传输过程中报文解析的方式,serialize 层负责将对象转换成字节,以用于传输,proxy 层负责将这些细节屏蔽。

它们的包含关系如下:protocol > transport > codec > serialize

motan 的 Protocol 接口可以佐证这一点:

1
2
3
4
5
public interface Protocol {
<T> Exporter<T> export(Provider<T> provider, URL url);
<T> Referer<T> refer(Class<T> clz, URL url, URL serviceUrl);
void destroy();
}

我们都知道 RPC 框架支持多种协议,由于协议处于框架层次的较高位置,任何一种协议的替换,都可能会导致服务发现和服务注册的方式,传输的方式,以及序列化的方式,而不同的协议也给不同的业务场景带来了更多的选择,下面就来看看一些常用协议。


Motan 中使用异步 RPC 接口

这周六参加了一个美团点评的技术沙龙,其中一位老师在介绍他们自研的 RPC 框架时提到一点:RPC 请求分为 sync,future,callback,oneway,并且需要遵循一个原则:能够异步的地方就不要使用同步。正好最近在优化一个业务场景:在一次页面展示中,需要调用 5 个 RPC 接口,导致页面响应很慢。正好启发了我。

为什么慢?

大多数开源的 RPC 框架实现远程调用的方式都是同步的,假设 [接口 1,…,接口 5] 的每一次调用耗时为 200ms (其中接口 2 依赖接口 1,接口 5 依赖接口 3,接口 4),那么总耗时为 1s,这整个是一个串行的过程。

多线程加速


深入理解 RPC 之传输篇

RPC 被称为“远程过程调用”,表明了一个方法调用会跨越网络,跨越进程,所以传输层是不可或缺的。一说到网络传输,一堆名词就蹦了出来:TCP、UDP、HTTP,同步 or 异步,阻塞 or 非阻塞,长连接 or 短连接…

本文介绍两种传输层的实现:使用 Socket 和使用 Netty。前者实现的是阻塞式的通信,是一个较为简单的传输层实现方式,借此可以了解传输层的工作原理及工作内容;后者是非阻塞式的,在一般的 RPC 场景下,性能会表现的很好,所以被很多开源 RPC 框架作为传输层的实现方式。

RpcRequest 和 RpcResponse

传输层传输的主要对象其实就是这两个类,它们封装了请求 id,方法名,方法参数,返回值,异常等 RPC 调用中需要的一系列信息。

1
2
3
4
5
6
7
8
9
10
public class RpcRequest implements Serializable {
private String interfaceName;
private String methodName;
private String parametersDesc;
private Object[] arguments;
private Map<String, String> attachments;
private int retries = 0;
private long requestId;
private byte rpcProtocolVersion;
}

深入理解 RPC 之动态代理篇

提到 JAVA 中的动态代理,大多数人都不会对 JDK 动态代理感到陌生,Proxy,InvocationHandler 等类都是 J2SE 中的基础概念。动态代理发生在服务调用方 / 客户端,RPC 框架需要解决的一个问题是:像调用本地接口一样调用远程的接口。于是如何组装数据报文,经过网络传输发送至服务提供方,屏蔽远程接口调用的细节,便是动态代理需要做的工作了。RPC 框架中的代理层往往是单独的一层,以方便替换代理方式(如 motan 代理层位于 com.weibo.api.motan.proxy ,dubbo 代理层位于 com.alibaba.dubbo.common.bytecode )。

实现动态代理的方案有下列几种:

  • jdk 动态代理
  • cglib 动态代理
  • javassist 动态代理
  • ASM 字节码
  • javassist 字节码

深入理解 RPC 之序列化篇 -- 总结篇

上一篇 《深入理解 RPC 之序列化篇 –Kryo》, 介绍了序列化的基础概念,并且详细介绍了 Kryo 的一系列特性,在这一篇中,简略的介绍其他常用的序列化器,并对它们进行一些比较。序列化篇仅仅由 Kryo 篇和总结篇构成可能有点突兀,等待后续有时间会补充详细的探讨。

定义抽象接口

1
2
3
4
5
6
public interface Serialization {

byte[] serialize(Object obj) throws IOException;

<T> T deserialize(byte[] bytes, Class<T> clz) throws IOException;
}

RPC 框架中的序列化实现自然是种类多样,但它们必须遵循统一的规范,于是我们使用 Serialization 作为序列化的统一接口,无论何种方案都需要实现该接口。


Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×