Netty

I/O模型

java支持3种模型:BIO NIO AIO
BIO: 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求服务端就要启动一个线程进行处理
NIO: 同步非阻塞,服务器实现模式为一个线程处理多个连接,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到有io请求就进行处理
AIO: 异步非阻塞,引入Proactor模式,在有效的请求才启动线程,一般用于连接数较多且时间较长的应用


重点:多路复用


适用场景

1.bio适用于连接数比较小并且固定的架构,简单
2.nio适用于连接数多且连接时间比较短(轻操作)的架构,比如聊天服务
3.aio适用于连接数多且连接比较长的架构,如相册服务器,充分调用os参与并发操作

    public static void main(String[] args) throws IOException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        ServerSocket serverSocket = new ServerSocket(6666);
        while (true) {
            final Socket socket = serverSocket.accept();
            System.out.println("一个客户端");
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    handler(socket);
                }
            });
        }

    }

    public static void handler(Socket socket) {
        System.out.println("当前线程:"+Thread.currentThread().getName());
        byte[] bytes = new byte[1024];
        try {
            InputStream inputStream = socket.getInputStream();
            while (true) {
                int len = inputStream.read(bytes);
                if (len != -1) {
                    System.out.println(new String(bytes, 0, len));
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

bio缺点:
1.每个请求都要创建独立的线程,与对应客户端进行数据read,业务处理,数据write
2.当并发量较大时,需要创建大量线程处理连接,占用系统资源
3.连接建立后,如果当前线程暂时没有数据可读,线程阻塞在Read上,造成线程资源浪费

nio三大核心部分: channel(通道),Buffer(缓冲区),Selector(选择器)

nio buffer的使用


    public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(5);
        intBuffer.put(10);
        intBuffer.flip();
        while (intBuffer.hasRemaining()) {
            System.out.println(intBuffer.get());
        }
    }

nio channel

通道可以同时进行读写,而流是能读或者写
通道可以实现异步读写数据
通道可以从缓冲读取数据,也可以写数据到缓冲
常用Channel: FileChannel DatagramChannel ServerSockerChannel SockerChannel

buffer写文件
    public static void main(String[] args) throws IOException {
        String str = "hello,aaaa";
        FileOutputStream fileOutputStream = new   
        FileOutputStream("d:/e.txt");
        FileChannel fileChannel = fileOutputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byteBuffer.put(str.getBytes());
        byteBuffer.flip();
        fileChannel.write(byteBuffer);
        fileOutputStream.close();
    }
buffer读文件
    public static void main(String[] args) throws IOException {
        String str = "hello,bbb";
        File f = new File("d:/e.txt");
        FileInputStream fileInputStream = new FileInputStream(f);
        FileChannel fileChannel = fileInputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) f.length());
        fileChannel.read(byteBuffer);
        System.out.println(new String(byteBuffer.array()));
    }
channel读写文件
    public static void main(String[] args) throws IOException {
        String str = "hello,bbb";
        File f = new File("d:/e.txt");
        FileInputStream fileInputStream = new FileInputStream(f);
        FileChannel inputChannel = fileInputStream.getChannel();
        FileOutputStream fileOutputStream = new     FileOutputStream("D:/f.txt");
        FileChannel outputChannel = fileOutputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        while (true){
            byteBuffer.clear();
            int read = inputChannel.read(byteBuffer);
            if(read == -1){
                break;
            }
            byteBuffer.flip();
            outputChannel.write(byteBuffer);
        }
    }
使用transferFrom拷贝文件
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = new FileInputStream("D:\\vm\\CentOS-7-x86_64-DVD-1810.iso");
        FileChannel inputChannel = fileInputStream.getChannel();
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\g.iso");
        FileChannel outputChannel = fileOutputStream.getChannel();
        outputChannel.transferFrom(inputChannel,0,inputChannel.size());
    }

selector

