RPC与netty

关于RPC
你的题目是RPC框架,首先了解什么叫RPC,为什么要RPC,RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

比如说,一个方法可能是这样定义的:
Employee getEmployeeByName(String fullName)
那么:

首先,要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。

第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。

第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。

第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。

第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用




为什么RPC呢?就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求,比如比如不同的系统间的通讯,甚至不同的组织间的通讯。由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用,

RPC的协议有很多,比如最早的CORBA,Java RMI,Web Service的RPC风格,Hessian,Thrift,甚至Rest API。






RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

RPC简单的来说就是像调用本地服务一样调用远程服务。

那么,netty是什么东西呢,跟RPC有什么关系?

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序


RPC要做到用户无感知的调用远程服务必定要经过网络传输,而netty正好是是Java编写的快速开发高性能高可靠性的网络编程框架。

目前使用netty作为传输层的RPC框架很多,国内知名的有dubbo,motan等。

下面以新浪开源的motan为例,说明netty在RPC的位置:
下图中transport即使使用netty实现的。


总结来说,netty就是解决RPC网络传输的。


分布式RPC需要解决哪些问题呢?

  1. protocol:传输协议
  2. proxy:client代理,服务引用方调用方法通过代理发送远程消息
  3. codec:协议编解码压缩等
  4. transport:协议传输
  5. registry:注册中心,服务注册服务发现
  6. cluster:负载均衡,服务容错策略
  7. 其他:服务降级,服务隔离,服务治理

如何实现一个分布式的RPC框架呢?

现在互联网已经很少单点服务了,一个好的rpc框架能帮我们省掉很多工作,那么如何撸一个自己喜欢的RPC框架呢?

现在写rpc框架已经不难了,我们可以有很多参考,很多成熟的第三方开源项目可以依赖,可以说是站在巨人的肩膀上。

第一步,选择传输协议:

高性能的rpc和良好的编码协议是分不开的。好的协议不仅耗用流量小,而且序列化和反序列化更快。

现在比较流行的协议有thrift,protobuf,json,restful等。其中thrfit和protobuf性能都比较优异,而且占用空间小,最重要的是跨语言,具有语言平台无关性。但,美中不足的是他们都需要预先根据协议文件预先生成好代码。开发极不流畅。

我们也可以自定义协议,像dubbo和motan一样,定制自己的私有协议,

比如motan协议的header部分如下:


body部分采用hession或者fastjson序列化,

如果不考虑跨语言,这种算是比较完美的解决方案。


定义协议过程中的一些重要且容易忽略的问题:

  • 协议版本号
  • 消息id
  • 协议扩展字段

第二步,协议传输层

一个高性能RPC框架最重要的四个点就是:传输协议,框架线程模型,IO模型,零拷贝。

java程序如果能做好这四点,那么性能应该不会比c++程序差多少。

而作为java开发者,netty正好解决了后三个点,所以使用netty作为RPC框架的传输层会事半功倍。

第三部,注册中心的选择

现在有很多提供服务注册发现的服务,实现成本比较低就是zookeeper,可以很容易的实现服务注册和服务发现的功能。


解决了这三部,后面的就得脚踏实地码代码了,当然后续会有很多细节,不过都不是问题,现在有好多成熟的开源框架可以参考。


当然也可以参考我最近实现的分布式RPC框架,也欢迎提issue(后续会持续优化)。


自己撸一个RPC还是很不错的,如果有兴趣建议自己撸一遍玩玩。


下面是广告时间>>>>>>>>>(顺便把广告也转过来吧~)

dempeZheng/forestRPC 基于netty, spring,轻量的高性能分布式RPC服务框架

Overview

基于netty, spring,轻量的高性能分布式RPC服务框架。简单,易用,高效。

Features

  • 服务端支持多种序列化方式:fastjson,hession,kryo
  • 服务端支持多种压缩方式:gzip,snappy
  • 服务端可根据group进行线程隔离,支持基于spring对不同的group配置不同的业务线程池
  • 支持注解配置,也支持spring xml配置
  • 支持服务发现服务注册
  • client端支持多种负载均衡策略和容灾策略
  • client内置连接池
  • 基于netty 4.x版本实现,高性能(win 8cpu单机8w+)

TODO

  • 服务降级功能
  • http服务支持
  • 跨语言协议支持
  • 服务治理管理后台


作者:郑大侠
链接:https://www.zhihu.com/question/25536695/answer/134976748
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 

没有更多推荐了,返回首页