程序员修神之路--设计一套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的系统吧 网上有现成的,直接接入一个不行吗? 别人的不太放心,毕竟自己写的,自己 ...
随机推荐
- HDU2276 Kiki & Little Kiki 2 矩阵快速幂
Kiki & Little Kiki 2 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java ...
- hdu 1671 Phone List 字典树模板
Given a list of phone numbers, determine if it is consistent in the sense that no number is the pref ...
- js 数组方法的作用,各方法是否改变原有的数组
不会改变原来数组的有: concat()---连接两个或更多的数组,并返回结果. every()---检测数组元素的每个元素是否都符合条件. some()---检测数组元素中是否有元素符合指定条件. ...
- 阿里巴巴资深技术专家雷卷:值得开发者关注的 Java 8 后时代的语言特性
作者 | 阿里巴巴资深技术专家 雷卷,GitHub ID @linux-china 导读:在 Python.JavaScript 等一众编程语言崛起风靡之际,一代霸主 Java 风采虽不及当年,但仍 ...
- 相同类中方法间调用时日志Aop失效处理
本篇分享的内容是在相同类中方法间调用时Aop失效处理方案,该问题我看有很多文章描述了,不过大多是从事务角度分享的,本篇打算从日志aop方面分享(当然都是aop,失效和处理方案都是一样),以下都是基于s ...
- 054 Python程序设计思维
目录 一.单元开篇 二.计算思维与程序设计 2.1 计算思维 2.1.1 第3种人类思维特征 2.1.2 抽象和自动化 2.1.3 计数求和:计算1-100的计数和 2.1.4 圆周率的计算 2.1. ...
- Elasticsearch之更新
public class UpdateElasticAPI { private static RestClient restClient; static { restClient=RestClient ...
- null==a和a==null的区别
在项目代码中在if判断中会经常看到一些老司机这样写:if(null == a),而我由于习惯会写成if(a == null),这两种有什么区别呢? 其实两种并没有什么区别,只是前者在细节处理上.我们在 ...
- 学习笔记_第十天_方法_方法的综合练习---ref练习
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Django跳转到不同的页面的方法和实例–使用Django建立你的第一个网站
1 前记 这次记录的这些东西,主要是自己在搭建个人网站的时候遇到的一些问题记录,不算严格意义上的教程和使用说明.按照目前自己的web水平,去写这方面的教程无疑是误人子弟.因为自己虽然做程序员很多年,但 ...