说起 RPC (远程过程调用),大家应该不陌生。随着微服务、分布式越来越流行,RPC 应用越来越普遍。常见的 RPC 框架如:Dubbo、gRPC、Thrift 等。本篇文章不是介绍各种 RPC 的使用和对比。而是深入剖析一个 RPC 包含哪些内容。我最近在 Hadoop 的源码,正好把 Hadoop RPC 看完了。感觉 Hadoop 的 RPC 框架设计的还是比价优秀的。Hadoop 作为大数据技术的基石,如果没有一个高性能、高可靠的 RPC 框架,很难支撑上千台服务器规模的集群。因此,本篇文章就以 Hadoop RPC 为例,介绍一个 RPC 框架会涉及的技术。

架构设计

RPC 的架构涉及客户端、网络、服务端三大组件。网络一般使用 socket ,更多的是基于现有的网络框架进行参数的设置达到最优的目的。但是客户端和服务端需要我们自己设计,并且对于分布式框架来说,设计的架构应该有高性能、高可用以及可扩展的特点。

  • 高性能:由于客户端同时发起多个请求,这就要求系统能够快速处理,降低响应延迟。也就是高吞吐、低延迟。从客户端角度来说,由于创建客户端到服务端的连接成本较高。因此可以缓存连接资源,从而实现多个客户端复用相同的连接资源,避免每个客户端都来创建而降低性能;从服务端角度来说,可以启动多线程来并发处理客户端请求。除了多线程,可以采用 Reactor 编程模式,提高多线程并发的性能。
  • 高可用:当我们的服务端挂了,能不能有备用节点继续提供服务。Hadoop 2.x 实现了 NameNode 的高可用。当客户端需要通过 RPC 调用 NameNode 服务的过程中,如果主 NameNode 宕机,那么备用 NameNode 会升级成活动节点。同时会将 RPC 的请求发送的当前活跃的 NameNode,从而继续提供可用的服务,而这个过程对客户端来说是透明的。
  • 可扩展性:一个框架需要不断地优化、不断升级。需要在架构设计时明确不变的需求点,以及可变的需求点,对于可变的需求需要能够有良好的可扩展性。以 RPC 涉及的序列化为例。由于不同序列化框架适用场景不同,因此这需要被当成可变的需求点,应该将其设计成可扩展的,能够容易地支持不同的序列化框架。目前,Hadoop RPC 支持自身的序列化框架(Writable)和 Protoc Buffer。

设计模式

设计模式更多地与上面提到的可扩展性相呼应。良好的设计模式可以提高代码复用性、增强可扩展性,同时能够降低 BUG 数量。Hadoop RPC 中涉及的设计模式比较多,大概包括:工厂模式、代理模式、适配器模式、装饰者模式和命令模式等。以代理模式为例,当客户端调用远程方法时,实际上是通过代理,将方法名和参数通过网络发送到服务端。但这个过程对客户端是透明的,对于客户端来说就像调用本地方法一样。

除了设计模式,在工程实践中还应该注意遵循常见的设计原则。

多线程

在任何一个系统中多线程都比较常见。通过多线程并发处理,提高系统的吞吐量。在 Hadoop RPC 中,客户端与服务端都用到了多线程技术。客户端开启多线程,每个线程处理一类请求,并且缓存连接资源。服务端也是多线程并发处理客户端的请求,使用 Reactor 编程模式提高并发性能。

谈到多线程就不得不提另一个话题 —— 线程安全。Hadoop RPC 中用了不少的技术来保证线程安全,包括:synchronized、concurrent并发包、atomic并发包和 nio 工具包。从优秀框架中学习线程安全,对我们以后并发编程有不少好处。

序列化与反序列化

由于 RPC 涉及数据在网络上传输,因此需要一个优秀的序列化框架,既能够高效的编码与解码,且编码后的数据大小又尽可能小。不同的序列化框架主要是在编解码效率和编码大小两个主要方面做权衡。Hadoop RPC 目前支持两种序列化框架,一个是 Hadoop 自己实现的 Writable 框架,另一个是 Protocol Buffer。Hadoop RPC 虽然支持 Writable 序列化框架,但还是以 Protocol Buffer 为主。因为 Protocol Buffer 从编解码效率和编码大小方便都是比较优秀的。当然常见的序列化包括 Avro、Kryo 等,有兴趣的读者可以查一下它们之间的性能对比。

