程序员修神之路--设计一套RPC框架并非易事
菜菜哥,我最近终于把Socket通信调通了

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

http协议不也是利用的Socket吗

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

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

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

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

如果你能解决掉这些问题,我觉得你真的是大牛了

RPC是远程过程调用(Remote Procedure Call)的缩写形式,是在多任务操作系统或联网的计算机之间运行的程序和进程所用的通信技术
撸码的人都应该知道,现代编程中最常用的系统之间通信方式是:http调用和rpc调用。对于同一个网络或者说是互通的网络环境中,rpc调用方式是系统间通信交互最常用的方式,比基于http协议的通信方式性能高出数倍甚至数个量级。我司的平台rpc通信,每秒在几万甚至更高,每次调用的通信时间在一定程度上几乎可以忽略不计,再加上我们首席架构师深厚的系统设计功力,采用进程内缓存等等优化措施,一次rpc调用的整体平均时间也在一毫秒之下。这是http协议无法达到的速度,如果你在浏览器的F12的窗口观察过,一个http协议调用如果整体花费的时间在5毫秒甚至10毫秒,那么其实就可以认为这个http请求响应时间是很短的了。
所以绝大部分公司内部的系统之间通信都会采用rpc调用这种方式。这里不要抬杠,如果你的公司内部系统通信采用的是基于http协议的,那说明你们的系统很有可能没有性能的要求。
RPC调用虽然简化了撸码的难度,但是想要实现一套rpc框架,何止容易,一套优秀的rpc框架,更是难如登天。
多数rpc框架的服务端以service的方式来运行,为了避免和其他进程发生监听端口的冲突,一般会随机选择一个端口来进行监听。虽然这看上去很好,但是却给client端带来了麻烦,如果服务端监听固定端口,client连接服务端的时候,最少可以在代码中固定写死服务端的IP和端口。但是现在服务端监听的端口是随机的,而且更可怕的是服务器有可能会更换或者切换IP,那client怎么才能正确的去和服务端建立连接呢?
服务端之所以会采用这种随机方式来监听端口,其中很大一个原因是为了以后扩容。client如何正确的去连接服务器则采用了一个集中式的方案,服务端引入了一个服务注册中心的概念,有的系统可能会以别的名称来体现,但是作用是类似的。这个注册中心存储着所有的服务端信息,其中包括每个服务端的IP和端口,有的甚至还有版本信息,每个服务端进程启动的时候,都是采用主动连接注册中心,主动注册的方式。client端在发起连接服务的时候,首先去注册中心查找已经注册的服务端信息,然后进行连接。这样rpc调用在某种程度上在连接步骤就实现了“自动化”。
当client和服务端建立tcp连接之后(有的rpc框架会采用udp协议),下一个问题就是client和服务端怎么相认的问题了。举个栗子:客户端想要实现一个获取用户姓名的方法,方法名怎么定义才能让服务端正确识别出来呢?是传一个字符串“GetName”,还是传一个整数1来代表呢?服务端的返回结果,如果发生异常改如何返回呢?
当我们在本地调用一个函数,语法,语义,以及语法语义的分析,编译器已经帮我们做好了这些,但是rpc是远程过程调用,虽然表面上和本地类似,但是已经出现了跨网络的情况,语法语义等等这些分析需要client和服务端协商一致。
其实现代几乎大部分rpc通信都遵循一个标准:

当client发起一个远程调用的时候,它首先会先调用本地的Stub,它负责将调用的接口,函数以及参数按照约定好的协议格式进行编码,然后通过本地的Runtime进行传输,最后通过网卡将数据包发送到指定的服务器。
服务器Runtime接收到请求之后,会首先调用本地的Stub按照约定好的协议格式进行解码,最后调用服务端具体的函数。函数执行完毕,把结果利用本地的Stub编码之后通过runtime发送给客户端。客户端Runtime接收到消息利用本地Stub进行解码,然后进行其他处理。
由此可见,现代的rpc框架其实是把协议的封装和数据的发送分别抽象成了单独的层。Stub负责协议部分,Runtime处理数据发送以及网络相关部分。
数据通过网络传输过程中,每个数据包的完整性如何来识别,如果是一个简单int型数据很简单,但是如果是一个类或者一个数组,甚至是其他变长的类型,rpc的通信协议如何约束这些,如果能正确识别出来数据是协议部分最难处理的部分。更何况还有大头小头编码的问题。
凡是基于网络传输的形式,任何通信都是不可靠的,网络本质是不可靠的。包括网络抖动,错误等造成的丢包,粘包现象,如何正确的处理也是一个rpc通信中很重要的部分。一个rpc请求失败,是直接丢弃还是重试,这些策略都需要去规定。
1.一个rpc调用如果采用同步的方式,性能会大大打折扣,如何实现rpc的异步调用,这是一个rpc是否优秀的重要指标。
2.无论rpc的网络传输多么优秀,都会有性能损耗,能否把某些结果数据设置缓存?
3.无论是client还是服务端,处理请求的线程能否重用(线程池)?
4.能否支持多语言呢?
socket虽易,RPC却难

