刷题外传之深入浅出 RPC

无论是 Leetcode 和层出不穷的 Online Judge, 核心是帮助大家锻炼 Coding 和解算法题的能力。 刷题非常有用,如刷题时代的困局所述,未来的趋势是,技术面试以及入职之后的 Ramp-up, 对大家的技术能力要求更高更广。因此我们推出一个新的系列——刷题外传,深入浅出的介绍那些刷题中无法涉及的、在面试和工作中却非常重要的系统知识。

本地调用的局限

很多朋友写起 Leetcode 如占瓜切菜,拿出 Eclipse/IntelliJ 建一个 Solution 类就可以码算法,然后 Main 函数里面放几个 Test case, 跑通了心里的满足感不要不要的。然后大家就觉得,写程序挺简单嘛,写几个类,大不了在 import 几个系统库,调用来调用去,语法没错,逻辑搞对,编译通过了就搞定啦。

真正进入工作了,你耳边想起各种新的词汇,什么 Web Service, RPC, Rest, blabla, 感觉生活不复当初一个 IDE 搞定一切那样美好,你的心中想着,怎么才能 import 这些乱七八糟的 service ? 怎么才能调用它们呢?

OK, 进入正题。初学者、或者大部分学生写过的程序都属于本地调用。

看上面的例子,从 main 到 PrintValue 的调用就是一个典型的本地调用。

当然复杂的例子可以很多,你可以调用各种系统库、第三方库中的类和函数,只要被调用的方法只在本地完成所有实现,那么就是本地调用。

本地调用的假设是所有实现都存在于本地,但这个假设在生产环境中基本不现实。

在真实的场景中,我们喜欢把常用的相对独立的功能单元做成一个服务 (service), 服务的提供者和服务的调用者往往部署在不同的机器上,有不同的团队管理。

这样做的好处很明显:

  • 服务的开发者不需要关心谁调用了它的服务;低耦合;
  • 服务的开发者只需要关心怎样最优化实现自己的服务,且更容易 Scale; 高内聚;
  • 服务的使用者(调用者)不需要关心服务的具体实现;
  • 服务的使用者(调用者)只需要处理好自己的调用链中的逻辑;

RPC

既然跨机器、跨服务的调用有样的好处,怎样实现呢?答案有很多种,RPC (Remote Procedure Call), 提供了一种很有意思的思路。

想象一下跨机器间的调用:底层基础一定是网络编程,机器 A 向机器 B 发送消息,另外机器 B 收到消息后,根据某种协议来做一些事情,比如:

  • 比如进行一个方法的调用
  • 比如对某个资源进行操作

RPC 属于前者,也就是跨机器进行方法的调用。

如图所示,Client / Server routines 可以想象成你的代码。他们通过 Client / Service Stub 和网络协议进行消息传递,看起来好复杂。

为什么设计成这样?Client 的代码直接调用 Service 端的代码不行么?

还是那句话,如果方法的调用者和实现者都在本机,当然可以直接调用(本地调用)。但在网络中传递消息本质上是传输 byte codes, 发消息和收消息的两台机器都需要按同样的规则序列化/反序列化消息内容,类似于编码和解码的过程。

换句话说,假设机器 A 需要调用机器 B 上的一个函数 “function_b”. 那么机器 A 需要把调用的 context (包括函数名,参数信息,调用服务地址,e.g 机器 B 的地址和端口)打包序列化成 byte codes, 通过网络协议传到机器 B, 机器 B 再反序列化获得 context, 执行程序实现,把结果再序列化发回给机器 A.

如果每次 RPC 调用都需要手写这么复杂的序列化、反序列化的过程,那可麻烦死了。

考虑到序列化、反序列化的过程都是类似的,能否把他们抽象出来呢?

没错,这就是上图中 Client / Service Stub 的作用。他们封装了 RPC 调用的序列化以及网络调用的部分,所以调用者只需要像调用本地方法一样调用 Client Stub 上的方法,消息就会顺着 Framework 来到另一端进行处理,结果依同样的路径返回调用者。

RPC 的优雅之处在于其良好的封装性,Client 用类似于本地调用的方式进行了跨机器的操作,代码简洁。测试更是非常直观,Mock 一下 Client Stub 怎么方便怎么测试,真的有助于写出高质量的代码。