其他

一个 RPC 框架,除了包含上面提到比较主要的方面。还有一些其他的方面

  • 语言层面:利用好 Java 语言的继承、组合、封装、多态等特性。甚至包括泛型、注解等。
  • 代码规范:良好的工程实现应该有一个良好的代码规范。在 Hadoop 中,代码风格比较统一,且每个重要的类都有详细的注释,在关键的方法或者属性上也有明确的注释。我在自己的工程中会使用阿里的 Java 代码规约插件,也会为了让自己的代码更规范。
  • 异常处理:对于一个优秀的框架异常处理很关键,什么时候需要抛出异常、抛出什么样的异常以及什么时候需要处理异常。在 RPC 中除了需要处理本地异常还要处理远程服务的异常。因此,在程序中如何优雅的处理异常也是体现一个程序员能力的地方。
  • 网络编程:RCP 中涉及的网络编程一般用 socket,Hadoop RPC 使用的 Reactor 模式的网络编程,并且 Netty 也在使用这种框架。我们有必要会用并且掌握它。

这一段写的比较杂,想到哪写到哪。最近有跟朋友聊过在看 RPC 相关的东西,朋友说:“一个 RPC 能够涉及多少东西?值得研究?”。其实我一开始也是这样想的,无非就是客户端将请求序列化,通过网络发给服务端,服务端反序列化调用函数后再返回。但是看了 Hadoop RPC 代码后,我发现这样框架涉及的知识还是特别多的,并且还比较系统,基本上包含了我们平时编程涉及的方方面面。同时它不再是一个单机程序,而是一个 C/S 架构的程序。如果我们有兴趣还可以继续研究他的高可用,从而对分布式应用有更深入的了解。

我觉得 RPC 是麻雀虽小五脏俱全。由于它涉及了我们编程的方方面面,所以我想基于 Hadoop RPC 做一个详细的教程,把它涉及的每个重要部分都进行详细的分析,上面提到的内容基本都会涵盖。对于想了解 RPC 的读者,能够感受到一个 RPC 框架更清晰的面貌。对于仅有 Java 基础的读者来说,能够学到编写一个框架所涉及的具体编程技术,同时能够从世界顶级开源项目学到优秀设计和工程经验。

小结

本篇文章主要介绍了 RPC 框架涉及的知识。包括:架构设计、设计模式以及设计原则、多线程并发以及线程安全、序列化框架和一些其他的内容。我觉得学习最好的方式就是从优秀的框架中学习、模仿。好比我们练书法基本都要经过临摹这一步。当然直接看别人的代码确实需求花费更多的时间和经历,并且有时候投入与产出并不成正比。所以,我想把我在 Hadoop RPC 框架中学到的优秀的设计和实现能够整理成教程,以便有兴趣的读者学习。如果有任何建议欢迎与我交流。公众号有福利

公众号「渡码」

 

