楼子湾

导航

统计
 

1.netty是一个 异步\ 基于事件驱动网络应用

 

 

tcp/ip---->原生的JDK IO/网络---->nio--->netty----->RPC

AVRO 实现数据文件共享

https://netty.io/wiki/related-projects.html

AKKA: 

FLINK : 内存级的计算框架

SPARK: 内存级的计算框架

 

 

 

 

一.Netty介绍和应用场景

做基于网络的高并发,异步高性能的通信框架

互联网行业

游戏行业

大数据领域

BIO 同步阻塞, 适用于链接数目较小且固定的架构, 这种方式对服务器资源要求较高, 并发局限于应用中: 通过线程池改善实现多个客户的链接

NIO 同步非阻塞 一个线程处理多个请求, 即客户端发送的请求都会注册到多路复用器上, 多路复用器轮询到链接有I/O请求就会处理

NIO适用于链接数目多且链接比较段架构,比如聊天服务器弹幕系统 服务期间通讯等

Netty可以做长连接

AIO适用于链接数据较多且链接比较长 重操作 目前没有广泛使用

 

BIO编程简单流程

1.服务端启动给一个ServerSocket

2.客户端启动Socket对服务器进行通信,默认情况下服务端需要对每个客户建立一个线程与之通讯

3.客户端发出请求后, 先自选服务器是否有线程响应,如果没有则会等待,或者被拒绝

4.如果有响应, 客户端线程会等待线程结束后才继续执行

二.NIO

NIO三大核心部分:channer buffer selector

1.每一个channel都对应一个buffer

2.一个selector对应一个线程, 一个线程可以对应多个channel(连接)

3.多个channel可以注册到一个selector

4.程序切换到哪个channel是由事件决定的, Event就是一个很重要的概念

5.selector会根据不同的时间,在各个通道上切换

6.Buffer就是一个内存块,底层是有一个数组

7.数据的读取写入是通过Buffer, 这个和BIO本质区别, BIO中要么是输入流或者输出流, 不能双向,但是NIO的Bufer是可以读也可以写,需要使用方法 flip()切换  

8.channel是双向的,可以反映底层操作系统的情况,比如Linux底层的操作系统通道就是双向的

面向缓冲区 面向块编程

比较: bio面向流, nio面向块, 块比流高效很多

 

三.Buffer

四个属性:capacity limit position mark

常用方法: capacity () position() postion(int newPosition) 设置缓冲区的位置

limit() limit(int newLimit)    limit属性指的的第几个不是下角标比如 limit(3) 是第三个下脚标为2

clear()清除缓冲区  flip()读写切换---》重置mark和position

1.ByteBuffer常用方法: 

allocateDirect(int capacity) // 创建直接缓冲区

allocate(int capacity) 创建缓冲区

get() 从当前位置position上get, get之后position会自动 +1

get(int index) // 根据下脚标获取数据

听到11讲

put(byte b) // 从当前位置上添加,put之后,position会自动 +1

put(int index, byte b)// 从绝对位置上put即将元素放到下脚标为index的位置上

 

 

通道Channel,类似流,内置于JAVA流中

通道可以同时进行读写,而流自能读或者写

FileChannel: 用于文件数据读写

DatagramChannel:用户UDP数据读写

ServerSocketChannel 和 SocketChannel 用于TCP的数据读写

 常用方法FileChannle

read(ByteBuffer dst) : 从通道读取数据到缓冲区

write(ByteBuffer src): 把缓冲区的数据写入 通道

transferFrom(ReableByteChannel src, long position, long count), 从目标通道中复制数据到当前通道

transferTo(long position, long count, WritableByteChannel target), 把数据从当前通道复制给目标通道  零拷贝

 Buffer可以转为只读buffer

 

 

 

 

 

18讲

1.MappedByteBuffer 可以让文件直接在内存(堆外内存)中修改,而如何同步到文件由NIO完成

说明:1.MappedByteBuffer 可以让文件直接在内存(堆外内存)中修改,操作系统不需要拷贝一次

 

