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

640?wx_fmt=gif

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

640
640?wx_fmt=jpeg

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

640
640?wx_fmt=jpeg

http协议不也是利用的Socket吗

640
640?wx_fmt=jpeg

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

640
640?wx_fmt=jpeg

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

640
640?wx_fmt=jpeg

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

640
640?wx_fmt=jpeg

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

640
640?wx_fmt=jpeg

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

640
640?wx_fmt=jpeg
640?wx_fmt=png
640?wx_fmt=png

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

01
开局
640

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

640

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

640
640

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

01
连接服务
640

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

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

02
调用方法
640

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

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

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

640?wx_fmt=jpeg

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

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

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

03
网络数据传输

640

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

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

04
性能

640

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

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

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

4.能否支持多语言呢?

640

socket虽易,RPC却难


640?wx_fmt=gif

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPU Shader 编程基础

转载自:http://www.cnblogs.com/youthlion/archive/2012/12/07/2807919.html 几个基本概念: Vertex buffer:存储顶点的数组。当构成模型的所有顶点都放进vertex buffer后,就可以把vertex buffer送进GPU,然后GPU就可…

Azure pipeline 配置根据条件执行脚本

Azure pipeline 配置根据条件执行脚本Intro我的应用通过 azure pipeline 来做持续集成,之前已经介绍了根据不同分支去打包不同的package,具体的就不再这里详细介绍了,可以参考 Solution来看一下修改之后的 azure-pipelines.yaml 示例配置吧&a…

监督学习和非监督学习

转自:http://blog.csdn.net/warrior_zhang/article/details/41453327 机器学习的常用方法,主要分为有监督学习(supervised learning)和无监督学习(unsupervised learning)。 监督学习,就是人们常说的分类,通过已有的训练样本&am…

C# 8 新特性 - 可空引用类型

Nullable Reference Type.在写C#代码的时候,你可能经常会遇到这个错误: 但如果想避免NullReferenceException的发生,确实需要做很多麻烦的工作。 可空引用类型 Null Reference Type 所以,C# 8的可空引用类型就出现了。 C# 8可以让…

Spring boot starter

1:Spring boot starter及项目中的类似运用 1:Spring boot starter的两种方式 引入pom文件,自动管理jar版本根据spring.factories配置文件,加载config的各种bean spring boot约定大于配置理念在这里有体现。 2:项目…

统计学习笔记(1) 监督学习概论(1)

原作品:The Elements of Statistical Learning Data Mining, Inference, and Prediction, Second Edition, by Trevor Hastie, Robert Tibshirani and Jerome Friedman An Introduction to Statistical Learning. by Gareth JamesDaniela WittenTrevor Hastie andR…

.NET Core 3.0之深入源码理解ObjectPool(一)

写在前面对象池是一种比较常用的提高系统性能的软件设计模式,它维护了一系列相关对象列表的容器对象,这些对象可以随时重复使用,对象池节省了频繁创建对象的开销。它使用取用/归还的操作模式,并重复执行这些操作。如下图所示&…

查看日志文件的方法

对于一般大小的日志文件,直接使用tail命令即可。 对于大日志文件,并且还在不停刷新的,使用more或less命令 对于很大的log文件用more不能直接跳到文件末尾向前查看。 这时可以用less来查看文件时,在command模式下按G跳到文件末尾&…

Deep Boltzmann Machines

转载自:http://blog.csdn.net/win_in_action/article/details/25333671 http://blog.csdn.net/zouxy09/article/details/8775518 深度神经网络(Deep neural network) 深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种…

生产问题

1:MQ过快 有个业务场景是:先创建一条记录(1),然后发mq,最后更新这条记录的状态(2)。 收到mq之后,再更新状态(3)。 问题出在mq快于本地事务&…

.NET斗鱼直播弹幕客户端(下)

前言在上篇文章中,我们提到了如何使用 .NET连接斗鱼TV直播弹幕的基本操作。然而想要做得好,做得容易扩展,就需要做进一步的代码整理。本文将涉及以下内容:介绍如何使用 ReactiveExtensions( Rx)&#xff0c…

字符串的排列

题目描述 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。 换句话说,第一个字符串的排列之一是第二个字符串的子串。 示例1: 输入: s1 “ab” s2 “eidbaooo” 输出: True 解释: s2 包含 s1 的排列之一 (“ba”). 示例2: 输入: …

【 .NET Core 3.0 】框架之十 || AOP 切面思想

本文有配套视频:https://www.bilibili.com/video/av58096866/?p6前言上回《【 .NET Core3.0 】框架之九 || 依赖注入IoC学习 AOP界面编程初探》咱们说到了依赖注入Autofac的使用,不知道大家对IoC的使用是怎样的感觉,我个人表示还是比较可行…

[ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker

对于一个 .NET Core开发人员,你可能没有使用过Docker,但是你不可能没有听说过Docker。Docker是Github上最受欢迎的开源项目之一,它号称要成为所有云应用的基石,并把互联网升级到下一代。Docker是dotCloud公司开源的一款产品&#…

翻转字符串里的单词

问题描述 示例 1: 输入: "the sky is blue" 输出: "blue is sky the"示例 2: 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字…

统计学习笔记(4) 线性回归(1)

Basic Introduction In this chapter, we review some of the key ideas underlying the linear regression model, as well as the least squares approach that is most commonly used to fit this model. Basic form: “≈” means “is approximately modeled as”, to …

简化路径

题目描述 以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…&#xf…

敏捷这么久,你知道如何开敏捷发布火车吗?

译者:单冰从事项目管理十几年,先后管理传统型项目团队及敏捷创新型团队。负责京东AI事业部敏捷创新、团队工程效率改进及敏捷教练工作。曾经负责手机端京东App项目管理工作5年,带领千人团队实施敏捷转型工作,版本发布从2个月提升为…

Newton Method in Maching Learning

牛顿方法:转自http://blog.csdn.net/andrewseu/article/details/46771947 本讲大纲: 1.牛顿方法(Newton’s method) 2.指数族(Exponential family) 3.广义线性模型(Generalized linear models) 1.牛顿方法 假设有函数:,我们希…

复原IP地址

1.题目描述 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。 示例: 输入: "25525511135" 输出: ["255.255.11.135", "255.255.111.35"]2.解法 2.1 回溯剪枝法 private int n;private String s;private Linked…