程序员修神之路--设计一套RPC框架并非易事的更多相关文章
- 程序员修神之路--用NOSql给高并发系统加速(送书)
随着互联网大潮的到来,越来越多网站,应用系统需要海量数据的支撑,高并发.低延迟.高可用.高扩展等要求在传统的关系型数据库中已经得不到满足,或者说关系型数据库应对这些需求已经显得力不从心了.关系型数据库 ...
- 程序员修神之路--kubernetes是微服务发展的必然产物
菜菜哥,我昨天又请假出去面试了 战况如何呀? 多数面试题回答的还行,但是最后让我介绍微服务和kubernetes的时候,挂了 话说微服务和kubernetes内容确实挺多的 那你给我大体介绍一下呗 可 ...
- 程序员修神之路--redis做分布式锁可能不那么简单
菜菜哥,复联四上映了,要不要一起去看看? 又想骗我电影票,对不对? 呵呵,想去看了叫我呀 看来你工作不饱和呀 哪有,这两天我刚基于redis写了一个分布式锁,很简单 不管你基于什么做分布式锁,你觉得很 ...
- 程序员修神之路--🤠分布式高并发下Actor模型如此优秀🤠
写在开始 一般来说有两种策略用来在并发线程中进行通信:共享数据和消息传递.使用共享数据方式的并发编程面临的最大的一个问题就是数据条件竞争.处理各种锁的问题是让人十分头痛的一件事. 传统多数流行的语言并 ...
- 程序员修神之路--为什么有了SOA,我们还用微服务?
菜菜哥,我最近需要做一个项目,老大让我用微服务的方式来做 那挺好呀,微服务现在的确很流行 我以前在别的公司都是以SOA的方式,SOA也是面向服务的方式呀 的确,微服务和SOA有相同之处 面向服务的架构 ...
- 程序员修神之路--打通Docker镜像发布容器运行流程
菜菜哥,我看了一下docker相关的内容,但是还是有点迷糊 还有哪不明白呢? 如果我想用docker实现所谓的云原生,我的项目该怎么发布呢? 这还是要详细介绍一下docker了 Docker 是一个开 ...
- 程序员修仙之路--优雅快速的统计千万级别uv(留言送书)
菜菜,咱们网站现在有多少PV和UV了? Y总,咱们没有统计pv和uv的系统,预估大约有一千万uv吧 写一个统计uv和pv的系统吧 网上有现成的,直接接入一个不行吗? 别人的不太放心,毕竟自己写的,自己 ...
- 程序员修仙之路- CXO让我做一个计算器!!
菜菜呀,个税最近改革了,我得重新计算你的工资呀,我需要个计算器,你开发一个吧 CEO,CTO,CFO于一身的CXO X总,咱不会买一个吗? 菜菜 那不得花钱吗,一块钱也是钱呀··这个计算器支持加减乘除 ...
- 程序员修仙之路--优雅快速的统计千万级别uv
菜菜,咱们网站现在有多少PV和UV了? Y总,咱们没有统计pv和uv的系统,预估大约有一千万uv吧 写一个统计uv和pv的系统吧 网上有现成的,直接接入一个不行吗? 别人的不太放心,毕竟自己写的,自己 ...
随机推荐
- hdu6312 2018杭电多校第二场 1004 D Game 博弈
Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- zoj 5823 Soldier Game 2018 青岛 I
题目传送门 题意:现在有n个人,现在可以把这n个人分成若干组,只有连续的人才能被分为一组,并且一个组内最多2个人,现在问你 所有组内的最大值-最小值 这个差值最小是多少. 题解: 将每个人的情况3种情 ...
- [NOI2001]炮兵阵地 题解
题意 我们先来了解一下基本的位运算 于( \(\bigwedge\) ),或 (\(\bigvee\) ) 异或(\(\bigoplus\)) 在下面我们用(&)代表于,(|)代表或 一道状压 ...
- solr 的基本用法
上图为 solr 的搜索页面,常用字段的基本用法如下: 1. q: 查询字符串,过滤条件,不能为空,必须输入,如果查询全部就写 * : * name:“马” AND age:[0 TO 18] ...
- 实现一个简易版的vuex持久化工具
背景 最近用uni-app开发小程序项目时,部分需要持久化的内容直接使用vue中的持久化插件貌似不太行,所以想着自己实现一下类似vuex-persistedstate插件的功能,想着功能不多,代码量应 ...
- java.lang.UnsupportedClassVersionError:JDK版本不一致报错
交代一下背景:公司运行的一个上线项目,打了个补丁发给客户后,反馈说运行不了.把源码拿回来场景重现.贴上报错信息: 08-15 14:13:29 ERROR doPost(jcm.framework.r ...
- JSP静态include和动态include的区别
静态include是指令元素.include指令的语法格式:<%@ include file="filename" %>.include指令的作用是在JSP页面中静态包 ...
- SeekBar拖动条
seekbar拖动条,通过滑块的位置值的改变,来对某些数据进行调节,比如音量调节; 改变滑块的外观可以通过android:thumb属性完成 实例:拖动滑块改变图片透明度 <LinearLayo ...
- mysql生成主键
在mysql中,可以使用uuid 来生成主键,但是用mysql的uuid()函数 ,生成的uuid是36位的,其中包含32个字符以及4个分隔符(-), 往往这个分隔符对我们来说是没有用的,可以使用my ...
- opencv中IplImage* src = cvLoadImage,错误
在调试这段代码时 IplImage* src = cvLoadImage("D:\\图像\\已处理 - 11.26\\1.jpg", 1); 提示一下错误 引发了异常: 读取访问权 ...