当前位置: 首页 > 编程日记 > 正文

RPC-client异步收发核心细节?

通过上篇文章的介绍,知道了要实施微服务,首先要搞定RPC框架,RPC框架分为客户端部分与服务端部分。


RPC-client的部分又分为:

(1)序列化反序列化的部分(上图中的1、4)

(2)发送字节流与接收字节流的部分(上图中的2、3)

前一篇文章讨论了序列化与范序列化的细节,这一篇文章将讨论发送字节流与接收字节流的部分。

客户端调用又分为同步调用与异步调用

同步调用的代码片段为:

Result = Add(Obj1, Obj2);// 得到Result之前处于阻塞状态

异步调用的代码片段为:

Add(Obj1, Obj2, callback);// 调用后直接返回,不等结果

处理结果通过回调得到:

callback(Result){// 得到处理结果后会调用这个回调函数

}

这两个调用方式,RPC-client里,处理方式也不一样,下文逐一叙述。

RPC-client同步调用


所谓同步调用,在得到结果之前,一直处于阻塞状态,会一直占用一个工作线程,上图简单的说明了一下组件、交互、流程步骤。

上图中的左边大框,就代表了调用方的一个工作线程。

左边粉色中框,代表了RPC-client组件。

右边橙色框,代表了RPC-server。

蓝色两个小框,代表了同步RPC-client两个核心组件,序列化组件与连接池组件。

白色的流程小框,以及箭头序号1-10,代表整个工作线程的串行执行步骤:

1)业务代码发起RPC调用,Result=Add(Obj1,Obj2)

2)序列化组件,将对象调用序列化成二进制字节流,可理解为一个待发送的包packet1

3)通过连接池组件拿到一个可用的连接connection

4)通过连接connection将包packet1发送给RPC-server

5)发送包在网络传输,发给RPC-server

6)响应包在网络传输,发回给RPC-client

7)通过连接connection从RPC-server收取响应包packet2

8)通过连接池组件,将conneciont放回连接池

9)序列化组件,将packet2范序列化为Result对象返回给调用方

10)业务代码获取Result结果,工作线程继续往下走

RPC框架需要支持负载均衡、故障转移、发送超时,这些特性都是通过连接池组件去实现的。

连接池组件


典型连接池组件对外提供的接口为:

int ConnectionPool::init(…);

Connection ConnectionPool::getConnection();

intConnectionPool::putConnection(Connection t);

【INIT】

和下游RPC-server(一般是一个集群),建立N个tcp长连接,即所谓的连接“池”

【getConnection】

从连接“池”中拿一个连接,加锁(置一个标志位),返回给调用方

【putConnection】

将一个分配出去的连接放回连接“池”中,解锁(也是置一个标志位)

如何实现负载均衡?

回答:连接池中建立了与一个RPC-server集群的连接,连接池在返回连接的时候,需要具备随机性。

如何实现故障转移?

回答:连接池中建立了与一个RPC-server集群的连接,当连接池发现某一个机器的连接异常后,需要将这个机器的连接排除掉,返回正常的连接,在机器恢复后,再将连接加回来。

如何实现发送超时?

回答:因为是同步阻塞调用,拿到一个连接后,使用带超时的send/recv即可实现带超时的发送和接收。

总的来说,同步的RPC-client的实现是相对比较容易的,序列化组件、连接池组件配合多工作线程数,就能够实现。还有一个问题,就是【“工作线程数设置多少最为合适?”】,这个问题在之前的文章中讨论过,此处不再深究。

RPC-client异步回调


所谓异步回调,在得到结果之前,不会处于阻塞状态,理论上任何时间都没有任何线程处于阻塞状态,因此异步回调的模型,理论上只需要很少的工作线程与服务连接就能够达到很高的吞吐量。

上图中左边的框框,是少量工作线程(少数几个就行了)进行调用与回调。

中间粉色的框框,代表了RPC-client组件。

右边橙色框,代表了RPC-server。

蓝色六个小框,代表了异步RPC-client六个核心组件:上下文管理器,超时管理器,序列化组件,下游收发队列,下游收发线程,连接池组件。

白色的流程小框,以及箭头序号1-17,代表整个工作线程的串行执行步骤:

1)业务代码发起异步RPC调用,Add(Obj1,Obj2, callback)

