七的博客

手写RPC框架系列(六) - 构建RPC通信基础

RPC手写系列

手写RPC框架系列(六) - 构建RPC通信基础

从本章节开始,我们将逐步切换到RPC框架的核心部分——通信。本章节主要涵盖以下内容:

  • 通信协议的选择
  • 序列化与反序列化方案
  • 常用的网络通信模型
  • Java生态中常用的网络编程框架

1. 网络通信协议的选择

RPC 框架的核心是网路通信,这决定了它的性能上限。在选择通信协议时,通常会有以下几个选择:

  • TCP 协议: TCP 协议可以提供可靠的、面向连接的服务。 TCP 保证了数据的顺序性以及完整性,目前市面上大部分的 RPC 框架都是基于 TCP 协议。
  • UDP 协议: UDP 是一种无连接的协议,通常用于哪些不需要可靠传输的场景。 典型的场景就是在线视频传输、直播流、直播弹幕信息等,这种信息丢失一小部分大多数时候对业务并没有特别大的影响。
  • HTTP 协议: 这个协议太常见不过了,目前你所能访问的网站都是大部分基于 HTTP 协议进行通信的。

综合考虑可靠性和性能,我们选择基于TCP协议进行通信。

2. 序列化以及反序列化

数据在网络中进行传输前需要先序列化,接收到后进行反序列化。高效的序列化可以极大的影响 RPC框架的性能。 比较常见的序列化协议包括:

序列化协议 二进制/文本 主要特点 常用于
JSON 文本 易于阅读和编辑,跨语言支持 Web APIs, 配置文件
XML 文本 可扩展性强,支持复杂数据结构 Web服务, 配置管理
Protocol Buffers 二进制 高效的编码,跨平台 通信协议, 数据存储
Thrift 二进制/文本 支持多种编程语言,可以定义数据类型和服务接口 跨语言服务开发
MessagePack 二进制 小巧,速度快 缓存数据, 实时数据传输
BSON 二进制 类似JSON但为二进制,支持更多数据类型 MongoDB文档存储

这些序列化协议各有优劣,选择合适的协议需要考虑实际应用场景的需求。如是否需要跨平台兼容、数据传输的效率、是否需要支持复杂的数据结构等因素。

考虑到易用性和通用性,我们选择JSON作为序列化协议。

3. 常用的网络通信模型

3.1 同步 vs 异步

  • 同步调用:客户端发起调用后需要等待服务端响应,简化编程模型但降低了整体效率。
  • 异步调用:客户端发起调用后可立即执行其他任务,通过回调或Future获取结果,提高并发性能。

在我们的RPC框架中,我们将支持异步通信模型,以提高处理效率和系统扩展性。

3.2 阻塞 vs 非阻塞

  • 阻塞调用:调用线程会一直等待操作完成,可能导致资源浪费。
  • 非阻塞调用:调用线程可在等待时执行其他任务,更好地利用资源。

由于RPC框架需要高效处理大量并发请求,我们采用非阻塞模型,以提高系统的响应速度和吞吐量。

4. Java 生态的网络编程库

目前 Java 生态的网络编程库比较常用的有下面三个:

4.1 原生 Java NIO

Java NIO(New Input/Output)是Java提供的一种新的输入输出模型,与传统的IO模型相比,它更加灵活,能够更好地处理高并发数据。Java NIO主要基于通道(Channel)和缓冲区(Buffer)的概念,支持非阻塞的IO操作。通道类似于传统IO中的流,但通道可以进行双向数据传输,而且可以异步地读写。

Java NIO的主要组件包括:

  • 缓冲区(Buffer):数据的临时存储区,可以读写数据。
  • 通道(Channel):连接到数据源如文件或套接字的开放连接,可以进行数据读写操作。
  • 选择器(Selector):与非阻塞模式一起使用,可以检测多个注册通道上的事件(如数据到达),从而允许单线程管理多个通道。

尽管Java NIO提供了高性能的数据处理能力,但它的编程复杂度相比传统IO较高,需要处理缓冲区的状态控制、通道的选择等问题。通常是不推荐直接用原生的 Java NIO 去进行生产环境的软件开发。

4.2 Netty

Netty 是基于Java NIO的客户端-服务器框架,提供了易于使用的 API 来创建高性能、高可靠性的网络应用程序。Netty 广泛应用于游戏服务器、通信中间件、微服务架构等多种领域。相比于原生 NIO,Netty 解决了很多底层细节,使得开发者能够更专注于业务逻辑的实现。

Netty 的主要特点包括:

  • 异步和事件驱动:Netty 基于事件驱动模型,可以处理数以千计的并发连接。
  • 简化的线程模型:Netty 内部实现了线程池,通过有效的资源管理优化了线程的使用。
  • 高度可定制:Netty 提供了灵活的编程接口和多种内置的协议支持,如HTTP、WebSocket等。
  • 内存管理:通过高效的缓冲区管理机制,减少内存复制次数,提升性能。

Netty 拥有活跃的社区和广泛的文档资料,有助于解决开发中的问题,在生产环境中使用的比例非常高。

4.3 Mina

Apache Mina 是另一种基于Java NIO的网络应用框架,与Netty类似,它也是设计用于开发高性能和高可扩展性的网络应用程序。Mina的设计哲学注重简单性和会话抽象,使得开发网络应用变得更简单。

Mina的核心特点包括:

  • 高级的抽象:Mina将网络通信的复杂性抽象成简单的会话和服务概念。
  • 可扩展性:提供了一套Filter接口,用户可以通过这些接口来扩展或修改框架的功能。
  • 支持多种协议:Mina不仅支持TCP和UDP,还可以通过编写自定义的协议解码器来支持其他协议。
  • 灵活的线程模型:允许用户根据需要自定义线程模型,以适应不同的应用场景。

相对于Netty,Mina 在某些高性能场景下可能表现不如 Netty,尤其是在处理大量并发连接时。并且还有个致命的问题,Mina 的社区活跃度和可用资源较少,可能在遇到问题时找到帮助的速度不如 Netty。

这里需要注意的是,虽然 Mina 和 Netty 看起来很强大,但是底层都是基于 Java NIO,本质上还是对 NIO 的 API 进行了封装。 但Mina更侧重于提供简单易用的接口,而Netty提供了更丰富的特性和更高的性能优化可能。

为了更加贴近于生产环境,我们决定选用 Netty 作为网络通信框架。

5. 总结

通过上面章节的介绍,我们应该对通信有了一些基本的了解,包括:

  • 通信协议是什么、常用的通信协议有哪些、各种通信协议的优缺点。
  • 序列化以及反序列化是什么、常用的序列化协议、各种序列化协议的优缺点。
  • 常用的网络通信模型有哪些、各种模型的优缺点。
  • 常用的网络编程框架有哪些、各自的优缺点、选型建议等。

这样就可以打通一整个通信链路,即:

  • 使用 TCP 作为通信协议
  • 使用 JSON 作为通信的数据格式
  • 使用 异步 + 非阻塞的通信模式
  • 使用 Netty 框架来简化 Java 代码的工作量

6. 参考链接