RPC - 麻雀虽小,五脏俱全的更多相关文章

  1. 我是这样手写 Spring 的(麻雀虽小五脏俱全)

    人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...

  2. 我是这样手写Spring的,麻雀虽小五脏俱全

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  3. js万年历,麻雀虽小五脏俱全,由原生js编写

    对于前端来说,我们可能见到最多的就是各种各样的框架,各种各样的插件了,有各种各样的功能,比如轮播啊,日历啊,给我们提供了很大的方便,但是呢?我们在用别人这些写好的插件,框架的时候,有没有试着问一问自己 ...

  4. RPC框架原理与实现

    了解一个框架最好的思路就是寻找一个该类型麻雀虽小五脏俱全的开源项目,不负所期,轻量级分布式 RPC 框架 RPC,全称 Remote Procedure Call(远程过程调用),即调用远程计算机上的 ...

  5. 一篇文章了解RPC框架原理

    1.RPC框架的概念 RPC(Remote Procedure Call)–远程过程调用,通过网络通信调用不同的服务,共同支撑一个软件系统,微服务实现的基石技术.使用RPC可以解耦系统,方便维护,同时 ...

  6. 花6个月写的付费专栏,免费送|仿开源框架从零到一完整实现高性能、可扩展的RPC框架

    作者 渡码,阿里巴巴码农,公众号:渡码 作者,专注大数据开发.数据分析和Python技术. 关注公众号 渡码 回复关键字 manis,可获取电子书.各章节和完整源代码,并且可加入读者群一起交流问题. ...

  7. 仿开源框架从零到一完整实现高性能、可扩展的RPC框架 | 6个月做成教程免费送

    去年年就在写一本付费小册,今年年初基本上就写完了,本来预计计划是春节上线结果由于平台的原因一直拖着没上.五一前跟平台联系给的反馈是五月份能上,结果平台又在重构,停止小册的申请和上线,最后我考虑了一下决 ...

  8. 读阿里巴巴Java开发手册v1.2.0之工程结构有感【架构篇】

    首先,把昨天那俩条sql语句的优化原因给大家补充一下,第一条效率极低,第二条优化后的,sql语句截图如下: 经过几个高手的评论和个人的分析: 第一条sql语句查询很慢是因为它首先使用了in关键字查询, ...

  9. [转帖]Windows 内核说明

    来源:https://zhidao.baidu.com/question/398191459.html 自己的理解. windows 的内核文件 是在 c:\windows\system32 目录下面 ...

随机推荐

  1. DHCPv6协议

    DHCPv6协议     1. 定义 IPv6 动态主机配置协议DHCPv6(Dynamic Host Configuration Protocol for IPv6)是针对IPv6编址方案设计,为主 ...

  2. 学霸笔记系列 - Python Selenium项目实战(一)—— 怎么去验证一个按钮是启用的(可点击)?

    Q: 使用 Python Selenium WebDriver 怎么去验证一个按钮是启用的(可点击)? A:Selenium WebDriver API 里面给出了解决方法is_enabled() 使 ...

  3. 根据不同环境配置pom

    clean install clean package -P jt808_dev clean package -P tanway_test -X gps-parent <?xml version ...

  4. 去除 Git 安装后的右键菜单

    64位 windows 8.1 安装 Git 后,右键菜单多了3个选项(Git Init Here,Git Gui, Git Bash),但是用不着,需要删掉.方法如下: 1.在 CMD 中进入 Gi ...

  5. 【Linux】Linux查看程序端口占用情况

    使用命令查询8880端口的占用信息: netstat -naop|grep 查询结果: 发现8880端口被PID为4518的进程占用 使用命令查询所有的进程和端口使用情况: netstat –apn ...

  6. windows 安装python

    前言: Windows 中直接使用Python真的是心累 安装vs 2017(最好是最新版的, 因为python依赖于一些vs提供的包) 下载最新的python的安装程序 安装完毕之后, 不像Linu ...

  7. 冷笑话,idea 按删除键就是undo?

    第一反应是keymap被改了,一看 那么,看起来就是alt出问题了 解决方法 在公司换一个键盘或者狂按alt

  8. 浅析System.Console.WriteLine()

    浅析System.Console.WriteLine() Writeline()函数的功能向 StreamWriter 类写入指定字符串和一行字符,共有19个重载,其与Write()函数的主要区别在于 ...

  9. 在MFC对话框中快速集成三维控件

    在MFC的对话框中可以方便的集成AnyCAD三维控件(c++版本),遵循一下几步: 1.在对话框资源中增加一个Static控件,ID为IDC_STATIC_3D,并且把它的Notify属性设置为Tru ...

  10. Storm里面fieldsGrouping和Field的概念详解

    这个Field通常和fieldsGrouping分组机制一起使用,这个Field特别难理解,我自己也是在网上看了好多文章,感觉依旧讲的不是很清楚,是似而非,没有抓到重点.这个问题足足困扰了我3-4天时 ...