rpc的正确打开方式|读懂Go原生net/rpc包
前言
最近在阅读字节跳动开源RPC框架Kitex的源码,分析了如何借助命令行,由一个IDL文件,生成client
和server
的脚手架代码,也分析了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
进行网络通信,只要client
和server
消息的发送和解析能对应即可。希望读者仔细体会——“约定”这个概念,这将贯穿始终。
分析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
需要提前注册到服务端,这样在客户端请求达到时才能准确调用。
服务注册主要参数是serviceName
和service
实体。
reflect.xxx()
:主要的工作就是通过反射的机制,解析所绑定的服务的名称、类型等。
suitableMethods()
:解析一个service
绑定的所有method
。
serviceMap.LoadOrStore()
:将service
注册到服务端server
的Map,如下是Server
的结构:
Client端的设计
这是Client
的结构:
codec
:编解码的具体实现。seq
:RPC的序列号,每发起一个就计数增加,加入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包的更多相关文章
- C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别
C#语法——泛型的多种应用 本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...
- C++11随机数的正确打开方式
C++11随机数的正确打开方式 在C++11之前,现有的随机数函数都存在一个问题:在利用循环多次获取随机数时,如果程序运行过快或者使用了多线程等方法,srand((unsigned)time(null ...
- iOS开发小技巧--相机相册的正确打开方式
iOS相机相册的正确打开方式- UIImagePickerController 通过指定sourceType来实现打开相册还是相机 UIImagePickerControllerSourceTypeP ...
- Xcode 的正确打开方式——Debugging(转载)
Xcode 的正确打开方式——Debugging 程序员日常开发中有大量时间都会花费在 debug 上,从事 iOS 开发不可避免地需要使用 Xcode.这篇博客就主要介绍了 Xcode 中几种能 ...
- InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式
InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式 https://mp.weixin.qq.com/s/HGa_90XvC22anabiBF8AbQ 在这篇文章里,我将讨论在MySQL 5 ...
- Console控制台的正确打开方式
Console控制台的正确打开方式 console对象提供了访问浏览器调试模式的信息到控制台 -- Console对象 |-- assert() 如果第一个参数断言为false,则在控制台输出错误信息 ...
- 任务队列和异步接口的正确打开方式(.NET Core版本)
任务队列和异步接口的正确打开方式 什么是异步接口? Asynchronous Operations Certain types of operations might require processi ...
- (一)Redis for Windows正确打开方式
目录 (一)Redis for Windows正确打开方式 (二)Redis for 阿里云公网连接 (三)Redis for StackExchange.Redis 下载地址 官网.中文网1 及 中 ...
- List的remove()方法的三种正确打开方式
转: java编程:List的remove()方法的三种正确打开方式! 2018年08月12日 16:26:13 Aries9986 阅读数 2728更多 分类专栏: leetcode刷题 版权声 ...
随机推荐
- 小程序中引入iconfont
注释:本人喜欢 font class, 你们可以依葫芦画瓢unicode和 symbol,,下面是 font class 演示: 1.选择好图标,然后: font class 2.步骤二: 复制 ...
- scss使用方法以及相关内容
我们平时都称之为 Sass,其实可分成sass和scss, 其中Sass 是以严格的缩进式语法规则来书写,不带大括号({})和分号(;),以".sass"后缀为扩展名:而 SCSS ...
- python---希尔排序的实现
def shell_sort(alist): """希尔排序""" n = len(alist) gap = n // 2 # 插入算法执行 ...
- centos7 安装樱桃树cherrytree
樱桃树对于做笔记或者编程来说都是很好的工具.以前再网上找了很久还是稿不懂cherrytree的方法.后来才发现,其实根本就不用那么麻烦.直接在epel源里面安装句可以了. 下面说下安装步骤: 第一步: ...
- spatialite-tools 安装
spatialite-tools 安装 官网 https://www.gaia-gis.it/fossil/spatialite-tools/index 下载地址 https://www.gaia-g ...
- uniapp报错:Browserslist: caniuse-lite is outdated. Please run next command `npm update`
uni-app的编译器是基于npm的,依赖了众多包括mpvue.webpack在内的npm库,这些库又引用了一个三方库caniuser-lite.caniuser-lite这个库的代码里有个浏览器兼容 ...
- 用 getElementsByTagName() 来获取,父元素指定的子元素
1. html 结构 <ul> <li>知否知否,应是等你好久11</li> <li>知否知否,应是等你好久11</li> <li&g ...
- vue3 数据可视化项目
可视化面板介绍 应对现在数据可视化的趋势,越来越多企业需要在很多场景(营销数据,生产数据,用户数据)下使用,可视化图表来展示体现数据,让数据更加直观,数据特点更加突出. 01-使用技术 完成该项目 ...
- Linux应急响应入门——入侵排查
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 账号安全: 1.用户信息文件 /etc/passwd # ...
- Android8.0 后台服务保活的一种思路
原文地址:Android8.0 后台服务保活的一种思路 | Stars-One的杂货小窝 项目中有个MQ服务,需要一直连着,接收到消息会发送语音,且手机要在锁屏也要实现此功能 目前是使用广播机制实现, ...