引言:
本周自己重新对底层通讯方式进行了学习,在此做一个输出。
分别从客户端发送多个请求的需求角度与服务端接收多个连接发送请求的需求角度,剖析4种基于java自身技术实现的消息方式通讯所带来的影响,解决方式以及各自通讯方式的区别和优缺点。
通讯协议的特性:
4种组合通讯方式区别和优缺点剖析:
TCP/IP+BIO:
对于客户端同时发送多个请求到服务端的问题:
简单直接的解决方式:生成多个socket连接
上述解决方式带来的影响:
1.生成太多的socket客户端会消耗大量的本地资源,当客户端机器多,服务端机器少时,客户端生成太多的socket会导致服务器端需要支撑非常高的连接数。
2.生成socket连接的过程通常是比较慢的,频繁创建会导致系统性能不足的问题。
针对上述影响问题的常见解决方案:
1.通常采用连接池的方式来维护socket连接,好处:一方面限制了能创建socket的个数,另一方面连接池避免了重复创建socket。
连接池方式带来的问题:
1.连接池中的socket个数是有限的,同时要用socket连接的请求过多的情况下就会造成资源竞争与大量的等待。
2.另外就是会遇到合理限制等待超时时间的问题,如果不设置超时会导致服务端处理变慢,进而导致客户端请求都在无限等待,而客户端资源是有限的,因此很容易出现服务端瓶颈引起客户端挂掉的现象。
那么,超时时间设置多少?这取决于客户端的请求量,以及服务端的处理速度,要在性能和出错率之间保持平衡。
对于服务端能同时接受多个连接发送的请求的问题:
直接的解决方案:
在accept获取socket后,将此socket放入一个线程中处理,即一个连接一个线程模式,这样服务器就可以接受多个连接发送请求了。
上述解决方式带来的影响:
1.无论socket连接上是否有真实的请求,都要耗费一个线程,为避免创建过多线程导致服务器资源耗尽,需限制线程创建的数量,这就造成了采用BIO情况下服务端所支撑的连接数是有限的问题。
TCP/IP+NIO:
对于客户端同时发送多个请求到服务端的问题:
实现方式:
与TCP/IP+BIO方式没有什么不同,但NIO可以做到不阻塞,如果服务器返回响应带上请求标识,那么客户端则可采用连接复用的方式,这可以降低连接池带来的资源争抢问题。
对于连接不复用的情况则采用socket.setSoTimeout方式来控制同步请求超时,连接复用设置超时时间可基于blockingqueue,对象的wait/notify机制,futrue机制来实现。
对于服务端能同时接受多个连接发送的请求的问题:
解决方式:
采用一个线程来监视连接事件,另一个或多个线程来监听网络读写流的事件,只有当实际网络流读写事件发生后,再放入线程池中处理。
带来的影响:
比TCP/IP+BIO方式能接受更多的连接,而这些连接只有在真实请求发生时才会创建线程处理,节省资源。
但当连接数不多,且连接数请求发送非常频繁时,不会带来太大的优势,不过实际场景中通常是服务端要支持接受非常多的连接,但是这些连接同时发送的请求并不多。
UDP/IP+BIO:
实现方式:
采用receive和send方法进行读写操作。
由于UDP方式不建立通讯连接,故没有连接竞争的问题,只是读写流的动作是同步的。
对于服务端能同时接受多个发送的请求,通过采用每收到一个packet 就放入一个线程中进行处理来实现。
UDP/IP+NIO:
对于UDP/IP通讯方式,NIO带来的好处只有在有流要读写时才做相应的IO操作,不用像BIO方式直接阻塞当前线程。
参考:《分布式java应用》