【RPC系列】1、聊一聊Rpc实现流程

RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的一种多进程间的通信机制。

可以自动处理通信协议、对象序列化、网络传输等复杂细节。

1、先了解Socket通信,类似聊天工具

客户端:

//绑定连接主机和端口
Socket client = new Socket("127.0.0.1", 9999);
//创建一个输出流,就用最简单的
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()), 1000);
//获取控制台输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "utf-8"));
//往流里面写数据
while(true) {
	String str = br.readLine();
	bw.write(str);
	bw.write("\n");
	//关闭
	bw.flush();
	//退出聊天
	if("exit".equals(str)) {
		break;
	}
}
client.close();

服务端:

//开启一个端口监控连接
ServerSocket server = new ServerSocket(9999);
//等待连接
Socket socket = server.accept();
//获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读数据
while(true) {
	String str = br.readLine();
	if("exit".equals(str)) {
		break;
	}
	if(str != null) {
		System.out.println("<<<" + str);
	}
}
server.close();

2、熟悉的NIO框架

从以上简单的socket通信来看,使用了字符串的传输,还会遇到字符串的编码问题,要形成生产实用的框架还需要考虑:

(1)网络异常情况。就是

(2)复杂数据传输编解码问题。

(3)多客户端连接以及服务端并发处理问题,连接复用,于是出现Nio模型的多路复用等。

(4)健康检查(心跳)机制等。

(5)缓存机制提高读写效率

要学习TCP、UDP通信,还是需要恶补一下Socket的知识:

TCP通信:每个TCP Socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式及TCP的滑动窗口就是依赖于两个独立的Buffer(缓冲区)。接收缓冲区把数据缓存入内核,若应用进程一直没有调用Socket的read方法,那么数据就会一直被缓存在接收缓冲区。read所做的事就是把内核接收缓冲区的数据复制到应用层用户的Buffer里面send所做的事就是把应用层用户的Buffer的数据复制到内核发送缓冲区

UDP通信:有接收缓冲区,没有发送缓冲区,意思就是有数据就发,不管对方收到没有。

TCP/IP滑动窗口和流量控制机制:想一下,如果Buffer满了怎么办,因为都无限制的去接收和发送。如果应用程序一直没有read,那么Buffer满了之后就会通知对端TCP协议中的窗口关闭,保证TCP socket接收缓冲区不会溢出,这就是滑动窗口实现。因为对方不允许发出超过窗口大小的数据,所以如果对方无视窗口大小而发出了超大数据,接收方就会选择丢弃,就是TCP的流量控制。

了解了滑动窗口和流量控制的概念,就很容易理解“阻塞”的概念了,如果Buffer里的数据是空的,那么read的时候线程就会阻塞(等待)了,直到有数据进入接收缓冲区,发送也是一样。如果待发送的数据大于Buffer发送缓冲区的大小了,那么就会阻塞在write方法上,等待缓冲区的数据发送出去,再继续发送下一段。

以上可以看出,每个socket的读写都要创建一个线程去处理,而且A/B两方的读写效率会互相影响,A写的效率慢,势必造成B阻塞在读上,多个socket连接就会出现大量线程阻塞在I/O等待上。

那如何做到“非阻塞”?无非就是将socket的读写与I/O线程解耦的问题。也就是NIO(No-Blocking I/O),于是就引入了事件的机制。有了事件,那就要想到需要有个事件驱动的总调度中心。我们可以认为NIO底层就存在一个I/O调度线程,它可以轮询扫描每个socket的缓冲区,当发现写入缓冲区未满的时候,就产生一个可写事件,一次写不完就等待下次可写事件的通知,当发现接收缓冲区中有数据时就产生可读事件。当然这都是程序去控制的,一定要注意轮询的深度,切忌空轮询。

以上可见阻塞和非阻塞的区别就是线程是否处于等待状态中

关于Reactor模型在下节讲诉。

3、大名鼎鼎RPC

首先清晰的理解下RPC和Socket在编程上的区别,以上基本了解了socket的编程和建立在socket通信的nio的模型,我们可以认为是客户端与服务端之间的通信连接编程,socket连接我们可以n vs 1,服务端绑定端口,客户端只要提供Host和Port就可以进行连接了,那如果多服务端会出现什么情况。

大名鼎鼎的RPC开发框架为了针对分布式系统开发诞生了。是由Sun公司提出的。为了将上面的socket程序改写成Rpc程序,我们需要将服务端和客户端分离,即在socket接口外封装一层Stub模块,实现过程远程调用所需要的通信功能,比如参数及调用结果的序列化功能,并通过网络完成远程传输。

看一下简单的rpc实现流程:

整个rpc的调用过程如下:

(1)服务消费方(客户端,消费者,订阅者)-caller以本地调用方式调用服务。

(2)User-stub获取到User的调用后负责将方法、参数等组装成能够在网络中传输的消息体。

(3)RPC-runtime找到服务地址,并将消息发送到服务端。

(4)Callee收到消息后将请求交给Server-stub进行解码。

(5)Server-stub解码完之后根据服务指令交给Server去调用。

(6)Server执行完并将结果返回给Server-stub进行打包并发送至Caller。

(7)Caller接收到响应包后交给User-stub进行解码并返回结果给User。

其中实现主要有三个模块的技术要点:

  • 高性能网络编程技术
  • 复杂结构消息体的序列化和反序列化技术
  • 动态代理编程技术

说到rpc就会说到微服务架构,一般而言,如果分布式系统具有以下几个特点,就可以称之为微服务架构:

  1. 任何一个服务都由多个独立的进程提供服务,这些进程可以分布在多台物理机上,任何进程宕机,都不会影响系统提供服务
  2. 整个系统是由多个微服务有机组成的一个分布式系统,换而言之,不是一个巨大的的单体应用。

目前主流的微服务架构分为一下三类:

  • 基于传统的高性能RPC技术和服务治理的微服务架构,代表为ZeroC IceGrid
  • 以Http Rest为通信机制的通用性微服务架构,最典型的为Spring cloud
  • 基于容器技术,目标是部署在公有云平台上的微服务架构基础平台,他们并没有提供特定的RPC通信机制,只保证TCP的可达性,提供一个微服务平台,任何分布式系统都可以部署上面,只需要设定通信协议:REST、Thrift、gRPC或者自定义

本文参考Leader-us著《架构解密》、张亮等著《未来架构》

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值