从零开始手写RPC框架(番外) Netty基础知识点及常见面试题汇总

目录

  • Netty 的核心组件
    • Bytebuf(字节容器)
    • Bootstrap 和 ServerBootstrap(启动引导类)
    • Channel(网络操作抽象类)
    • Selector
    • EventLoop(事件循环)
      • NioEventLoopGroup 默认的构造函数会起多少线程?
    • ChannelHandler(消息处理器) 、 ChannelPipeline(ChannelHandler 对象链表)和ChannelHandlerContext
    • ChannelFuture(操作执行结果)
  • Netty 是什么?BIO,NIO 和 AIO 有啥区别?
  • 为什么要用 Netty?它有哪些应用场景?
  • Reactor 线程模型
  • netty依赖什么做的这么高性能
  • Netty 线程模型
  • Netty 服务端和客户端的启动过程?
  • 什么是 TCP 粘包/拆包?有什么解决办法呢?
  • 什么是 Netty 心跳机制、零拷贝?
  • 说一说Netty中的编解码器
  • 说一说Netty中Handler的执行顺序
  • Netty中如何实现断线自动重连?
  • Netty中使用到了哪些设计模式?
  • Netty为什么要造一个FastThreadLocal?
  • Netty有哪些序列化协议?

Netty 的核心组件

从零开始手写RPC框架(番外) Netty基础知识点及常见面试题汇总_第1张图片

Netty由三层结构构成,1.网络通信层2事件调度层3.服务编排层。
在网络通信层有三个核心组件Bootstrap 、ServerBootstrap和Channel,Bootstrap负责客户端启动并去连接远程的Netty Server,ServerBootstrap是负责服务端的监听,监听指定的一个端口,Channel是负责网络通信的一个载体,事件调度器。
事件调度器有两个核心角色,EventLoopGroup和EventLoop,EventLoopGroup本质上是一个线程池,主要去负责接收IO请求并分配线程去执行处理请求,EventLoop相对于线程池里的一个具体线程。
在服务编排层有三个核心组件,ChannelHandler(消息处理器) 、 ChannelPipeline(ChannelHandler 对象链表)和ChannelHandlerContext。ChannelPipeline负责处理多个ChannelHandler,它会把多个ChannelHandler构成一个链去形成这样一个Pipeline,ChannelHandler主要是针对IO数据的一个处理器,数据接收后通过指定的一个lHandler进行处理,ChannelHandlerContext是用来保存ChannelHandler的上下文信息的。



Bytebuf(字节容器)

网络通信最终都是通过字节流进行传输的。 ByteBuf 就是 Netty 提供的一个字节容器,其内部是一个字节数组。 当我们通过 Netty 传输数据的时候,就是通过 ByteBuf 进行的。
我们可以将 ByteBuf 看作是 Netty 对 Java NIO 提供的ByteBuffer 字节容器的封装和抽象。为什么不直接使用 Java NIO 提供的 ByteBuffer 呢?因为 ByteBuffer 这个类使用起来过于复杂和繁琐。



Bootstrap 和 ServerBootstrap(启动引导类)

Bootstrap 是客户端的启动引导类/辅助类

EventLoopGroup group = new NioEventLoopGroup();
try {
   
	//创建客户端启动引导/辅助类:Bootstrap
	Bootstrap b = new Bootstrap();
	//指定线程模型
	b.group(group).
		......
	// 尝试建立连接
	ChannelFuture f = b.connect(host, port).sync();
	f.channel().closeFuture().sync();
} finally {
   
	// 优雅关闭相关线程组资源
	group.shutdownGracefully();
}

ServerBootstrap 是服务端的启动引导类/辅助类

// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
   
	//2.创建服务端启动引导/辅助类:ServerBootstrap
	ServerBootstrap b = new ServerBootstrap();
	//3.给引导类配置两大线程组,确定了线程模型
	b.group(bossGroup, workerGroup).
		......
	// 6.绑定端口
	ChannelFuture f = b.bind(port).sync();
	// 等待连接关闭
	f.channel().closeFuture().sync();
} finally {
   
	//7.优雅关闭相关线程组资源
	bossGroup.shutdownGracefully();
	workerGroup.shutdownGracefully();
}
  1. Bootstrap 通常使用 connect() 方法连接到远程的主机和端口,作为一个 Netty TCP 协议通信中的客户端。另外,Bootstrap 也可以通过 bind() 方法绑定本地的一个端口,作为 UDP 协议通信中的一端。
  2. ServerBootstrap通常使用 bind() 方法绑定本地的端口上,然后等待客户端的连接。
  3. Bootstrap 只需要配置一个线程组— EventLoopGroup ,而 ServerBootstrap需要配置两个线程组— EventLoopGroup ,一个用于接收连接,一个用于具体的 IO 处理。


Channel(网络操作抽象类)

Channel 接口是 Netty 对网络操作抽象类。通过 Channel 我们可以进行 I/O 操作。
一旦客户端成功连接服务端,就会新建一个 Channel 同该用户端进行绑定。

// 通过 Bootstrap 的 connect 方法连接到服务端
public Channel doConnect(InetSocketAddress inetSocketAddress) {
   
	CompletableFuture<Channel> completableFuture = new CompletableFuture<>();
	bootstrap.connect(inetSocketAddress).addListener((ChannelFutureListener)future -> {
   
		if (future.isSuccess()) {
   
			completableFuture.complete(future.channel());
		} else {
   
			throw new IllegalStateException();
		}
	});
	return completableFuture.get();
}

比较常用的Channel 接口实现类是 :
NioServerSocketChannel(服务端)
NioSocketChannel(客户端)
这两个Channel 可以和 BIO 编程模型中的ServerSocket 以及Socket 两个概念对应上。



Selector

Netty是基于Selector对象实现的I/O多路复用,通过Selector 一个线程可以监听多个连接的Channel事件。
当向一个Selector中注册Channel后,Selector可以自动不断地查询(Select)这些注册的Channel 是否有已就绪的I/O事件,这样程序就可以很简单地使用一个线程高效地管理多个Channel 。



EventLoop(事件循环)

EventLoop(事件循环)接口可以说是 Netty 中最核心的概念了。EventLoop 的主要作用实际就是责监听网络事件并调用事件处理器进行相关 I/O 操作(读写)
的处理。

那 Channel 和 EventLoop 直接有啥联系呢?Channel 为 Netty 网络操作(读写等操作)抽象类,EventLoop 负责处理注册到其上的Channel 的 I/O操作,两者配合进行 I/O 操作。

EventloopGroup 和 EventLoop 的关系:EventLoopGroup 包含多个 EventLoop(每一个 EventLoop 通常内部包含一个线程),它管理着所有的 EventLoop 的生命周期。并且,EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理,即 Thread 和 EventLoop 属于1 : 1 的关系,从而保证线程安全。

Netty 的设计原则之一是:同一个 Channel 的所有 I/O 操作都由同一个 EventLoop 来处理,这样可以保证同一个 Channel 的所有 I/O 操作都是由同一个线程按照顺序执行的,避免了多线程并发处理同一个 Channel 时需要进行线程同步的开销。如果你想要并行地执行多个 I/O 操作,你需要创建多个 Channel,每个 Channel 对应一个 I/O 操作。这样,这些 I/O 操作就可能会被不同的 EventLoop(也就是不同的线程)并行执行。

从零开始手写RPC框架(番外) Netty基础知识点及常见面试题汇总_第2张图片


NioEventLoopGroup 默认的构造函数会起多少线程?

回顾我们在上面写的服务器端的代码:

// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理

你可能感兴趣的:(微服务,从零开始手写RPC框架,rpc,网络协议,网络,开发语言)