RPC框架学习 - 1

Posted 不油腻的儿子娃娃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RPC框架学习 - 1相关的知识,希望对你有一定的参考价值。

RPC是分布式系统的基石,在RPC里会包括有哪些组件呢?各个组件是如何实现的呢?如何进行交互的呢?

概述RPC是什么RPC框架(Framework)通信模型超时计算线程模型IO模型Reactor线程模型三个角色单线程模型多线程模型主从线程多线程模型连接管理长短连接TCP层的Keep-Alive应用层Keep-Alive优雅关闭数据透传序列化框架(Serialization)通信协议(Communication Protocol)

概述

RPC是什么

RPC是由Bruce Jay Nelson在论文Implementing Remote Procedure Calls里提出来的,在论文中作者认为RPC需要包括有:

  1. Client

  2. Client-Stub

  3. RPC-Runtime

  4. Server-Stub

  5. Server

从上面的图示来看,Stub做的是打包的事情,RPC Runtime做的网络传输的事情。

问题1: 如何进行打包? —> 序列化(如Protobuf)和网络协议编解码(如Rest/HTTP2)。Serialization + Protocol Codec

问题2: 如何找到Server?  —> 注册服务(Registery,可以使用Zookeeper或者ETCD),并加上路由信息、负载均衡器等内容。Router + Registery + Load Balancer

问题3: 如何进行网络传输?—> 如使用BOLT或者Netty。Transport

RPC框架(Framework)

处理如何建立并管理连接,如何处理RPC和应用业务逻辑的关系

通信模型

  • 同步处理,处理线程必须要等待RPC返回(包括超时或者抛出异常)才能继续往下走

  • 异步处理,处理线程发送RPC请求之后,继续往下执行。由RPC Runtime缓存了RPC请求Future对应的服务器处理结果,然后处理线程通过Future去获取最终服务器的处理结果,获取结果的时候线程是阻塞的

  • Callback处理,RPC发送请求线程和处理RPC返回结果线程不是同一个线程

超时计算

使用HashedWheelTimer来进行超时控制

线程模型

IO模型

  • 阻塞IO,使得请求进程阻塞,直到请求完成或出错

  • 非阻塞IO,一直查询问是否就绪,若数据不就绪,则返回EWOULDBLOCK或者EAGAIN。若就绪了,则将数据从内核空间拷贝到用户空间,并返回给处理线程。在将数据从内核空间拷贝到用户空间的过程中,也是阻塞的

  • IO复用,使用select, poll, epoll等,也会使得进程阻塞,但是跟阻塞IO不同的是,是可以同时阻塞多个IO操作,即同时处理多个IO的读写

  • 还有不太常用的如信号驱动IO、异步IO等等

在IO模型中,常见的为阻塞IO、非阻塞IO和IO复用,这三种方式中都是会存在有阻塞时间,只是在阻塞IO里阻塞时间最长,非阻塞IO和IO复用里,只有在处理数据的时候处于阻塞处理阶段

Reactor线程模型

线程模型中,当前有Reactor线程模型和Proactor模型,但是Proactor不太常用,主要是介绍下Reactor线程模型。

三个角色

存在有Reactor/Acceptor/Handler三个角色。其中

  • Reactor,将事件分发到Handler

  • Acceptor, 建立新连接

  • Handler, 数据已经就绪,处理非阻塞的IO任务

单线程模型

即所有的操作,不管是Reactor、Acceptor还是Handler,都是在同一个RPC线程里完成的模式

多线程模型

将IO操作和非IO操作分离,所有的IO操作放到RPC线程里来完成,非IO操作放到线程池里去处理

主从线程多线程模型

同上面的多线程模型不同的部分是,将IO事件里将ACCEPT事件进行分离,由主Reactor处理ON_ACCEPT事件,从Reactor处理ON_READ事件

当然还可以更加进一步,这块的线程池里指的是RPC自己的线程池,对于业务复杂的,还可以有业务自己的线程池

连接管理

长短连接

  • 短连接只建立连接,发送数据并接收服务器返回的数据之后,就断开连接,然后再重复上面的过程

  • 长连接是指,建立连接后,发送数据,接收数据,但是不主动断开,并且主动地通过心跳机制来维护这个连接可用,当再次有数据发送请求的时候,不需要再次进行建立连接的过程

连接管理很大部分是处理长连接的问题

TCP层的Keep-Alive

TCP层的Keep-Alive机制,指的是在连接无活动一段时间之后,发送一个空的Ack,使得TCP连接不会被关闭掉

操作系统默认支持TCP Keep-Alive

1net.ipv4.tcp_keepalive_time=7200
2net.ipv4.tcp_keepalive_probes=9
3net.ipv4.tcp_keepalive_intvl=75

上面三个参数设置的含义为:

每2H进行一次Tcp Keep-Alive探测,若没有收到探测应答,每次最多探测9次,其中探测频率为75s。若经过9次探测,每次等待周期为75s后还是没有应答,那么就断开连接。

应用层Keep-Alive

一般叫做心跳包,类似于TCP Keep-Alive,用来检测是否断线的一种机制。那么有了TCP层的Keep-Alive机制,为啥还要有应用层的Keep-Alive机制呢

  1. TCP层的Keep-Alive机制,需要2H才能发现,时间太长。若修改的话,影响整个系统层面,影响太大

  2. TCP层的Keep-Alive机制,在复杂的网络情况下不一定可行,如使用了Socks-Proxy的网络,TCP层的Keep-Alive就失效了

大部分的情况下,都是同时使用应用层Keep-Alive和TCP层的Keep-Alive两种机制,对所有的连接进行统一管理,然后通过心跳机制去检测哪些连接可用或者不可用,每次使用的时候都获取能用的连接。

优雅关闭

数据透传

即在RPC请求过程中,增加一个Context,在Context里填充所需要的字段,在整个RPC过程中来回传输。相当于扩展了RPC的机制,不仅仅是包括有Request/Response,再增加一些有关该次RPC过程中的一些Context信息

序列化框架(Serialization)

序列化解决的是对象和字节之间的映射,序列化是从对象变成字节,反序列化为字节变成对象。这块属于应用层的协议

当前使用非常多的就是Protocol Buffer,对Protocol Buffer详细描述的内容有:  高效的数据压缩编码方式-Protocol Buffer

通信协议(Communication Protocol)

参考文章


以上是关于RPC框架学习 - 1的主要内容,如果未能解决你的问题,请参考以下文章

RPC框架研究Hadoop源代码-1

学习别人的rpc框架

RPC框架学习 - 1

RPC&Netty 学习之路

一个入门rpc框架的学习

稳定性 耗时 监控原因分析-- dubbo rpc 框架 的线程池,io 连接模型. 客户端,服务端