2)上下文管理器,将请求,回调,上下文存储起来

3)序列化组件,将对象调用序列化成二进制字节流,可理解为一个待发送的包packet1

4)下游收发队列,将报文放入“待发送队列”,此时调用返回,不会阻塞工作线程

5)下游收发线程,将报文从“待发送队列”中取出,通过连接池组件拿到一个可用的连接connection

6)通过连接connection将包packet1发送给RPC-server

7)发送包在网络传输,发给RPC-server

8)响应包在网络传输,发回给RPC-client

9)通过连接connection从RPC-server收取响应包packet2

10)下游收发线程,将报文放入“已接受队列”,通过连接池组件,将conneciont放回连接池

11)下游收发队列里,报文被取出,此时回调将要开始,不会阻塞工作线程

12)序列化组件,将packet2范序列化为Result对象

13)上下文管理器,将结果,回调,上下文取出

14)通过callback回调业务代码,返回Result结果,工作线程继续往下走

如果请求长时间不返回,处理流程是:

15)上下文管理器,请求长时间没有返回

16)超时管理器拿到超时的上下文

17)通过timeout_cb回调业务代码,工作线程继续往下走

上下文管理器

为什么需要上下文管理器?

回答:由于请求包的发送,响应包的回调都是异步的,甚至不在同一个工作线程中完成,需要一个组件来记录一个请求的上下文,把请求-响应-回调等一些信息匹配起来。

如何将请求-响应-回调这些信息匹配起来?

这是一个很有意思的问题,通过一条连接往下游服务发送了a,b,c三个请求包,异步的收到了x,y,z三个响应包:


(1)怎么知道哪个请求包与哪个响应包对应?

(2)怎么知道哪个响应包与哪个回调函数对应?

回答:这是通过【请求id】来实现请求-响应-回调的串联的。


整个处理流程如上,通过请求id,上下文管理器来对应请求-响应-callback之间的映射关系:

1)生成请求id

2)生成请求上下文context,上下文中包含发送时间time,回调函数callback等信息

3)上下文管理器记录req-id与上下文context的映射关系,

4)将req-id打在请求包里发给RPC-server

5)RPC-server将req-id打在响应包里返回

6)由响应包中的req-id,通过上下文管理器找到原来的上下文context

7)从上下文context中拿到回调函数callback

8)callback将Result带回,推动业务的进一步执行

如何实现负载均衡,故障转移?

回答:与同步的连接池思路相同。不同在于,同步连接池使用阻塞方式收发,需要与一个服务的一个ip建立多条连接,异步收发,一个服务的一个ip只需要建立少量的连接(例如,一条tcp连接)。

如何实现超时发送与接收?

回答:同步阻塞发送,可以直接使用带超时的send/recv来实现,异步非阻塞的nio的网络报文收发,如何实现超时接收呢?(由于连接不会一直等待回包,那如何知晓超时呢?)这时,超时管理器就上场啦。

超时管理器


超时管理器,用于实现请求回包超时回调处理。

每一个请求发送给下游RPC-server,会在上下文管理器中保存req-id与上下文的信息,上下文中保存了请求很多相关信息,例如req-id,回包回调,超时回调,发送时间等。

超时管理器启动timer对上下文管理器中的context进行扫描,看上下文中请求发送时间是否过长,如果过长,就不再等待回包,直接超时回调,推动业务流程继续往下走,并将上下文删除掉。

如果超时回调执行后,正常的回包又到达,通过req-id在上下文管理器里找不到上下文,就直接将请求丢弃(因为已经超时处理过了)。

however,异步回调和同步回调相比,除了序列化组件和连接池组件,会多出上下文管理器,超时管理器,下游收发队列,下游收发线程等组件,并且对调用方的调用习惯有影响(同步->回调)。异步回调能提高系统整体的吞吐量,具体使用哪种方式实现RPC-client,可以结合业务场景来选取(对时延敏感的可以选用同步,对吞吐量敏感的可以选用异步)。

以上内容均来自微信公众号“架构师之路”胡剑老师的文章,欢迎关注。

转载于:https://www.cnblogs.com/sheldon-blog/p/8109835.html

相关文章:

【青少年编程】【三级】病毒传染模拟程序

「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】或【Python】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档&…

UI培训分享:UI设计行业常见术语有哪些?