selector能够检测多个注册的通道上是否有事件发生
多个channel以事件的方式可以注册到同一个selector,如果有事件发生,便获取事件然后针对每一个事件进行相应的处理,这样就可以用一个单线程去管理多个通道,也就是管理多个连接和请求




Netty简介

BossGroup和WatchGroup协同工作

Netty是JBoss提供的一个java开源框架
Netty是一个异步的,基于事件驱动的网络应用框架
BIO:每个客户端连接到服务端都会新增一个线程处理,会出现性能问题,会阻塞

NIO

同步非阻塞,服务器实现模式为一个线程处理多个请求
客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有io请求则进行处理

NIO和BIO比较


缓冲区Buffer


flip操作:切换buffer的读写状态,其实是将position重置为0


通道

通道可以同时进行读写,而流只能读或者写
通道可以实现异步读写数据
常用的有:FileChannel(文件读写),DatagramChannel(UDP读写),ServerSocketChannel和SocketChannel


Selector(选择器)

selector能够检测多个注册的通道上是否有事件发生
如果有事件发生,便获取事件然后针对每个事件进行相应的处理
这样可以用一个单线程去管理多个通道,也就是管理多个连接和请求




通过selectkey可以反向获取到channel

selectionKey

零拷贝

常用的零拷贝有mmap和sendFile
传统io的read方法:
1.先使用DMA将数据从硬盘读取到内核中,(DMA拷贝就是不通过cpu的直接内存拷贝)然后用cpu将数据从内核态缓冲区读取到用户态的缓冲区中
2.在用户态缓冲区中对数据进行修改
3.用cpu将用户态缓冲区数据拷贝到socket的缓冲区
4.将socket缓冲区的数据用DMZ拷贝到协议栈

传统io是进行4次拷贝,3次状态切换
优化方法:
mmap:少了一次拷贝
通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据,这样,在进行网络传输时,减少从内核空间到用户空间的拷贝次数

sendFile:
Linux2.1提供了sendFile函数,原理:数据根本不经过用户态,直接从内核缓冲区进入到socketbuffer,同时,由于和用户态完全无关,就减少了一次上下文切换

0拷贝不是不拷贝,而是没有cpu拷贝的意思,从硬盘出来的DMA拷贝是一定要存在的
Linux2.4做了一写修改,避免从内核缓冲区拷贝到socketbuffer操作,直接拷贝到协议栈
又少了一次数据的拷贝

mmap和sendfile的区别:

Netty架构设计

目前存在的线程模型:
1.传统阻塞I/O服务模型

采用阻塞io模式获取输入的数据
每个连接都需要独立的线程完成数据的输入,业务处理,数据返回
2.Reactor模式


Reactor一共有3中实现
Reactor模式,通过一个或多个输入同时传递给服务处理器的模式,基于事件驱动
服务端程序处理传入的多个请求,并将它们同步分派到相应的处理线程

1)单Reactor单线程

2)单Reactor多线程


3)主从Reactor多线程

Netty线程模式是基于主从Reactor多线程模型做了一定的改进,其中主从Reactor多线程模型有多个Reactor


Netty模型

简单版


复杂版


任务队列taskQueue

问题:在pineline中执行长时间操作会出现问题,应该将这些任务放到任务队列中

提交任务到队列中


这样就会把任务放到taskQueue执行,防止阻塞到handler中的某个方法中
如果在同一个方法中有两个任务执行,则会阻塞,因为是在同一方法中是同一线程执行
如果在handler中有长时间任务执行,则最好使用这种方式执行



提交任务到定时队列中


方案再说明

异步模型




Netty核心组件

Bootstrap,ServerBootStrap

Future,ChannelFuture

Channel


selector

ChannelHandler

Pipeline和ChannelPipeline


ChannelHandlerContext


Unpooled

posted @ 2021-03-02 11:37  余***龙  阅读(491)  评论(0编辑  收藏  举报