同步操作将从 后端研发Marion/marion-notes 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
随着5G应用、多终端应用、物联网应用、工业互联应用、大数据应用、人工智能应用的飞速发展,高并发开发时代已然到来,能够驾驭高并发和大数据的物联网架构师、高并发架构师、大数据架构师、Java高级工程师在人才市场也随之成为“香饽饽”,Netty、Redis、ZooKeeper、高性能HTTP服务器组件(如Nginx)、高并发Java组件(JUC包)等则成为广大Java工程师所必须掌握的开发技能。
1.1.1 Netty火热的程度
Java NIO类库包含以下三个核心组件:
3.1.1 NIO和OIO的对比
(1)OIO是面向流(Stream Oriented)的,NIO是面向缓冲区(Buffer Oriented)的。
(2)OIO的操作是阻塞的,而NIO的操作是非阻塞的。
(3)OIO没有选择器(Selector)的概念,而NIO有选择器的概念。
3.1.2 通道
3.1.3 选择器
IO多路复用编程的第一步是把通道注册到选择器中,第二步是通过选择器所提供的事件查询(select)方法来查询这些注册的通道是否有已经就绪的IO事件(例如可读、可写、网络连接完成等)。
3.1.4 缓冲区
NIO的Buffer本质上是一个内存块,既可以写入数据,也可以从中读取数据。Java NIO中代表缓冲区的Buffer类是一个抽象类,位于java.nio包中。
3.2.1 Buffer类
3.2.2 Buffer类的重要属性
Buffer类的position属性表示当前的位置。position属性的值与缓冲区的读写模式有关
写模式下
读模式下
Buffer的读写模式具体如何切换呢?
Buffer类的limit属性表示可以写入或者读取的数据最大上限,其属性值的具体含义也与缓冲区的读写模式有关。
3.3 详解NIO Buffer类的重要方法
本节将详细介绍Buffer类的几个常用方法,包含Buffer实例的创建、写入、读取、重复读、标记和重置等。
3.3.1 allocate()
3.3.2 put()
3.3.3 flip()
向缓冲区写入数据之后,是否可以直接从缓冲区读取数据呢?不能!这时缓冲区还处于写模式,如果需要读取数据,要将缓冲区转换成读模式。fip()翻转方法是Buffer类提供的一个模式转变的重要方法,作用是将写模式翻转成读模式。
在读取完成后,如何再一次将缓冲区切换成写模式呢?
3.3.4 get()
缓冲区是不是可以重复读呢?
3.3.5 rewind()
已经读完的数据,如果需要再读一遍,可以调用rewind()方法。rewind()也叫倒带,就像播放磁带一样倒回去,再重新播放。
rewind ()方法主要是调整了缓冲区的position属性与mark属性
3.3.6 mark()和reset()
3.3.7 clear()
3.3.8 使用Buffer类的基本步骤
3.4 详解NIO Channel类
Java NIO中一个socket连接使用一个Channel来表示 (1)FileChannel:文件通道,用于文件的数据读写。 (2)SocketChannel:套接字通道,用于套接字TCP连接的数据读写。 (3)ServerSocketChannel:服务器套接字通道(或服务器监听通道),允许我们监听TCP连接请求,为每个监听到的请求创建一个SocketChannel通道。 (4)DatagramChannel:数据报通道,用于UDP的数据读写。
3.4.1 FileChannel
3.4.2 使用FileChannel完成文件复制的实战案例
3.4.3 SocketChannel
在NIO中,涉及网络连接的通道有两个:一个是SocketChannel,负责连接的数据传输;另一个是ServerSocketChannel,负责连接的监听。其中,NIO中的SocketChannel传输通道与OIO中的Socket类对应,NIO中的ServerSocketChannel监听通道对应于OIO中的ServerSocket类。
3.4.4 使用SocketChannel发送文件的实战案例
3.4.5 DatagramChannel
3.4.6 使用DatagramChannel发送数据的实战案例
3.5 详解NIO Selector
3.5.1 选择器与注册
简单地说,选择器的使命是完成IO的多路复用,其主要工作是通道的注册、监听、事件查询。一个通道代表一条连接通路,通过选择器可以同时监控多个通道的IO(输入输出)状况。选择器和通道的关系是监控和被监控的关系。
在NIO编程中,一般是一个单线程处理一个选择器,一个选择器可以监控很多通道。所以,通过选择器,一个单线程可以处理数百、数千、数万甚至更多的通道
可供选择器监控的通道IO事件类型
什么是IO事件?
3.5.2 SelectableChannel
3.5.3 SelectionKey
3.5.4 选择器使用流程
(1)获取选择器实例。选择器实例是通过调用静态工厂方法open()来获取的
(2)将通道注册到选择器实例
(3)选出感兴趣的IO就绪事件(选择键集合)
用于选择就绪的IO事件的select()方法有多个重载的实现版本
3.5.5 使用NIO实现Discard服务器的实战案例
3.5.6 使用SocketChannel在服务端接收文件的实战案例
3.5 详解NIO Selector
Java NIO的三大核心组件是Channel(通道)、Buffer(缓冲区)、Selector(选择器)。其中,通道和缓冲区的联系比较密切:数据总是从通道读到缓冲区内,或者从缓冲区写入通道中
4.3.1 多线程版本的Reactor模式演进
4.3.2 多线程版本Reactor的实战案例
4.3.3 多线程版本Handler的实战案例
(1)Reactor模式和生产者消费者模式对比
(2)Reactor模式和观察者模式对比
Reactor模式的优点
Reactor模式的缺点
Netty是一个Java NIO客户端/服务器框架,是一个为了快速开发可维护的高性能、高可扩展的网络服务器和客户端程序而提供的异步事件驱动基础框架和工具
5.1.1 创建第一个Netty项目
5.1.2 第一个Netty服务端程序
5.1.3 业务处理器NettyDiscardHandler
5.1.4 运行NettyDiscardServer
5.2.1 回顾Reactor模式中IO事件的处理流程
5.2.2 Netty中的Channel
5.2.3 Netty中的Reactor
5.2.4 Netty中的Handler
通道IO事件类型
Netty的Handler分为两大类:第一类是ChannelInboundHandler入站处理器;第二类是ChannelOutboundHandler出站处理器,二者都继承了ChannelHandler处理器接口
在通道中发生了OP_READ事件后,会被EventLoop查询到,然后分发给ChannelInboundHandler入站处理器,调用对应的入站处理的read()方法。在ChannelInboundHandler入站处理器内部的read()方法具体实现中,可以从通道中读取数据。
在应用程序完成业务处理后,可以通过ChannelOutboundHandler出站处理器将处理的结果写入底层通道。
5.2.5 Netty中的Pipeline
Netty的Reactor模式实现中各个组件之间的关系
Bootstrap类是Netty提供的一个便利的工厂类,可以通过它来完成Netty的客户端或服务端的Netty组件的组装,以及Netty程序的初始化和启动执行。Netty的官方解释是,完全可以不用这个Bootstrap类,可以一点点去手动创建通道、完成各种设置和启动注册到EventLoop反应器,然后开始事件的轮询和处理,但是这个过程会非常麻烦。通常情况下,使用这个便利的Bootstrap工具类的效率会更高。
5.3.1 父子通道
5.3.2 EventLoopGroup
5.3.3 Bootstrap启动流程
Bootstrap的启动流程也就是Netty组件的组装、配置,以及Netty服务器或者客户端的启动流程。在本节中对启动流程进行了梳理,大致分成8个步骤。
第1步:创建反应器轮询组,并设置到ServerBootstrap引导类实例
第2步:设置通道的IO类型。
第3步:设置监听端口
第4步:设置传输通道的配置选项
第5步:装配子通道的Pipeline。
第6步:开始绑定服务器新连接的监听端口
第7步:自我阻塞,直到监听通道关闭
第8步:关闭EventLoopGroup
5.3.4 ChannelOption
5.4.1 Channel的主要成员和方法
通道接口中所定义的几个重要方法
5.4.2 EmbeddedChannel
整个IO处理操作环节大致包括从通道读数据包、数据包解码、业务处理、目标数据编码、把数据包写到通道,然后由通道发送到对端
5.5.1 ChannelInboundHandler入站处理器
5.5.2 ChannelOutboundHandler出站处理器
5.5.3 ChannelInitializer通道初始化处理器
5.5.4 ChannelInboundHandler的生命周期的实战案例
前面讲到,一条Netty通道需要很多业务处理器来处理业务。每条通道内部都有一条流水线(Pipeline)将Handler装配起来。Netty的业务处理器流水线ChannelPipeline是基于责任链设计模式(Chain of Responsibility)来设计的,内部是一个双向链表结构,能够支持动态地添加和删除业务处理器。
5.6.1 Pipeline入站处理流程
5.6.2 Pipeline出站处理流程
5.6.3 ChannelHandlerContext
流水线ChannelPipeline中的双向链接实质是一个由ChannelHandlerContext组成的双向链表。作为Context的成员,无状态的Handler关联在ChannelHandlerContext中。
Channel、Handler、ChannelHandlerContext三者的关系
5.6.4 HeadContext与TailContext
5.6.5 Pipeline入站和出站的双向链接操作
5.6.6 截断流水线的入站处理传播过程
5.6.7 在流水线上热插拔Handler
5.7.1 ByteBuf的优势
5.7.2 ByteBuf的组成部分
5.7.3 ByteBuf的重要属性
5.7.4 ByteBuf的方法
第一组:容量系列
第二组:写入系列
isWritable()
第三组:读取系列
5.7.5 ByteBuf基本使用的实战案例
5.7.6 ByteBuf的引用计数
5.7.7 ByteBuf的分配器
5.7.8 ByteBuf缓冲区的类型
5.7.9 两类ByteBuf使用的实战案例
5.7.10 ByteBuf的自动创建与自动释放
方式一:TailContext自动释放
方式二:SimpleChannelInboundHandler自动释放
5.7.11 ByteBuf浅层复制的高级使用方式
概述
(1)固定长度数据包解码器——FixedLengthFrameDecoder
(2)行分割数据包解码器——LineBasedFrameDecoder
(3)自定义分隔符数据包解码器——DelimiterBasedFrameDecoder
(4)自定义长度数据包解码器——LengthFieldBasedFrameDecoder
6.2.1 LineBasedFrameDecoder解码器
6.2.2 DelimiterBasedFrameDecoder解码器
6.2.3 LengthFieldBasedFrameDecoder解码器
LengthFieldBasedFrameDecoder构造器
(1)maxFrameLength:发送的数据包的最大长度。示例程序中该值为1024,表示一个数据包最多可发送1024字节。
(2)lengthFieldOffset:长度字段偏移量,指的是长度字段位于整个数据包内部字节数组中的下标索引值。
(3)lengthFieldLength:长度字段所占的字节数。如果长度字段是一个int整数,则为4;如果长度字段是一个short整数,则为2。
(4)lengthAdjustment:长度的调整值。这个参数最为难懂。在传输协议比较复杂的情况下,例如协议包含了长度字段、协议版本号、魔数等,那么解码时就需要进行长度调整。长度调整值的计算公式为:内容字段偏移量-长度字段偏移量-长度字段的字节数。这个公式一看就比较复杂,下一小节会有详细的举例说明。
(5)initialBytesToStrip:丢弃的起始字节数。在有效数据字段Content前面,如果还有一些其他字段的字节,作为最终的解析结果可以丢弃。例如,在上面的示例程序中,前面有4字节的长度字段,它起辅助的作用,最终的结果中不需要这个长度,所以丢弃的字节数为4。
6.2.4 多字段Head-Content协议数据包解析的实战案例
6.3.1 MessageToByteEncoder编码器
6.3.2 MessageToMessageEncoder编码器
我们在开发一些远程过程调用(RPC)的程序时通常会涉及对象的序列化/反序列化问题,例如一个Person对象从客户端通过TCP方式发送到服务端
JSON的可读性较强。这种方式的缺点是它的性能稍差
如何选择序列化/反序列化框架呢?
Netty也提供了相应的编解码器,为Protobuf解决了有关Socket通信中“半包、粘包”等问题。
7.3.1 一个简单的proto文件的实战案例
7.3.2 通过控制台命令生成POJO和Builder
7.3.3 通过Maven插件生成POJO和Builder
7.3.4 Protobuf序列化与反序列化的实战案例
本章结合分布式缓存Redis、分布式协调ZooKeeper、高性能通信Netty,从架构的维度设计一套亿级IM的高并发架构方案
15.1.1 亿级流量的系统架构的开发实战
15.1.2 高并发架构的技术选型
15.1.3 详解IM消息的序列化协议选型
15.1.4 详解长连接和短连接
15.2.1 IM节点的POJO类
15.2.2 IM节点的ImWorker类
所有的工作节点都在ZooKeeper的同一个父节点下创建顺序节点,然后从返回的临时路径上取得属于自己的后缀编号
这里有三个ZNode相关的路径:MANAGE_PATH、pathPrefix和pathRegistered
在高并发的IM系统中,负载均衡需要将IM长连接分摊到不同的Netty服务器,防止单个Netty服务器负载过大,从而导致其不可用。
15.3.1 ImLoadBalance负载均衡器
短连接网关WebGate需要通过查询ZooKeeper集群来获得最佳的Netty服务器。定义一个负载均衡器ImLoadBalance类,将计算最佳Netty服务器的算法放在负载均衡器中
短连接网关WebGate会调用getBestWorker()方法取得最佳的IM服务器。
15.3.2 与WebGate的整合
15.4.1 IM路由器WorkerRouter
为每一个Worker节点增加一个IM路由器类,名为WorkerRouter
WorkerRouter路由器使用Curator的TreeCache缓存订阅了节点的NODE_ADDED节点添加消息。当一个新的Netty节点加入时,调用processNodeAdded(data)方法在本地保存一份节点的POJO信息,并且建立一个消息中转的Netty客户连接。
WorkerRouter路由器有一个容器成员workerMap,用于封装和保存所有的在线节点
因为WorkerRouter路由器的主要作用除了路由节点,还需要进行消息的转发,所以WorkerRouter路由器保存的是转发器PeerSender,而添加的远程Netty节点的POJO信息被封装在转发器中
15.4.2 IM转发器PeerSender
利用ZooKeeper可以实现一个集群共享的计数器,只要使用相同的path就可以得到最新的计数器值,这是由ZooKeeper的一致性保证的。
15.5.1 Curator的分布式计数器
15.5.2 用户上线和下线的统计
XMind - Trial Version
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。