二、Socket传输
三、Netty 传输
RPC 被称为“远程过程调用”,会跨越网络,跨越进程,传输层是不可或缺。网络传输名词:TCP、UDP、HTTP,同步 or 异步,阻塞 or 非阻塞,长连接 or 短连接…两种传输层的实现:
Socket:阻塞式的通信,简单实现方式,可了解传输层工作原理及内容
Netty: 非阻塞式,一般 RPC 场景性能好,被很多RPC 框架作为传输层的实现方式
一、RpcRequest 和 RpcResponse
传输层传输主要对象,封装请求 id,方法名,方法参数,返回值,异常等 RPC 调用中需要的一系列信息。
二、Socket传输
Server
Client
dis.readInt() 和 dis.read(byte[] bytes) 决定了使用 Socket 通信是阻塞式操作,报文头+报文体是常见传输格式,除此之外,特殊字符(空行)也可划分报文结构。用 int(4字节)传递报问题长度,之后传递报文体,复杂通信协议中,报文头除了存储报文体,还有协议名称,版本,心跳标识等。
网络传输中,只有字节能够被识别,引入 Serialization 接口完成 RpcRequest 和 RpcResponse 与字节的相互转换。
每次 Server 处理 Client 请求都从线程池中取出一个线程来处理请求,这开销对于 Rpc 调用是不能够接受的,Nett网络框架上场
三、Netty 传输
Server 和 ServerHandler
(1)创建、初始化netty服务端的bootstrap对象
(2)初始化通道:解码RPC请求、编码RPC响应、处理RPC请求
(3)关闭RPC服务器
模拟反射调用,写入RPC相应对象,自动关闭连接
Client 和 ClientHandler
Netty 好处:实现非阻塞式的调用,关键部分都写了注释。上述代码虽然多,和Socket 通信代码大相径庭,大多数都是 Netty 模板代码,启动服务器,配置编解码器等。真正 RPC 封装操作大多集中在 Handler 的 channelRead 方法(负责读取)以及 channel.writeAndFlush 方法(负责写入)中。
Netty 不能保证返回的字节大小,所以加上 in.readableBytes() < 4 、 in.markReaderIndex() 区分报文头和报文体
四、同步与异步 阻塞与非阻塞
Socket 同步阻塞,Netty 异步非阻塞,其实有点问题。
其实没有必然的联系,大多数使用 Netty 实现的 RPC 调用其实应当是同步非阻塞的(一般 RPC 也支持异步非阻塞)。
4.1同步/异步要看:消息通信机制
同步:调用没有得到结果前,不返回。一旦返回,就得到返回值。调用者主动等待结果
异步:调用发出后,就直接返回,不会立刻得到结果。被调用者通知调用者(通过状态、通知),或通过回调函数处理调用。如果不关心其返回值,可做成异步接口,提升效率。
4.2 阻塞/非阻塞摇篮程序在等待调用结果(消息,返回值)时的状态.
阻塞:结果返回之前,当前线程被挂起。调用线程只有在得到结果之后才会返回。
非阻塞:结果返回之前,不会阻塞当前线程。
Socket :声明线程池(10个线程),每次请求分配一个,等待客户端传递报文头和报文体的行为都会阻塞该线程。
Netty :每次请求通过 Handler方式处理请求(联想 NIO 中 Selector),非阻塞
同步非阻塞比不一定同步阻塞式的通信强,没有最好,只有更合适,同步非阻塞适用于 :1.网络连接数量多 2.每个连接的io不频繁 的场景,与 RPC 调用契合。成熟RPC 框架的传输层和协议层通常也会提供多种选择,应对不同场景。
总结
难点:Socket 的理解,Netty 框架掌握。Netty 的学习有一定的门槛,实际需要掌握的知识点其实并不多(仅仅针对 RPC 框架所涉及的知识点而言),推荐《Netty IN ACTION》以及https://waylau.gitbooks.io/netty-4-user-guide/Getting%20Started/Before%20Getting%20Started.html该网站的例子。
参考资料:http://cmsblogs.com/?p=3875
网友评论