2.前面的读写都是通过一个Buffer完成, NIO还支持通过多个Buffer(即Buffer数组)完成读写操作,即Scatering(分散) 和 Gathering(聚合)

scattering:  将数据写入buffer时,可以采用buffer数组依次写入【分散】

Gathering: 从buffer读取数据时,可以采用buffer数组依次读取【聚合】

 

 

Selector(选择器)

1.基本介绍

JAVA

1)Seletor 能够检测多个注册的通道上是否有事件发生(注意:多个Channlel以事件的方式注册到同一个Selector),如果事件发生,便获取事件然后对每个事件进行处理,这样可以只用一个线程去管理多个通道,也就是管理多个连接和请求

2)只有在 连接/通道 真正有读写事件发生时,才会进行读写,大大减少系统开销,并且不同为每个连接都创建一个线程,不同去维护多个线程

3)避免了多线程之间的上下文切换导致的开销

 

特点:

1)Netty 的IO 线程 NioEventLoop聚合了Selector, 可以处理多个客户端连接

2)

Selector类的相关方法

Selector是一个抽象类

静态方法open();// 得到一个选择器对象

select(long timeout); // 监控所有注册的通道,当其中有IO操作进行时,将对应的SelectionKey加入到内部集合中并返回,参数用来设置超时时间

public Set<SelectionKey> selectionKeys(); // 从内部集合中得到所有的SelectionKey

Selector相关方法注意事项

selector.select: 阻塞

selector.select(1000) // 阻塞1000毫秒, 然后返回

selector.wakeup() 喚醒 selector

selector.selectNow// 不阻塞,立马返回

 

selector selectionKey serverSocketChannel socketChannel关系:

1.当客户段端连接时,会通过ServerSocketChannel得到对应的SocketChannel,ServerSocketChannel本身也要注册到Selector上,关心链接为连接Accept

2. Selector进行监听, select 方法,返回有事件发生的通道个数

3. 将SocketChannel注册到Selector上 register(Selector sel, int ops),  一个Selector可以注册多个SocketChannel

4. 注册后返回一个SelectionKey, 会和该Selector关联(集合)

5. 进一步得到各个SelectionKey(有事件发生的)

6. 再通过SelectionKey反向获取SockeyChannel,方法channel()

7.可以通过得到的Channel,完成业务处理

注意:客户端和服务端的SocketChannel要么同时配置为非阻塞要么都配置为阻塞

 

26讲

 SelectionKey

1)SelectionKey, 表示Selector和网络通道的注册关系,共4种:

int OP_Accept = 1 << 4: 有新网络连接可以accept,值未16(1向左位移4位)

int OP_CONNECT = 1 << 3; : 代表连接已经建立, 值为8

int OP_READ = 1 << 0: 代表度操作,值为1

int OP_WRITE = 1 << 2: 代表写操作,值为4

2)SelectionKey相关方法

selector();// 返回与之关联的Selector对象

channel(); // 得到与之关联的通道

attachment(); // 得到与之关联的共享数据

// interestOps(int ops); // 设置或者改变监听事件

isAcceptable(); 是否可以accept

isReadable(); 是否可以读

isWriteable(); 是否可以写

 

ServeSocketChannel

1)在服务端监听新的客户端socket的连接

2)相关方法

open();得到一个ServerSocketChannel通道

bind(SocketAddress local); 设置服务端端口

configureBlocking(boolean block); 设置阻塞或非阻塞模式,取值false表示采用非阻塞模式

accept(); 接受一个链接,返回代表这个连接的通道对象

register(Selector sel, int ops); 注册一个选择器并设置监听事件

 

SocketChannel

1)SocketChannel,网络IO通道,具体负责进行读写操作。NIO把缓冲区数据写入到通道,或者把通道的数据读到缓冲区

2)相关方法

open(); 得到一个SocketChannel通道

configureBlocking(boolean block); 设置阻塞或者非阻塞模式,取值false表示非阻塞么模式

connect(SocketAdress remote); 链接服务器

finishConnect(); 如果上面的方法链接失败,接下来就要通过该方法完成链接操作

write(Bytebuffer src); 往通道写数据

