您现在的位置是:首页 > 文章详情

传统同步阻塞式I/O模型(BIO)

日期:2019-01-26点击:496

传统BIO编程

网络编程的基本模型是Client/Server模型,就是两个进程之间进行相互通信,Server端提供绑定的IP地址和监听端口,客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连接,建立成功之后就可以通过Socket通信。在BIO模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作,连接成功后双方通过输入输出流进行BIO通信。

BIO通信模式

采用BIO通信模型的Server端,通常由一个独立的Acceptor线程负责监听客户端的连接,接受到服务端的请求后为每个客户端创建一个新的线程进行链路处理,处理完成后通过输出流返回应答给客户端,线程销毁。如图
image

基于BIO实现的TimeServer

https://github.com/chenjian44/netty_readings_note/tree/master/bio/SyncBlockingIO

弊端分析

缺乏弹性伸缩能力,当客户端访问量增加的时候,服务端的线程个数和客户端并发访问数为1:1的关系,由于线程是jvm宝贵的资源,线程膨胀之后,系统性能急剧下降,随着访问量继续增加,系统便会发生线程堆栈溢出、创建线程失败等问题,并最终导致宕机或者僵死,不能再对外提供服务。

伪异步IO编程

伪异步编程后端通过一个线程池来处理多个客户端的请求接入,形成客户端最大数M:和线程池最大数N的对应关系,M可以远大于N,通过线程池可以灵活调配线程资源,设置线程的最大值,防止由于海量线程并发接入导致线程耗尽。

伪异步通信模式

采用线程池和任务队列实现,当有新的客户端接入时,将客户端的Socket封装成一个Task(实现Runable接口)投递到后端的线程池中处理,JDK的线程池维护一个消息队列和N个活跃线程对消息队列中的任务进行处理。由于线程池可以设置消息队列的大小和最大的线程数,因此资源占用是可控的,所以更多客户端并发访问,并不会导致资源的耗尽和宕机。如图
image

伪异步IO实现的TimeServer

https://github.com/chenjian44/netty_readings_note/tree/master/bio/PseAsyncIO

弊端分析

伪异步IO的读和写操作都是同步阻塞的,阻塞的时间取决于对方IO线程的处理速度和网络IO的传输速度。因为无法保证生产环境的网络状况和端的应用程序足够快,它的可靠性就非常差。伪异步IO只是对之前IO线程模型的一个简单优化,无法从根本上解决同步IO导致的通信线程阻塞的问题。如果通信对方返回的应答时间过长,会引起的级联故障分析:

  • 服务端处理缓慢,返回应答消息耗费60s,平时只需要10s;
  • 伪异步IO的线程正在读取故障服务节点的响应,由于输入流是阻塞的,它也会被同步阻塞60s;
  • 假如所有的可用线程都被故障服务器阻塞,那后续的IO消息都将zai队列中排队;
  • 由于线程池采用阻塞队列实现,当队列积满后,后续入队的操作将被阻塞
  • 由于前端只有一个Acceptor线程接受客户端接入,它被阻塞在线程池的同步阻塞队列之后,新的客户端请求消息将被拒绝,客户端会发生大量的连接超时;
  • 由于几乎所有的连接都超时,调用者会认为系统已经崩溃,无法接受新的请求消息;
原文链接:https://yq.aliyun.com/articles/689084
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章