Netty实战一之异步和事件驱动
Netty是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端。
使用Netty你可以并不是很需要网络编程、多线程处理、并发等专业Java知识的积蓄。
Netty的架构方法和设计原则是:每个小点都和它的技术性内容一样重要,穷其精妙,因此我们也借此可以了解更多方面: 关注点分离——业务和网络逻辑解耦 模块化和可复用性 可测试性作为首要的要求
1、Java网络编程
早期的Java API只支持由本地系统套接字库(需要了解复杂的C语言套接字库)提供的所谓的阻塞函数。
以下给出阻塞I/O示例,代码清单1-1 代码清单1-1实习点了Socket API的基本模式之一。 ——ServerSocket上的accept()方法将会一直阻塞到一个连接建立,随后返回一个新的Socket用于客户端和服务器之间的通信。该ServerSocket将继续监听传入的连接。 ——BufferedReader和PrintWriter都衍生于Socket的输入输出流,前者从一个字符输入流中读取文本,后者打印对象的格式化的表示到文本输出流。 ——readLine()方法将会阻塞,直到由换行符或者回车符结尾的字符串被读取。
以上代码段可以明显看出,只能同时处理一个连接,要管理多个并发客户端,需要为每个新的客户端Socket创建一个新的Thread。如下图1-1所示
我们可以尝试着分析这个方案:
第一,在任何时候都可能又大量的线程处于休眠状态,只是等待输入或者输出数据,这可以算是一种资源浪费;
第二,需要为每个线程的调用栈分配内存,其默认值大小区间为64KB到1KB;
第三,即使JVM在物理上可以支持非常大的数量的线程,但是远在到达极限之前,上下文切换所带来的的开销就会有很多麻烦。
当然,这种并发方案对于支撑中小数量的客户端来说可以接收,但是为了支撑100000或更多的并发连接所需资源使得它很不理想。
2、Java NIO
除了阻塞调用,本地套接字库很早也提供了非阻塞调用,其为网络资源的利用率提供了相当多的控制:
——可以使用setsocket()方法配置套接字,以便读/写调用再没有数据的时候立即返回
(有关NIO的解释:新的I/O,非阻塞I/O)
3、选择器
图1-2展示了一个非阻塞设计,消除了上一节的弊端。 Java.nio.channels.Selector是java的非阻塞I/O实现的关键,使用时间通知API以确定在一组非阻塞套接字中,哪些已经就绪能够进行I/O相关的操作。
一个单一的线程便可以处理多个并发的连接。
与阻塞I/O模型相比,这种模型提供了更好的资源管理: ——较少的线程,减少了内存管理和上下文切换所带来的的开销 ——没有I/O操作时,线程可以用于其他任务
但是在高负载下可靠和高效地处理和调度I/O操作时一项繁琐而且容易出错的任务,即使Java NIO也很难完美解决这个问题。
4、Netty简介
首先我们一直要关注和注意到:直接使用底层的API暴露了复杂性,并且引入了对往往供不应求的技能的关键性依赖,这也是面向对象基本概念:用较简单的抽象隐藏底层实现的复杂性。
在网络编程领域,Netty是java的卓越框架,我们在了解Netty之前,先看看它具备的而且经常被提及的特性
设计 ——统一的API,支持多种传输类型,阻塞的和非阻塞的,简单而强大的线程模型,真正的无连接数据报套接字支持,链接逻辑组件以支持复用
易于使用 ——详实的JavaDoc和大量的示例集,不需要超过JDK1.6的依赖,最新版需要JDK1.8
性能 ——拥有比Java的核心API更高的吞吐量以及更低的延迟,得益于池化和复用,拥有更低的资源消耗,最少的内存复制
健壮性 ——不会因为慢速、快速或者超载的连接而导致OutOfMemoryError,消除在高速网络中NIO应用程序常见的不公平读/写比率
安全性 ——完整的SSL/TLS以及StarTLS支持,可用于受限环境下,如Applet和OSGI
社区驱动 ——发布快速而且频繁
5、异步和事件驱动
Netty中,或者说Netty的讲解中使用量较大的是“异步”这个词,因此我们也简述下所谓 异步 :通常,你只有在已经问了一个问题之后才会得到一个和它对应的答案,而在你等待它的同时你也可以做点别的事情。
本质上,对于计算机而言,一个既是异步的又是事件驱动的系统会表现出一种特殊的、对我来说极具价值的行为:它可以以任意的顺序响应在任意的时间点产生的事件。
实现最高级别的可伸缩性:一种系统、网络或者进程在需要处理的工作不断增长时,可以通过某种可行的方式或者扩大它的处理能力来适应这种增长的能力。
异步和可伸缩性之间的联系?
——非阻塞网络调用使得我们可以不必等待一个操作的完成,完全异步的I/O正是基于这个特性构建的,并且更进一步:异步方法会立即返回,并且在它完成时,会直接或者在稍后的某个时间点通知用户 ——选择器使得我们能够通过较少的线程便可监视许多连接上的事件。
至此,至少我们明显知道非阻塞是更优于阻塞的。
6、Netty的核心组件——Channel
Java NIO的一个基本构造,代表一个到实体的开放连接,如读操作和写操作,可以把Channel看作是传入或者传出数据的载体,因此它可以被打开或者被关闭,连接或者断开链接。
7、Netty的核心组件——回调
即一个方法,一个指向已经被提供给另外一个方法的方法的引用。回调在广泛的编程场景中都有应用,而且也是在操作完成之后通知相关方最常见的方式之一。
Netty在内部使用了回调来处理事件,当一个回调被触发时,相关的事件可以被一个interfaceChannelHandler的实现处理,代码清单1-2展示了一个例子,当一个新的连接已经被建立时,ChannelHandler的channelActive()回调方法将会被调用,并将打印一条信息。
8、Netty的核心组件——Future
Futrue提供了另一种在操作完成时通知应用程序的方式,这个对象可以看作是一个异步操作的结构的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。
JDK预置了interface java.util.concurrent.Future,但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成,这是比较繁琐,所以Netty提供了它自己的现实——ChannelFuture,用于在执行异步操作的时候使用。
ChannelFuture 提供了几种额外的方法,这些方法使得我们能够注册一个或者多个操作完成时被调用。然后监听器可以判断该操作是成功完成或出错,后者则会产生Throwable,简而言之,由ChannelFutureListener提供的通知机制消除了手动检查对应的操作是否完成的必要。
每个Netty的出站I/O操作都将返回一个ChannelFuture;也就是说,他们都不会阻塞,也就是说Netty完全是异步和事件驱动的。
代码清单1-3 展示了一个ChannelFuture作为一个I/O操作的一部分返回的例子,这里,connect()方法将会直接返回,而不会阻塞,该调用将会在后台完成。这究竟什么时候会发生则取决于若干的元素,但这个关注点已经从代码中抽象出来了,因为线程不用阻塞以等待对应的操作完成,所以它可以同时做其他的工作,从而更加有效地利用资源。
代码清单1-4 显示了如何利用ChannelFutureListener,首先,要连接到远程节点上,然后,要注册一个新的ChannelFutureListener到对connect()方法调用所返回的ChannelFuture上,当该监听器被通知连接已经建立的时候,要检查对应的状态。如果成功,那么将数据写到该Channel,否则,要从ChannelFuture中检索对应的Throwable。
需要注意的是,对错误的处理完全取决于你、目标,当然也包括目前任何对于特定类型的错误加以限制。
如果你把ChannelFutureListener 看作是回调的一个更加精细的版本,那么你是对的,事实上,回调和Future是相互补充的机制,他们相互结合,构成了Netty本身的关键构件块之一。
9、事件和ChannelHandler
Netty使用不同的事件来通知我们状态的改变或是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。
——记录日志
——数据转换
——流控制
——应用程序逻辑
Netty是一个网络编程框架,所以事件是按照他们与入站或出站数据流的相关性进行分类的
——连接已被激活或者连接失活
——数据读取
——用户事件
——错误事件
出站事件是未来将会触发的某个动作的操作结果,包括:
——打开或者关闭到远程节点的连接
——将数据写到或者冲刷到套接字
每个事件都可以被分发给ChannelHandler类中的某个用户实现的方法。这是一个将事件驱动范式直接转换为应用程序构件块的例子,图1-3展示了一个事件是如何被一个这样的ChannelHandler链处理的。
Netty的ChannelHandler为处理器提供了基本的抽象,如图1-3所示,目前我们可以认为每个ChannelHandler的实例都类似于一种为了响应特定事件而被执行的回调。
Netty提供了大量预定义的开箱即用的ChannelHandler实现,在内部,ChannelHandler自己也使用了事件和Future,使得它们成为了你的应用程序将使用的相同抽象的消费者。
10、本章回顾
有关于Future、回调、ChannelHandler
Netty的异步编程模型是建立在Future和回调的概念智商,而将事件派发到ChannelHandler的方法则发生在更深的层次上,结合在一起,提供了一个处理环境,使得我们的应用程序逻辑可以独立于任何网络操作相关的顾虑而独立地演变。
拦截操作以及高速地转换入站数据和出站数据,都只需要你提供回调或者利用操作所返回的Future,这使得链接操作变得即简单又高效,并且促进了可重用的通用代码的编写。
有关选择器、事件、EventLoop
Netty通过触发事件将Selector从应用程序中抽象出来,消除了所有本来将要需要手动编写的派发代码。在内部,将会为每个Channel分配一个EventLoop,用以处理所有事件: ——注册感兴趣的事件 ——将事件派发给ChannelHandler ——安排进一步的动作
EventLoop本身只由一个线程驱动,其处理了一个Channel的所有I/O事件,并且在该EventLoop的整个生命周期内都不会改变,我们并不用对同步有任何顾虑,仅仅需要专注于提供正确的逻辑。
Netty实战一之异步和事件驱动的更多相关文章
- 重磅!阿里P8费心整理Netty实战+指南+项目白皮书PDF,总计1.08G
前言 Netty是一款用于快速开发高性能的网络应用程序的Java框架.它封装了网络编程的复杂性,使网络编程和Web技术的最新进展能够被比以往更广泛的开发人员接触到. Netty不只是一个接口和类的集合 ...
- Netty实战三之Netty的组件和设计
有关Netty,我们可以从两个视角来讨论Netty:类库的视角以及框架的视角,对于使用Netty编写高效的.可重用的和可维护的代码来说,两者缺一不可. Netty解决了两个响应的关注领域,可以大致标志 ...
- Netty实战
一.Netty异步和事件驱动1.Java网络编程回顾socket.accept 阻塞socket.setsockopt /非阻塞2.NIO异步非阻塞a).nio 非阻塞的关键时使用选择器(java.n ...
- 1.Netty 实战前言
1.参考文档:Netty实战精髓篇 2.Netty介绍: Netty是基于Java NIO的网络应用框架. Netty是一个NIO client-server(客户端服务器)框架,使用Nett ...
- 关于Web开发里并发、同步、异步以及事件驱动编程的相关技术
一.开篇语 我的上篇文章<关于如何提供Web服务端并发效率的异步编程技术>又成为了博客园里“编辑推荐”的文章,这是对我写博客很大的鼓励,也许是被推荐的原因很多童鞋在这篇文章里发表了评论,有 ...
- Netty实现的一个异步Socket代码
本人写的一个使用Netty实现的一个异步Socket代码 package test.core.nio; import com.google.common.util.concurrent.ThreadF ...
- ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用!因此,ES transport client可以同步调用也可以异步(不过底层的socket必然是异步实现)
ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用! 因此,ES tra ...
- 《Netty实战》源码运行及本地环境搭建
1.源码路径: GitHub - zzzvvvxxxd/netty-in-action-cn: Netty In Action 中文版 ,中文唯一正版<Netty实战>的代码清单 下载后 ...
- 1.- Netty设计理念-异步和事件驱动
0. 关键点 a). 非阻塞网络调用,异步方法立即返回 b). 选择器(Selector)使得单一线程就可监控很多连接上的事件. <dependency> <groupId>i ...
随机推荐
- maven项目(多模块)
在eclipse下构建maven项目,该项目由多个子模块组成. 1.创建一个父项目 NEW -->project-->maven-->maven Project,点击下一步,进入ne ...
- 2016 安全圈玩起了直播,“学霸”带你玩转CTF_i春秋学院
2016安全圈玩起了直播,“学霸”带你玩转CTF_i春秋学院 从小就很羡慕学霸的脑子,总有很简单很便捷的方法解出难题来,所以对于他们的笔记总会疯狂地想占有和copy.那么,对CTF大神自己总结出来的赛 ...
- mysql命令行创建表,插入表数据
create table t_hero( id int unsigned auto_increment primary key, name varchar(10) unique not null, a ...
- C++ Opencv Mat类型使用的几个注意事项及自写函数实现Laplace图像锐化
为了提升自己对Opencv中Mat数据类型的熟悉和掌握程度,自己尝试着写了一下Laplace图像锐化函数,一路坎坷,踩坑不断.现将代码分享如下: #include <opencv2/opencv ...
- postgresql 安装文档
tar xf postgresql-9.4.5.tar.gz cd postgresql-9.4.5 yum grouplist yum grouplist|grep Deve yum groupin ...
- 解决Java中There is no getter for property XXX'XXX' in 'class XXX'的问题
当你出现There is no getter for property XXX'XXX' in 'class XXX'时, 就是在你的这个类中没有找到你这个属性. 检查两个地方 1.你的返回值类型是否 ...
- Python You-Get (送你一个免广告的视频和音乐网站 VIP)
You-get可以在仅仅提供URL情况下就可以实现下载视频.图片.音乐等信息.也可以通过播放器在线观看视频或听音乐,重要的是再也不用烦恼弹出的广告了,如果你想观看视频,但又不想观看广告,并且你还想把视 ...
- spring boot整合 springmvc+mybatis
需要以下依赖 <dependencies> <dependency> <groupId>org.springframework.boot</groupId&g ...
- python之获取当前操作系统(平台)
Python在不同环境平台使用时,需要判断当前是什么系统,比如常用的windows,linux等 下面介绍一些能够获取当前系统的命令 1.使用sys.platform获取 #!/usr/bin/env ...
- java提高(2)---正则表达式(1)常用符号
正则表达式---常用符号 首先声明,我这里列表的是经常使用的一些符号,如果你想得到全部,那建议你通过API中,搜索Pattern类,会得到所有符号. 字符类 [abc] a.b 或 c(简单类) [^ ...