专栏首页架构师程序员修神之路--设计一套RPC框架并非易事

程序员修神之路--设计一套RPC框架并非易事

菜菜哥,我最近终于把Socket通信调通了

这么底层的东西你现在都会了,恭喜你离涨薪又进一步呀

http协议不也是利用的Socket吗

可以这么说,http协议是基于TCP协议的,底层的数据传输可以说是利用的socket

既然Socket通信会了,那一个rpc的框架不就很容易就能实现了吗

一个比较完备的rpc框架可能并非像你所想那样简单,要不然人人都可以出RPC框架了

有那么难吗?我觉得没有那么难呀

RPC是远程过程调用(Remote Procedure Call)的缩写形式,是在多任务操作系统或联网的计算机之间运行的程序和进程所的通信技术

01

开局

撸码的人都应该知道,现代编程中最常用的系统之间通信方式是:http调用和rpc调用。对于同一个网络或者说是互通的网络环境中,rpc调用方式是系统间通信交互最常用的方式,比基于http协议的通信方式性能高出数倍甚至数个量级。我司的平台rpc通信,每秒在几万甚至更高,每次调用的通信时间在一定程度上几乎可以忽略不计,再加上我们首席架构师深厚的系统设计功力,采用进程内缓存等等优化措施,一次rpc调用的整体平均时间也在一毫秒之下。这是http协议无法达到的速度,如果你在浏览器的F12的窗口观察过,一个http协议调用如果整体花费的时间在5毫秒甚至10毫秒,那么其实就可以认为这个http请求响应时间是很短的了。

所以绝大部分公司内部的系统之间通信都会采用rpc调用这种方式。这里不要抬杠,如果你的公司内部系统通信采用的是基于http协议的,那说明你们的系统很有可能没有性能的要求。

RPC调用虽然简化了撸码的难度,但是想要实现一套rpc框架,何止容易,一套优秀的rpc框架,更是难如登天。

01

连接服务

多数rpc框架的服务端以service的方式来运行,为了避免和其他进程发生监听端口的冲突,一般会随机选择一个端口来进行监听。虽然这看上去很好,但是却给client端带来了麻烦,如果服务端监听固定端口,client连接服务端的时候,最少可以在代码中固定写死服务端的IP和端口。但是现在服务端监听的端口是随机的,而且更可怕的是服务器有可能会更换或者切换IP,那client怎么才能正确的去和服务端建立连接呢?

服务端之所以会采用这种随机方式来监听端口,其中很大一个原因是为了以后扩容。client如何正确的去连接服务器则采用了一个集中式的方案,服务端引入了一个服务注册中心的概念,有的系统可能会以别的名称来体现,但是作用是类似的。这个注册中心存储着所有的服务端信息,其中包括每个服务端的IP和端口,有的甚至还有版本信息,每个服务端进程启动的时候,都是采用主动连接注册中心,主动注册的方式。client端在发起连接服务的时候,首先去注册中心查找已经注册的服务端信息,然后进行连接。这样rpc调用在某种程度上在连接步骤就实现了“自动化”。

02

调用方法

当client和服务端建立tcp连接之后(有的rpc框架会采用udp协议),下一个问题就是client和服务端怎么相认的问题了。举个栗子:客户端想要实现一个获取用户姓名的方法,方法名怎么定义才能让服务端正确识别出来呢?是传一个字符串“GetName”,还是传一个整数1来代表呢?服务端的返回结果,如果发生异常改如何返回呢?

当我们在本地调用一个函数,语法,语义,以及语法语义的分析,编译器已经帮我们做好了这些,但是rpc是远程过程调用,虽然表面上和本地类似,但是已经出现了跨网络的情况,语法语义等等这些分析需要client和服务端协商一致。

其实现代几乎大部分rpc通信都遵循一个标准:

当client发起一个远程调用的时候,它首先会先调用本地的Stub,它负责将调用的接口,函数以及参数按照约定好的协议格式进行编码,然后通过本地的Runtime进行传输,最后通过网卡将数据包发送到指定的服务器。

