前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >刷题外传之深入浅出 RPC

刷题外传之深入浅出 RPC

作者头像
包子面试培训
发布2018-04-19 11:59:44
6980
发布2018-04-19 11:59:44
举报
文章被收录于专栏:包子铺里聊IT

无论是 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 的原理和基本应用。粗糙之处,也请大家指正。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 包子铺里聊IT 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本地调用的局限
  • RPC
  • 进阶 RPC
  • 尾声
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档