前言

最近在阅读字节跳动开源RPC框架Kitex的源码,分析了如何借助命令行,由一个IDL文件,生成clientserver的脚手架代码,也分析了Kitex的日志组件klog。当然Kitex还有许多其他组件:服务注册、发现、负载均衡、熔断、限流等等,后续我也会继续分析。

我希望借助这篇文章,用尽可能少的语言,配合分析Go原生net/rpc包的部分核心代码,帮助你贯通RPC的知识,梳理RPC的运作流程,让你对RPC有一个比较全面的认识。

以此为基础,将有助于你在阅读其他开源RPC框架源码时,对比发掘开源RPC框架具体做了哪些提高。

RPC的流程

远程过程调用 (Remote Procedure Call,RPC) 是一种计算机通信协议。允许运行在一台计算机的程序调用另一个地址空间的子程序(一般是开放网络中的一台计算机),而程序员就像调用调用本地程序一样,无需额外做交互编程。

假设你要调用一个Add(a int, b int) int方法,实现求和功能,但是这个方法部署在另一台机器上,该如何调用?

这就是一次RPC的流程,甚至和HTTP请求/响应流程很像,眼下我先侧重于介绍RPC的概念,以后会介绍其与HTTP的区别。

并且这里暂时没有涉及所谓的服务注册、发现、负载均衡、熔断、限流等字眼,这些都是一个成熟的RPC框架应该具备的功能组件,用于确保一个RPC框架的高可用,但是却不是一个RPC框架所必需的。

RPC协议本质上定义了一种通信的流程,而具体的实现技术是没有约束的,每一种RPC框架都有自己的实现方式,比如你可以规定自己的RPC请求/响应包含消息头和消息体,使用gob/json/pb/thrift来序列化/反序列化消息内容,使用socket/http2进行网络通信,只要clientserver消息的发送和解析能对应即可。希望读者仔细体会——“约定”这个概念,这将贯穿始终。

分析net/rpc

先讲解一下流程图中的序列化和网络传输部分,这是RPC的核心。

消息编码/解码(序列化)

上面的RPC通信流程图,其中很重要的一环就是消息的编解码,消息只有序列化之后,才能高效地参与网络传输。通过实现上图net/rpc包定义的接口,可以指定使用的编解码方式,比如net/rpc包默认使用了gob二进制编码:

服务端负责序列化的结构gobServerCodec的实现了ServerCodec接口,服务端需要编解码消息的地方,都会调用gobServerCodec的对应方法(客户端也是类似的实现,也是一样使用gob编解码)。

消息的网络传输

消息序列化之后,是需要用于网络传输的,涉及到客户端与服务端的通信方式。

这是服务端的接受链接的逻辑,和大部分网络应用相同,server监听了一个ip:port

,然后accept一个连接之后,会开启一个go协程处理请求与响应。

这是客户端发起请求的方式,也印证了socket网络编程的通信模型。

理解了RPC的各个流程之后,就能梳理清楚RPC框架的各种组件是作用在哪个层面的,例如Kitex的网络库netpoll,虽然我未曾看过其源码实现,但是有理由猜测其是在网络通信/传输部分做了提高。

Server端的设计

这是service的结构,可以看到一个服务通过Map可以绑定多个名称的方法,提供调用,且对应service需要提前注册到服务端,这样在客户端请求达到时才能准确调用。

服务注册主要参数是serviceNameservice实体。

  • reflect.xxx():主要的工作就是通过反射的机制,解析所绑定的服务的名称、类型等。
  • suitableMethods():解析一个service绑定的所有method
  • serviceMap.LoadOrStore():将service注册到服务端serverMap,如下是Server的结构:

Client端的设计

这是Client的结构:

  • codec:编解码的具体实现。
  • seqRPC的序列号,每发起一个就计数增加,加入Map,且完成或失败后从Map中移除。
  • pending:配合seq工作的Map

这是客户端具体发起一次RPC请求的过程,当然一次具体的RPC请求可以是同步的,也可以是异步的:

  • client.Go()是异步的。
  • client.Call()是同步的,且其内部就是调用了client.Go(),但是因为其调用之后,在调用完成之前,会被阻塞在chan上,因此后续的RPC请求必须等待发送。

小结

到此为止我们粗浅的分析了net/rpc的一些核心源码,借此梳理了RPC的工作流程,主要包括:

  • RPC的编解码(序列化)协议选择
  • RPC的网络通信/传输模型(Socket编程
  • RPC的请求发起/响应接受(同步/异步)

RPC的功能组件

一个成熟的RPC框架只实现基本的通信功能是不够的,否则它将十分的脆弱,没有任何应对服务宕机的能力,在高并发场景下也难堪重任,因此需要增加很多的功能组件来提高服务的可靠性:

  • 超时控制|请求重试|负载均衡|熔断器|限流器|日志|监控|链路追踪|...

Go原生net/rpc包也有很多提高可靠性的设计,本文没有过多展开)

结束语