read(Bytebuffer dst); 从通道里读数据到缓冲区

register(Selector sel, int ips, Object att);  注册一个选择器并设置监听事件,最后一个参数可以设置共享数据

close();关闭通道 

 

NIO 网络编程应用示例-群聊系统

 

1.先编写服务端

1.1服务器启动并监听 6667

1.2服务器接收客户端消息,并实时转发(处理上线和下线)

2.编写客户端

1.1链接服务器

1.2发送消息

1.3接收消息

 

下次观看33讲

 NIO与零拷贝

是指从操作系统角度看的,是没有CPU拷贝

1)零拷贝网络编程的关键,

2)mmap(memery map 内存映射) sendFile

DMA(direct memeory access )拷贝:直接内存拷贝不使用CPU

mmap优化: 不是真正的零拷贝只是减少了一次拷贝

1)mmap通过内核映射, 将文件映射到内核缓冲区,同时,用户空间可以共享内核空间资源。这样,在进行网络传输时,就可以减少内核口空间到用户空间的拷贝次数

sendFile优化:拷贝减少为3次,状态减少为2次

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

3) Linux2.4中,做了一些修改,避免了从内核缓冲区拷贝到Socket buffer的操作, 从而再一次减少了数据拷贝

直接从kenel buffer到协议栈

这里其实有一次CPU拷贝kenel buffer -> scoket buffer 但是拷贝信息很少,比如 length, offset,消耗低,可以忽略

 

NIO零拷贝案例

transferTo传一个大文件

在window下最多8M一次, linux下可以一次传输

 

零拷贝的再次理解

1)零拷贝是从操作系统角度来说的,因为内核缓冲区之间,没有数据时重复的(只有kenel buffer一份数据)

2)零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,例如更少的上下文切换,更少的CPU缓存伪共享及无CPU校验和计算

零拷贝是进行网络数据传输的非常重要的优化手段

mmap 和 sendFile的区别

1)mmap 适合小数据读写,sendFile适合大文件传输

2) mmap  需要4次(也可以说3次从中间计算)上下文切换, 3次数据拷贝; sendFile 需要 3次上下文切换,最少2次数据拷贝

3)sendFile可以利用DMA方式,减少CPU拷贝, mmap则不能(必须从内核拷贝到Socket缓冲区)

 

 

Netty概述

原生NIO存在的问题

1)NIO的类库和API繁杂

 

Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.

 

 

Netty官网说明

1)Netty室友JBOSS提供的一个Java开源框架。Netty提供异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠的网络IO程序

2)Netty可以帮助你快速、简单的开发出一个网络应用,相当于简化和流程化NIO的开发过程

3)Netty是目前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,知名的Elasticsearch 、Dubbo框架内部都采用了Netty

 

线程模型基本介绍

1)目前存在的现成模型

传统阻塞 I/O服务模型

Reactor模式

2)根据Reactor的数量和处理资源池线程的数量不同,有3中典型的实现 

单Reactor单线程

单Reactor多线程

主从 Reactor多线程

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

 

传统阻塞I/O服务模型

工作原理图

行色的框表示对象,蓝蓝色的框表示线程

白色的框表示方法(API)--->实线框

模型特点

1)采用阻塞IO模式获取输入的数据

2)每个连接都需要独立的线程完成数据的输入,业务处理,数据返回

问题分析

1)当并发数很大,就会创建大量的线程,占用很大的系统资源

2) 链接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作上造成线程资源的浪费

 

Netty的核心组件

Bootstrap ServerBootstrap

ServerBootstrap的handle给bossGroup加处理器;childHandle给workerGroup加处理器

Future ChannelFuture

1)Netty中所有的IO操作都是异步的 可以通过Future和ChannelFuture注册监听

2)常见方法:

Channel channel() 返回当前正在进行IO操作的通道

ChannelFuture sync() 等待异步操作执行完毕, 把同步变成异步操作

Channel

NioServerSocketChannel

NioSocetChannel

 

posted on 2020-06-08 18:48  楼子湾  阅读(...)  评论(...编辑  收藏