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刷题 版权声 ...
随机推荐
- Spring MVC 工作原理和流程、注解
Spring MVC 是实现MVC设计模式的企业级开发框架,是Spring框架的一个子模块,无需整合,开发起来更加便捷. MVC设计模式 MVC是一种设计模式,它将应用程序分为 Controller. ...
- python数据类型内置的方法
数据类型的内置方法 在日常生活中不同类型的数据具有不同的功能 eg:表格数据文件具有处理表格的各项功能(透视表 图形化 公式计算) 视频数据文件具有快进 加速等各项功能 ... 1.整型int # 方 ...
- Vue_transition动画
1 <!DOCTYPE html> 2 <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml ...
- golang bufio解析
golang bufio 当进行频繁地对少量数据读写时会占用IO,造成性能问题.golang的bufio库使用缓存来一次性进行大块数据的读写,以此降低IO系统调用,提升性能. 在Transport中可 ...
- C/C++指针、函数、结构体、共用体
指针 变量与地址 变量给谁用的? 变量是对某一块空间的抽象命名. 变量名就是你抽象出来的某块空间的别名. 指针就是地址.指向某个地址. 指针与指针变量 指针是指向某块地址.指针(地址)是常量. 指针变 ...
- XCTF练习题---MISC---Recover-Deleted-File
XCTF练习题---MISC---Recover-Deleted-File flag:de6838252f95d3b9e803b28df33b4baa 解题步骤: 1.观察题目,下载附件 2. 根据题 ...
- SDDC的Windows初体验-QT篇
前言 如果熟悉爱智和看过我之前文章的朋友见到这篇文章一定会有很大疑问,SDDC 作为智能设备发现控制协议,怎么会用在 windows 上? 这一切还是源自于我巨大的脑洞,因为这段在搞 Windows ...
- [论文] FRCRN:利用频率递归提升特征表征的单通道语音增强
本文介绍了ICASSP2022 DNS Challenge第二名阿里和新加坡南阳理工大学的技术方案,该方案针对卷积循环网络对频率特征的提取高度受限于卷积编解码器(Convolutional Encod ...
- centos7系统安装 VMware
安装版本: CentOS-7-x86_64-DVD-2009.iso 下载地址:阿里巴巴开源镜像 第一步:打开虚拟机,新建虚拟机引导,选择高级,下一步. 第二步:默认下一步 第三步:选择最后一项, ...
- 一文带你读懂什么是docker
一 简介 1.了解Docker的前生LXC LXC为Linux Container的简写.一种轻量级的内核虚拟化技术,隔离进程和资源. Linux Container有点像chroot,提供了一个拥有 ...