进阶 RPC

相信读到此处的读者对于 RPC 已经有了不错的理解。那么为什么圈子里流行着各种各样的 RPC Framework 呢,比如最早的 XML-based RPC, Facebook 开源的 Thrift, Google 开源的 gRPC. 大家都在 re-invert wheels 么?

性能是最大的动力。还是如上图所示,RPC 封装的是系列化和网络传输的部分。先说序列化,XML 是最原始的系列化手段,但是其体积大,传输效率低。所以 Thrift 和 gRPC 都实现了自己的 binary 序列化协议,提升了序列化的效率。

换句话说,传递同样的 Context, 使用 XML 序列化产生的消息大小要超过 Thrift/gRPC.

网络协议也是一个优化的重点。Thrift/gRPC 都是在 TCP 的基础上实现自家的应用层协议,效率高。(如果你还搞不清楚 TCP / HTTP 之间的区别,等包子的系列文章吧)。

此外,很多 RPC Framework 也支持 Stream 操作,即 Client / Server 端可以连续发送几条消息给对方,然后等待回复。在很多需要高性能的场景下,Streaming RPC 是比较不错的选择。

尾声

RPC 是一种非常常见的服务调用方式,这篇文章提供一个简单的切入点,帮助大家理解 RPC 的原理和基本应用。粗糙之处,也请大家指正。

原文发布于微信公众号 - 包子铺里聊IT(baozitraining)

原文发表时间:2016-01-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小樱的经验随笔

BugkuCTF web基础$_GET

前言 写了这么久的web题,算是把它基础部分都刷完了一遍,以下的几天将持续更新BugkuCTF WEB部分的题解,为了不影响阅读,所以每道题的题解都以单独一篇文...

32910
来自专栏Crossin的编程教室

【每周一坑】数路径

加入教室的新同学看这里 ☞ 给新同学:编程教室资源索引 另外一些书籍推荐 ☞ 几个以前发过、回复过很多次、比较有用的学习资源 代码方面的问题,欢迎大家在论坛上发...

3338
来自专栏Python数据科学

Python定期爬取GitHub上每日流行项目

介绍一个在GitHub上看到的通用的python爬虫,难度不大,是一个蛮好玩的点,顺便总结一下python爬虫的一些需要注意的点。

2382
来自专栏玉树芝兰

如何在Jupyter Notebook中使用Python虚拟环境?

如何在使用Jupyter Notebook时,解决Python虚拟环境间的切换问题?本文一步步帮你拆解。希望你能够避免踩坑的痛苦,把更多的时间花在愉快的编程上。

3393
来自专栏程序员互动联盟

程序语言变形记

随着科技的发展我们生活中接触到的应用程序越来越多,它给我们的生活带来了很大的便利。移动端安卓,苹果大肆横行;pc上QQ,浏览器大行天下。我们在享受这些软件给我们...

3335
来自专栏FreeBuf

逆向华为路由器第三部分

引文 在前面两个部分(1,2)已经介绍了UART,BusyBox等部分的逆向调试,而这篇将会开始在流量分析方面下手,来逆向出更多的信息。 正文 请看下图,数据存...

2058
来自专栏LET

CPU Cache简介

真空中光速为299,792,458米/秒,目前,Intel的i7频率可以达到4GHz,简单换算一下,可以得出结论:光(电流)在一个Cycle内移动的距离约为0....

2102
来自专栏炉边夜话

免费的午餐已经结束,你准备好了吗?

2005年3月,C++大师Herb Sutter在Dr.Dobb’s Journal上发表了一篇名为《免费的午餐已经结束》的文章,一石激起千层浪,该文引起了社区...

962
来自专栏zhangdd.com

zabbix监控交换机出图断断续续问题解决

Zabbix通过snmp监控交换机流量时,之前经常出现出图很不稳定的情况。我先对zabbix以及snmp是怎么来监控流量的做个简单的说明:

2964
来自专栏数据小魔方

扒一扒rvest的前世今生!

rvest包可能是R语言中数据抓取使用频率最高的包了,它的知名度和曝光度在知乎的数据分析相关帖子和回答中都很高。 甚至很多爬虫教程和数据分析课程在讲解R语言网络...

3887

扫码关注云+社区

领取腾讯云代金券