netty-server端学习总结

NIO基础概念

REACTOR 模型

reactor 模型是基于事件驱动的, 它将不同的事件分配给不同的处理器执行.
Multiple reactors
Multiple reactors

  1. reactor 模型中的事件驱动, 是基于 i/o 多路复用机制实现的. 1 2
  2. selector, nio 中的多路复用器, 负责注册、处理事件.
  3. netty中, 基于 Multiple reactors , 即多响应器模型. 部分 reactor 只负责响应连接事件, 其它负责响应处理读写事件.

零拷贝

零拷贝技术减少了文件、socket 数据的读写过程, 这里只讨论 nio 中, 对零拷贝对使用.
linux 中的零拷贝的实现主要通过 mmap 与 sendfile 两种方式, mmap 简单说就是将内核态中的数据地址, 直接映射到用户态中, 从而用户可以跳过数据从内核态复制到用户态的过程, 而直接操作. sendfile 相较于 mmap 更进一步精简了功能, 它没有对数据地址进行映射, 通过这种方式, 只能将读取的数据存储到磁盘或soket发送出去, 性能进一步提升, 但也不能操作数据.

  1. nio 中, 使用直接内存实现 mmap 的零拷贝方式, MappedByteBuffer/DirectByteBuffer, DirectByteBuffer 是 MappedByteBuffer (abstract) 的子类, MappedByteBuffer 提供了它的实例方法 (直接内存不使用在JVM中申请的内存, 它只有在 full gc 时, 才会被清理. 使用直接内存, 一般会创建一个内存池, 用来重复使用).
  2. nio 中, FileChannel.transferTo()/transferFrom 都使用了 sendfile 的方式.

NETTY

netty 在 nio 的基础上进行了封装, 简化了 nio 复杂的处理逻辑与异常捕捉. 依据 multi reactors 模型, netty 的连接并发理论上可以做到极大(超出网络带宽的限制).

netty模版代码

public static void main(String[] args) throws InterruptedException {
   
            EventLoopGroup master = new NioEventLoopGroup(1);
            EventLoopGroup works = new NioEventLoopGroup();
        try {
   
            ServerBootstrap server = new ServerBootstrap();

            server.group(master,works)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
   
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
   
                            socketChannel.pipeline().addLast(new Encode());
                            socketChannel.pipeline().addLast(new Decode());
                            socketChannel.pipeline().addLast(new ServerChannelHandler());
                        }
                    });
            ChannelFuture sync = server.bind(12321).sync();
            sync.channel().closeFuture().sync();
        }finally {
   
            master.shutdownGracefully();
            master.shutdownGracefully();
        }
    }

netty 的服务代码非常简单. 下面是流程的概述:

  1. 首先创建两个线程池(NioEventLoopGroup, 参数为线程数量, 默认为两倍核数), 它们分别用来处理 accept 事件和 read 事件. 用来处理 accept 事件的线程池, 如果没有多个不同端口的 ServerSocketChannel 需要处理, 参数配置为 1 即可.
  2. 新建一个引导对象(ServerBootstrap). 将第一步创建的两个线程池作为参数传给它. option 方法用来添加网络编程的相关参数, childHandler 中添加通道处理器, 这些处理器是有方向的, read/write 分别对应实现了 channelInboundHandler/channelOutboundHandler 接口的处理器. 方向正确的处理器才会被调用. 通道中的所有处理器, 采用责任链统一处理.
  3. 所有参数添加完成后, 调用 server 的 bind() 方法, 这里会调用 nio 中 selector 的 select 方法, 服务开始正式运行. sync 方法, 会同步 bind 方法, 保证继续执行代码时, 绑定已经成功. closeFuture 方法是一个回调方法, 当 serverSocketChannel 关闭时, 才会被调用, 其后的 sync 同步方法, 将在它被正式调用前, 阻塞线程.
  4. netty 工作流程图
    在这里插入图片描述

源码流程

  1. 创建 NioEventLoopGroup对象.
	// nioeventLoopGroup 新建对象(无参), 最终会进入这个方法.
	//  nThread 是 0, executor 是 null, 
	// selectorProvider 是 nio 方法 SelectorProvider.provider() 创建的. 
	// selectStrategyFactory 是一个自定义的策略工厂 创建方法: DefaultSelectStrategyFactory.INSTANCE . 
	// RejectedExecutionHandlers.reject() 是线程池的拒绝策略, 它会简单的抛出异常
	public NioEventLoopGroup(int nThreads, Executor executor, SelectorProvider selectorProvider, SelectStrategyFactory selectStrategyFactory) {
   
		super(nThreads, executor, new Object[]{
   selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()});
    }
	// 当 nThreads 为 0 时, 会使用 DEFAULT_EVENT_LOOP_THREADS, 它的值等于两倍核数
	protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
   
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }
	// 多线程事件执行组对象创建方法
	protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
   
        if (nThreads <= 0) {
   
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }
		// 这里创建了执行器, 它主要负责创建新线程, 并对新的线程进行了一系列的复制, 添加组 等操作
        if (executor == null) {
   
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
		// 这里根据 参数确定线程池的线程数量.每一个EventExecutor也是一个“线程池”,不过它只有一个线程
        children = new EventExecutor[nThreads];
		// 为每一个事件执行器实例化对象
        for (int i = 0; i < nThreads; i ++) {
   
            boolean success = false;
            try {
   
            	// 类似线程池中的 worker 对象, 但有些不同. 任务队列不在group中统一维护, 而是将任务直接交给child,child中维护了一个queue,用来存储无法及时处理但任务.
            	// newChild 方法有多个实现, 这里是 NioEventLoopGroup 的实现. 如果确认服务器支持 epoll, 可以使用 EpollEventLoopGroup
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
   
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
   
                if (!success) {
   
                	... // 略
                }
            }
        }
	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值