学会UI设计之后,大家后面就要进入到真正的UI设计行业了,那么关于UI设计行业的常见术语大家也要做一些了解,尤其是新人,这对后面的工作会很多有帮助,本期UI培训教程就给大家介绍一下UI设计行业常见术语有哪些? UI培训分…

面试常用SQL整理

我们都知道面试的时候通常都会考数据库部分的知识,所以在此整理了下我们常用的面试中常用的一些查询语句SQL,本人测试数据库为SQL Server2008 首先在数据库中建立一个测试库,此处用DavidTest代替 数据表与相应测试数据 USE [DavidTest] GO /*…

【青少年编程(第25周)】隔离终于解除了!

2021年08月08日(周日)晚20:00我们在青少年编程竞赛交流群开展了第二十五次直播活动。我们直播活动的主要内容如下: 首先,我们奖励了上周测试超过60分的小朋友。 其次,我们鼓励刚刚加入学习的小朋友参加8月14日开营的&…

JetBrains大力推广Kotlin为哪般?

在之前一篇备受关注的文章“Kotlin与Java之争”中,Vasiliy Zukanov讲述了发生在Kotlin与Java之间的一场没有硝烟的战争,并认为企业从Java转向Kotlin可能需要付出更大的代价。最近,Vasiliy继续发文,对JetBrains大力推广Kotlin背后的…

哪些人适合参加Python培训班?

哪些人适合参加Python培训班?确实,不是所有人都适合参加Python培训班的,有一定基础的同学会选择自学,零基础的同学比较适合参加Python培训班,来看看下面的具体介绍。 哪些人适合参加Python培训班? 1、学生/零基础学员:如果你自制…

关于jsp页面中的pageEncoding和contentType以及html中的meta标签中字符集的设置(转)...

转载:《关于JSP页面中的pageEncoding和contentType两种属性的区别》 pageEncoding是jsp文件本身的编码 contentType的charset是指服务器发送给客户端时的内容编码 JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-…

JNI调用实例

1. 环境 Windows7-64Bit VS2010-32Bit JDK1.8-64Bit 2. 步骤 2.1 创建NativePrint类 public class NativePrint {public native void nativePrint(); } 其中包含一个native方法,这个native方法是通过C实现的,C的实现代码最终是生成dll文件,然…

【青少年编程】【三级】加法出题机

「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】或【Python】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档&…

Python培训教程分享:Python异常机制

​ 在学习Python技术的时候,我们经常会遇到一些异常,例如导致程序在运行过程中出现的中断或退出,我们都称之为异常,大多数的异常都不会被程序处理,而是以错误信息的形式展现出来。本期Python培训教程就算教大家关于Pyt…

SharePoint【调试,诊错系列】-- 一种调试Sharepoint2010 Solution的快捷方式

Visual Studio 2010 支持通过F5来调试Sharepoint Solutions,但这种方法却很难用在调试workflows, event recievers, custom controls上,我们往往通过 "Attach to process..."来调试这些模块,关于如何Attach到正确的Process&#xf…

通往SQL Server复制的阶梯:一级- SQL服务器复制介绍

链接:http://www.sqlservercentral.com/articles/StairwaySeries/72274/ 文章:Stairway to SQL Server Replication: Level 1 - Introduction to SQL Server Replication 通往SQL Server复制的阶梯:一级- SQL服务器复制介绍 By Sebastian Meine, 2012/12…

【青少年编程】【三级】青蛙捕虫

「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】或【Python】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档&…

UI培训教程分享:UI设计的分类有哪些?

本期为大家介绍的UI培训教程是关于UI设计分类这块的,在UI设计中,我们常应用到的终端设备可大致分为三类,分别为移动端UI设计、PC端UI设计、其他终端UI设计。 UI培训教程分享:UI设计的分类有哪些? 1. 移动端UI设计 移动端一般指移…

slider(滑动条)控件模版,样式--用图片定义控件模版

初接触wpf,想自己用图片做一个个性slider滑块控件,网上找了很久无果。后来一些机缘巧合看别人源码的时候找到了类似的,然后自己再查了一下msdn,大概弄懂了。 我们先来看看slider控件组成元素。 Slider控件组成: 用图片…

360浏览器调用selenium

2019独角兽企业重金招聘Python工程师标准>>> 360浏览器调用selenium package com.demo;import java.io.File; import java.io.IOException;import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver;…

【组队学习】【28期】R语言数据科学

R语言数据科学 论坛版块: http://datawhale.club/c/team-learning/36-category/36 开源内容: https://github.com/datawhalechina/team-learning-program/tree/master/RLanguage 学习目标 向零基础的同学介绍如何利用R语言进行数据分析。通过学习&…

零基础参加Java培训班合适吗

零基础参加Java培训班合适吗?对于这个问题,首先答案是肯定的,零基础学习java技术最靠谱最快速的方法就是报java培训班进行学习了,来看看下面的详细介绍就知道了。 零基础参加Java培训班合适吗? 能够想到参加Java培训班学习的同学一般分为三…

用VS(c#)创建、调试windows service以及部署卸载

同事问到windows service的东东,现在整理一下,用c#如何创建一个windows service,以及如何调试、部署、卸载。 一、创建windows service 1. 打开VS2008,新建一个Project, Project类型选择Visual C#-Windows,在Templates…

【组队学习】【28期】基于Python的会员数据化运营

基于Python的会员数据化运营 论坛版块: http://datawhale.club/c/team-learning/37-category/37 开源内容: https://github.com/datawhalechina/team-learning-data-mining/tree/master/MemberOperations 学习目标 数据化运营是业务知识与编程技能…

异步系统接口调用流程图

2019独角兽企业重金招聘Python工程师标准>>> 异步系统接口调用流程图 博客分类: java ................................... 转载于:https://my.oschina.net/xiaominmin/blog/1597725

java培训教程分享:Java中用户如何自定义异常?

我们在学习java技术的时候应该有了解过,在java中是定义了很多的异常类的,虽然这些大量异常类可以帮助我们描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况,例如在设计divide()方法时不允许…

【组队学习】【28期】基于transformers的自然语言处理(NLP)入门

基于transformers的自然语言处理(NLP)入门 论坛版块: http://datawhale.club/c/team-learning/39-category/39 开源内容: https://github.com/datawhalechina/Learn-NLP-with-Transformers 学习目标 自然语言处理(Natural Language Pro…

java io在文件结尾持续添加内容

[代码] java io在文件结尾持续添加内容 public static void write(String path, String content) {try {File f new File(path);BufferedWriter output new BufferedWriter(new FileWriter(f,true));output http://www.szhaoexport.com/linked/20130222.do; .write(content &…

Docker1.12让容器使用和宿主机同一个网段

2019独角兽企业重金招聘Python工程师标准>>> Docker1.12让容器使用和宿主机同一个网段 博客分类: docker 由于开发的一些特殊需求,需要将容器部署在与宿主机同一个网段中,部署步骤如下:步骤一:创建网络$ …

java培训分享:java培训架构师学习线路图

本期java教程分享主要是讲解关于java培训架构师方面的内容,主要针对java架构师的学习线路图进行一个知识点的概括,下面来看看学习java架构师都需要了解哪些内容吧。 java培训分享:java培训架构师学习线路图 1、常见模式与工具 学习Java技术体…

设计中涉及到的dip、dp、px、sp等单位说明

在进行UI设计中常会遇到各种数值单位,开始使用时也常搞混,于是搜集了单位解说的文章与大家一同分享 dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用…

【组队学习】【28期】Datawhale组队学习内容介绍

第28期 Datawhale 组队学习活动马上就要开始啦! 本次组队学习的内容为: 吃瓜教程——西瓜书南瓜书李宏毅机器学习动手学数据分析集成学习SQL编程语言R语言数据科学基于Python的会员数据化运营数据采集从入门到精通基于transformers的自然语言处理(NLP)入…

多线程读一个全局变量要不要加锁?还是说只是当修改全局变量的时候才要加锁?...

如果所有线程都只读取该变量的话不必加锁,因为仅读取不存在破坏数据的风险,如果有线程写该变量的话不管读取还是写入都要加锁的。

java培训教程分享:Java编写软件代码自动提示功能

本期的java培训教程分享主要是介绍的java编写软件代码的一个自动提示功能,很多零基础和初学java的同学们对这一块还不是很了解,Eclipse for android 实现代码自动提示智能提示功能,以下是介绍 Eclipse for android。 java培训教程分享&#x…