服务器Runtime接收到请求之后,会首先调用本地的Stub按照约定好的协议格式进行解码,最后调用服务端具体的函数。函数执行完毕,把结果利用本地的Stub编码之后通过runtime发送给客户端。客户端Runtime接收到消息利用本地Stub进行解码,然后进行其他处理。

由此可见,现代的rpc框架其实是把协议的封装和数据的发送分别抽象成了单独的层。Stub负责协议部分,Runtime处理数据发送以及网络相关部分。

03

网络数据传输

数据通过网络传输过程中,每个数据包的完整性如何来识别,如果是一个简单int型数据很简单,但是如果是一个类或者一个数组,甚至是其他变长的类型,rpc的通信协议如何约束这些,如果能正确识别出来数据是协议部分最难处理的部分。更何况还有大头小头编码的问题。

凡是基于网络传输的形式,任何通信都是不可靠的,网络本质是不可靠的。包括网络抖动,错误等造成的丢包,粘包现象,如何正确的处理也是一个rpc通信中很重要的部分。一个rpc请求失败,是直接丢弃还是重试,这些策略都需要去规定。

04

性能

1.一个rpc调用如果采用同步的方式,性能会大大打折扣,如何实现rpc的异步调用,这是一个rpc是否优秀的重要指标。

2.无论rpc的网络传输多么优秀,都会有性能损耗,能否把某些结果数据设置缓存?

3.无论是client还是服务端,处理请求的线程能否重用(线程池)?

4.能否支持多语言呢?

socket虽易,RPC却难

本文分享自微信公众号 - 架构师修行之路(jiagoushixiuxing),作者:菜v菜

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-14

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 程序员过关斩将-- 工作好多年可能还未真正了解接口和抽象类

    在面向对象编程的语言中,多数都添加了对抽象类和接口的支持,比如最常用的java,C#等语言。

    架构师修行之路
  • 程序员修神之路--高并发下为什么更喜欢进程内缓存

    从前有个机构,机构的主人叫做 CPU,这个机构专门派仆人取一些东西然后做相应的处理。下面是这个机构日常的场景。

    架构师修行之路
  • 一文带你全面了解虚拟机的四种网络模型(图文并茂)

    著名的「六度分隔定理」说到,世界上任何两个互不相识的人,只需要最多六个人就能够建立起联系。这个定理成立的前提就是依托于庞大的网络结构。

    架构师修行之路
  • Java 基础巩固:再谈抽象类和接口

    文章出自:安卓进阶学习指南 主要贡献者: Milo Struggle shixinzhang 背景介绍 ? 大家好,这篇文章是 《安卓进阶技能树计划》 的...

    张拭心 shixinzhang
  • 这个前端竟然用动态规划写瀑布流布局?给我打死他!

    瀑布流布局是前端领域中一个很常见的需求,由于图片的高度是不一致的,所以在多列布局中默认布局下很难获得满意的排列。

    ssh1995
  • 第十八节:详解Java抽象类和接口的区别

    在Java中,实现抽象的机制分两种,一为抽象类,二为接口。 抽象类为abstract class,接口为Interface。

    达达前端
  • 接口和抽象类,傻傻分不清楚?

    兄弟们,你们怎么看,这段解释把我绕得晕乎乎的,好像喝过一斤二锅头。到底是解释抽象类呢还是接口呢?傻傻分不清楚。

    沉默王二
  • 一文彻底搞懂抽象类和接口!

    最近一些刚入门JAVA的读者朋友让我来写一篇有关于抽象类和接口的文章,我当即就答应了,因为抽象类和接口确实是两个很重要但是一时半会又无法完全理解的...

    Python进击者
  • 【竞赛】一种提升多分类准确性的Trick

    随机森林是一种高效并且可扩展性较好的算法, K最近邻算法则是一种简单并且可解释较强的非参数化算法。在本篇文章中,我们针对多分类问题提出了一种将随机森林和KNN算...

    yuquanle
  • 百度输入法每天语音被调度3.35亿次!又一个AI赋能的样板

    8月1日,百度发布了2018年二季度财报。财报显示,百度二季度营收260亿元人民币,同比增长32%,净利润64亿人民币,同比增长45%,移动端收入占比77%,高...

    罗超频道

扫码关注云+社区

领取腾讯云代金券