logo资料库

架构师特刊:深入浅出Netty(李林峰)--精品.pdf

第1页 / 共106页
第2页 / 共106页
第3页 / 共106页
第4页 / 共106页
第5页 / 共106页
第6页 / 共106页
第7页 / 共106页
第8页 / 共106页
资料共106页,剩余部分请下载后查看
_1459336704
_1459336813
_1459337051
_1459336728
1 架构师特刊:深入浅出Netty
序言 最近几年,Netty 社区的发展如火如荼,无论是大数据领域,还是微服 务架构,底层都需要一个高效的分布式通信框架作为基础组件。 Netty 凭借优异的性能、灵活的可扩展新得到了广泛的应用。短短几年间, Netty 已经成为众多 Java 高性能异步通信框架的首选。 作为 Java 语言领域最流行、表现最优异的 NIO 框架,Netty 深受大家喜爱, 但是长期以来除了 UserGuide 之外,国内鲜有 Netty 相关的 系统性文章供广大 NIO 编程爱好者学习和参考。由于 Netty 源码的复杂 性和 NIO 编程本身的技术门槛限制,对于大多数初学者而言,通过 自己阅读和分析源码来深入掌握 Netty 的设计原理和实现细节是件非常 困难的事情。 为了方便大家系统性的学习 Netty,2014 年春节前后,我分享了博文 2 架构师特刊:深入浅出Netty
《Netty5.0 架构剖析和源码解读》,短短几个月的时间,阅读和下载量超过 10 万次。很多网友建议我能够继续按照专题的形式分析和解析 Netty 的架构 和源码,以及实际应用案例。于是从 2014 年 5 月份开始,我正式在 InfoQ 社 区分享 Netty 相关的专题文章,涉及到性能、可靠性、编解码、定制性以及 案例剖析等。这些文章深受大家的喜爱,几乎每期都是热点内容排名 TOP5。 2 年多的时间,在 InfoQ 分享的 Netty 专题文章超过 10 篇,通过其它方 式也陆续分享了一些 Netty 的实际案例,为了便于大家集中学习,很有必要 对这些已经发表的文章进行汇总和提取,形成一本迷你书,奉献给各位读者。 感谢主编郭蕾的帮助和支持,InfoQ 上的 Netty 专题,都是由他亲自策划、 编辑和校审的。感谢 InfoQ 这个平台,为广大 Netty 爱好者提供了免费 学习和交流的技术乐土。 由于自身水平所限,文章难免存在遗漏或者错误,欢迎广大读者批评指正。 李林峰 3 架构师特刊:深入浅出Netty
目录 01 Netty 入门 02 Netty 服务端创建 03 Netty 客户端创建 04 Netty 消息的发送和接收 05 Netty 线程模型 06 Netty 架构剖析 07 Netty 案例集锦 4 架构师特刊:深入浅出Netty
1 Netty 入门 1.1 传统的BIO编程 网络编程的基本模型是 Client/Server 模型,也就是两个进程之间 进行相互通信,其中服务端提供位置信息(绑定的 IP 地址和监听端口),客 户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连 接,如果连接建立成功,双方就可以通过网络套接字(Socket)进行通信。 在基于传统同步阻塞模型开发中,ServerSocket 负责绑定 IP 地址, 启动监听端口;Socket 负责发起连接操作。连接成功之后,双方通过输入和 输出流进行同步阻塞式通信。 1.1.1 BIO 通信模型图 首先,我们通过图 2-1 所示的通信模型图来熟悉下 BIO 的服务端通信模型: 采用 BIO 通信模型的服务端,通常由一个独立的 Acceptor 线程负责监听客户端 的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路 处理,处理完成之后,通过输出流返回应答给客户端,线程销毁。这就是典型的 一请求一应答通信模型。 5 架构师特刊:深入浅出Netty
图 1-1 同步阻塞 I/O 服务端通信模型(1 客户端 1 线程) 该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增 加后,服务端的线程个数和客户端并发访问数呈 1:1 的正比关系,由于线程 是 Java 虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将急剧 下降,随着并发访问量的继续增大,系统会发生线程堆栈溢出、创建新线程 失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务。 1.2 伪异步I/O编程 为了解决同步阻塞 I/O 面临的一个链路需要一个线程处理的问题,后来有人 对它的线程模型进行了优化,后端通过一个线程池来处理多个客户端的请求接入, 形成客户端个数 M:线程池最大线程数 N 的比例关系,其中 M 可以远远大于 N, 通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量并发接 入导致线程耗尽。 下面,我们结合连接模型图和源码,对伪异步 I/O 进行分析,看它是否能够 解决同步阻塞 I/O 面临的问题。 1.2.1 伪异步 I/O 模型图 采用线程池和任务队列可以实现一种叫做伪异步的 I/O 通信框架,它的模型 图如图 1-2 所示。 当有新的客户端接入的时候,将客户端的 Socket 封装成一个 Task(该任务 实现 java.lang.Runnable 接口)投递到后端的线程池中进行处理,JDK 的线程 6 架构师特刊:深入浅出Netty
池维护一个消息队列和 N 个活跃线程对消息队列中的任务进行处理。由于线程池 可以设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多 少个客户端并发访问,都不会导致资源的耗尽和宕机。 图 1-2 伪异步 I/O 服务端通信模型(M:N) 伪异步 I/O 实际上仅仅只是对之前 I/O 线程模型的一个简单优化,它无法从 根本上解决同步 I/O 导致的通信线程阻塞问题。下面我们就简单分析下如果通信 对方返回应答时间过长,会引起的级联故障。 1. 服务端处理缓慢,返回应答消息耗费60s,平时只需要10ms。 2. 采用伪异步I/O的线程正在读取故障服务节点的响应,由于读取输入流是 阻塞的,因此,它将会被同步阻塞60s。 3. 假如所有的可用线程都被故障服务器阻塞,那后续所有的I/O消息都将在 队列中排队。 4. 由于线程池采用阻塞队列实现,当队列积满之后,后续入队列的操作将被 阻塞。 5. 由于前端只有一个Accptor线程接收客户端接入,它被阻塞在线程池的同 步阻塞队列之后,新的客户端请求消息将被拒绝,客户端会发生大量的连 接超时。 6. 由于几乎所有的连接都超时,调用者会认为系统已经崩溃,无法接收新的 7 架构师特刊:深入浅出Netty
请求消息。 1.3 NIO编程 在介绍 NIO 编程之前,我们首先需要澄清一个概念:NIO 到底是什么的简称? 有人称之为 New I/O,因为它相对于之前的 I/O 类库是新增的,所以被称为 New I/O,这是它的官方叫法。但是,由于之前老的 I/O 类库是阻塞 I/O,New I/O 类 库的目标就是要让 Java 支持非阻塞 I/O,所以,更多的人喜欢称之为非阻塞 I/ O(Non-block I/O),由于非阻塞 I/O 更能够体现 NIO 的特点,所以本文使用的 NIO 都指的是非阻塞 I/O。 与 Socket 类 和 ServerSocket 类 相 对 应,NIO 也 提 供 了 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现。这两种新增的通道都支持阻 塞和非阻塞两种模式。阻塞模式使用非常简单,但是性能和可靠性都不好,非阻 塞模式则正好相反。开发人员一般可以根据自己的需要来选择合适的模式,一般 来说,低负载、低并发的应用程序可以选择同步阻塞 I/O 以降低编程复杂度,但 是对于高负载、高并发的网络应用,需要使用 NIO 的非阻塞模式进行开发。 1.4 AIO编程 NIO2.0 引入了新的异步通道的概念,并提供了异步文件通道和异步套接字 通道的实现。异步通道提供两种方式获取获取操作结果: • 通过java.util.concurrent.Future类来表示异步操作的结果; • 在执行异步操作的时候传入一个java.nio.channels; • CompletionHandler接口的实现类作为操作完成的回调。 NIO2.0 的异步套接字通道是真正的异步非阻塞 I/O,它对应 UNIX 网络编程 中的事件驱动 I/O(AIO),它不需要通过多路复用器(Selector)对注册的通 道进行轮询操作即可实现异步读写,从而简化了 NIO 的编程模型。 1.5 几种I/O模型对比 不同的 I/O 模型由于线程模型、API 等差别很大,所以用法的差异也非常大。 8 架构师特刊:深入浅出Netty
分享到:
收藏