这篇文章,我借助Go原生net/rpc包的部分核心源码,梳理了RPC的工作流程,试图帮助你建立RPC的全局观念,希望你明白,RPC框架是对RPC通信流程的具体实现,每一个框架为提高自身的可靠性,又延伸出了多种功能组件。

后续的文章我也将继续分析字节跳动开源RPC框架Kitex的核心组件源码,共勉。

关注公众号【程序员白泽】,我会同步分享博客文章。

rpc的正确打开方式|读懂Go原生net/rpc包的更多相关文章

  1. C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别

    C#语法——泛型的多种应用   本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...

  2. C++11随机数的正确打开方式

    C++11随机数的正确打开方式 在C++11之前,现有的随机数函数都存在一个问题:在利用循环多次获取随机数时,如果程序运行过快或者使用了多线程等方法,srand((unsigned)time(null ...

  3. iOS开发小技巧--相机相册的正确打开方式

    iOS相机相册的正确打开方式- UIImagePickerController 通过指定sourceType来实现打开相册还是相机 UIImagePickerControllerSourceTypeP ...

  4. Xcode 的正确打开方式——Debugging(转载)

    Xcode 的正确打开方式——Debugging   程序员日常开发中有大量时间都会花费在 debug 上,从事 iOS 开发不可避免地需要使用 Xcode.这篇博客就主要介绍了 Xcode 中几种能 ...

  5. InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式

    InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式 https://mp.weixin.qq.com/s/HGa_90XvC22anabiBF8AbQ 在这篇文章里,我将讨论在MySQL 5 ...

  6. Console控制台的正确打开方式

    Console控制台的正确打开方式 console对象提供了访问浏览器调试模式的信息到控制台 -- Console对象 |-- assert() 如果第一个参数断言为false,则在控制台输出错误信息 ...

  7. 任务队列和异步接口的正确打开方式(.NET Core版本)

    任务队列和异步接口的正确打开方式 什么是异步接口? Asynchronous Operations Certain types of operations might require processi ...

  8. (一)Redis for Windows正确打开方式

    目录 (一)Redis for Windows正确打开方式 (二)Redis for 阿里云公网连接 (三)Redis for StackExchange.Redis 下载地址 官网.中文网1 及 中 ...

  9. List的remove()方法的三种正确打开方式

    转: java编程:List的remove()方法的三种正确打开方式! 2018年08月12日 16:26:13 Aries9986 阅读数 2728更多 分类专栏: leetcode刷题   版权声 ...

随机推荐

  1. SVN 添加账号密码的方法(Windows 系统完整版)

    前言: 本人新接了一个项目,目前该项目基本完工,现在想要将该项目上传至SVN上保管,然后设置并添加账号密码信息,以便于后期加入这个项目的小伙伴可以通过新增加的账号密码信息获取到SVN项目,以便后期项目 ...

  2. 设计模式之:享元模式FlyweightPattern的实现

    享元模式的理解: 享元模式的定义:运用共享技术支持大量细粒度对象的复用: Flyweight Pattern Definition:Use sharing to support large numbe ...

  3. FastAPI(七十一)实战开发《在线课程学习系统》接口开发-- 查看留言

    之前FastAPI(七十)实战开发<在线课程学习系统>接口开发--留言功能开发分享了留言开发,这次我们分享查看留言 梳理这里的逻辑,这个接口要依赖登录. 1.判断用户是否登录 2.判断对应 ...

  4. LazyCaptcha自定义随机验证码和字体

    介绍 LazyCaptcha是仿EasyCaptcha和SimpleCaptcha,基于.Net Standard 2.1的图形验证码模块. 目前Gitee 52star, 如果对您有帮助,请不吝啬点 ...

  5. caioj 1001: [视频]实数运算1[水题]

    题意:输入两个实数a和b,输出它们的和 题解:简单题不写题解了-- 代码: #include <cstdio> double a, b; int main() { while (~scan ...

  6. Springcloud报错:java.lang.IllegalStateException: Service id not legal hostname (/a-service)

    今天在做springcloud链路追踪的时候,报错java.lang.IllegalStateException: Service id not legal hostname (/a-service) ...

  7. Python Windows 快捷键自动给剪贴板(复制)图片添加水印

    编写一个能在windows上使用的按下快捷键自动给剪贴板(复制)的图片添加水印的小工具.plyer.PIL.pyinstaller.pynput.win32clipboard库.记录自己踩过的坑,部分 ...

  8. 安卓记账本开发学习day10

    完成了最后一部分功能 1.柱状分析每月的支出或收入 2. 删除所有记录

  9. Casdoor + OAuth 实现单点登录 SSO

    简介 Casdoor 是一个基于 OAuth 2.0 / OIDC 的中心化的单点登录(SSO)身份验证平台,简单来说,就是 Casdoor 可以帮你解决用户管理的难题,你无需开发用户登录.注册等与用 ...

  10. jsp第一周作业

    环境搭建,运行出来一个JSP页面,显式hello 英文字母表 <%@ page language="java" import="java.util.*" ...