`

MINA及其在高性能通讯应用中的突出问题(NIO架构及应用之二)

 
阅读更多

前面写过一个博文高:高吞吐高并发Java NIO服务的架构,http://maoyidao.iteye.com/admin/blogs/1149015 。这个架构是和MINA一致的,或者可以说MINA是基于同样的思路构架的。想阅读MINA源代码的朋友可用参考这个架构来研究MINAsource code。但是考虑到在已经有比较可靠的开源实现的情况下,现在朋友们很少会自己去实现一个NIO模块。就想到把它做成一个系列,第一篇主要是讲解一种业内普遍采用的NIO架构,及其架构上的两个要点,即:1. 基于提高的性能的线程池设计;2. 基于网络通讯量的通讯完整性校验。这一篇来讲讲在基于MINA搭建高性能NIO服务时如何具体实施以上两点。有部分代码选自openfire(openfire是一个实现XMPP协议的开源项目,其底层通讯模块为MINA)

MINA的使用相信朋友们已经很熟悉了。把MINA应用于高性能分布式应用的时候,表现出来比较突出的问题还是协议解析的问题和容量规划的问题。

1,协议解析的正确性问题

MINA已经给我们提供了非常方便的接口来实现NIO。coding的重点可能会是在协议解析上,即实现ProtocolCodecFactory接口中规定的encoder、decoder。当收到一个NIO包并从中解析出协议消息体并不困难,且容易测试。但高负荷的通信使得协议数据不能在TCP的一个packet中完全到达,即所谓断包。我经历过某团队到性能测试时才发现这一问题,花了很多时间在海量的tcpdump包中寻找问题,花费了很多时间,而且非常痛苦。如能从一开始了解TCP通讯和MINA架构,则轻松很多。

TCP socket发送大数据时会将其拆分成一个个小数据包发出,由于接收窗口和拥塞窗口的限制,这些数据包可能不能一次发送出去。这时后继的数据包等待在发送缓冲区,等待窗口的扩大。比如在Linux系统,通过修改/proc/sys/net/core/rmem_max改变最大的TCP数据接收缓冲,通过修改/proc/sys/net/core/wmem_max改变最大的TCP数据发送缓冲。另外,即使是比较小的数据包,为了达到最好的性能,我们总是尽可能多的把小数据包拼接起来填充每个报文,以减少发送数据包的个数。比如MINA默认的参数会把John Nagle算法设为false。如下代码,socketSessionConfig.isTcpNoDelay()返回false。

SocketAcceptorConfig socketAcceptorConfig = socketAcceptor.getDefaultConfig();
SocketSessionConfig socketSessionConfig = socketAcceptorConfig.getSessionConfig();
socketSessionConfig.setTcpNoDelay(JiveGlobals.getBooleanProperty("xmpp.socket.tcp-nodelay", scocketSessionConfig.isTcpNoDelay()));
 

这些TCP传输的特性导致NIO收到的packet对于应用协议来说可能是不完整的。因此需要在协议解码类中实现拼接消息的逻辑。

解决办法也很简单,即将这次没有解析完的byte再放到下次数据包头重新解析。openfire的协议解析实现类XMLLightweightParser中startLastMsg记录的就是上次完整消息的解析后ByteBuffer的位置。而StringBuilder类型的buffer则是用来存储上一次收到的数据包中没有解析完的数据。XMPP是XML流协议,解析起来比较复杂,朋友们不看也罢。这些都是代码实现的细节,等用到了再做测试不迟。但抛去其解析协议的复杂逻辑,这不起眼的buffer和startLastMsg则是具有通用性的逻辑。有些协议比如RTSP协议会规定在消息头中传递数据包的长度,其逻辑实现就简洁很多,但也需要实现类似的buffer和startLastMsg的逻辑。

2,容量规划问题。

在本系列第一篇中已经阐述过NIO的瓶颈在于后端架构的实现。当时给出了一个线程计算公式来估计所需的线程。但我在实际情况中发现工程师们往往不愿意做这样的测试,而喜欢简单的将线程池设为CPU核数+1。比如openfire在MINA中设置处理线程池:

// Customize Executor that will be used by processors to process incoming stanzas
ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance("CommServer");
int eventThreads = getCPUCoreNumber();
ThreadPoolExecutor eventExecutor = (ThreadPoolExecutor) threadModel.getExecutor();
eventExecutor.setCorePoolSize(eventThreads + 1);
eventExecutor.setMaximumPoolSize(eventThreads + 1);
eventExecutor.setKeepAliveTime(60, TimeUnit.SECONDS);
commSocketAcceptor.getDefaultConfig().setThreadModel(threadModel);
 

这里我还是建议朋友们在线程池大小上多花些时间,这对提高单台NIO服务效率是很有好处的。特别是在特定场景下更是如此,

1,每个操作都需要调用数据库。数据库操作是重IO,相对来讲CPU比较闲,这个时候就可以多设置些线程。这里还可以有一个优化,就是在db上增加一个写缓冲。对db采用batch write,还可以合并update操作,速度可以提高很多。

2,每个操作都要访问互锁的资源。这就是说实际上线程之间要争夺一个mutex锁,这样的逻辑最好是可以避免的。或者缩小锁的影响范围。如果实在避免不了,则要考虑是否有必要减少线程数量,因为既然都要抢一个mutex,实际并行的也是一个线程。

当然即使线程池大小适度,也不能完全解决容量问题。比如我这里有一个实际模型



这里需要调用远程资源,可以认为是memcached,也可以是其他socket资源。最后还要通过socket发送到其他模块。这时则要求即使这些资源访问全部挂掉,也不能让线程等待很久,否则前端的queue就会堆积溢出。因此resource的调用必须有很快的超时返回,而socket则必须有心跳和很快的超时返回。在这个项目中,经过容量规划我们认为后端socket的超时应该为3秒。这个时间相对是比较短的,但是为了保证整个系统的健康,是必须的。

 

在发送端设置发送缓冲的意义我想引用Timyang的一篇博客中所说的,

 

1. Socket占满后写socket会block, 或者设置了TCP_NODELAY则不管SOCKET buffer是否占满都会block
2. 如果应用写入操作没有队列概念则应用程序会出现异常,所有操作会阻塞。
3. 强壮的应用会对发送数据做应用层的buffer,像Connection Manager/Openfire之间是使用发送 Thread Pool,在对方不可到达的时段内,内存占用会急剧上升。
4. 如果网络层恢复正常,首先是socket buffer中的数据会被发送,然后应用层堆积的数据也随后发送。
5. 如果网络层长时间不可用,有2种方法可以判断,通过达到SO_SNDTIMEO Socket返回错误检测,应用层如果需要更早知道错误,可以调低SO_SNDTIMEO。另外一种检测方法是应用检测发送队列达到上限临界值来做进一步 处理。避免服务器内存溢出造成崩溃。实际环境中需要结合这2种方式一起考虑。

 

对于第五点,我提供的经验是,对LinkedBlockingQueue size做一个定时健康监控。如果前端queue内容发生堆积,说明系统中有锁定的情况;如果后端queue堆积,说明网络状况不好。

 

总结一下,设计和开发广泛适用于分布式的通讯模块,需处理

1,收不到,

2,收到处理不了,

3,和发不出去

这三种情况下的健壮性。

 

  • 大小: 25.7 KB
0
1
分享到:
评论
1 楼 zhaoqun007 2013-05-15  
MINA里的CumulativeProtocolDecoder应该就是为解决第一个问题存在的。。。

相关推荐

    高性能网络架构Mina框架 下载

    高性能网络架构Mina视频免费下载_百度云盘资源

    mina高性能Java网络框架.rar

    Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议...

    MINA通讯框架的两个简单实例和文档

    Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议...

    mina2.0初学教程

    Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议...

    mina实例、资源包、学习文档

    Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议...

    mina2框架+项目实例教程

    一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议(如TCP/IP,UDP/IP协议等)下快速高效开发。 Apache Mina也称为:  NIO...

    Netty权威指南(第2版)

    长期从事高性能通信软件的架构设计和开发工作,有多年在NIO领域的设计、开发和运维经验,精通NIO编程和Netty、Mina等主流NIO框架。目前负责华为软件公司下一代SOA中间件和PaaS平台的架构设计工作。

    Netty权威指南 第2版 带书签目录

    长期从事高性能通信软件的架构设计和开发工作,有多年在NIO领域的设计、开发和运维经验,精通NIO编程和Netty、Mina等主流NIO框架。目前负责华为软件公司下一代SOA中间件和PaaS平台的架构设计工作。

    架构师-深入浅出Netty 书签版

    李林锋,2007 年毕业于东北大学,2008 年进入华为公司从事高性能通信 软件的设计和开发工作,有7 年NIO 设计和开发经验,精通Netty、Mina 等 NIO 框架和平台中间件,现任华为软件平台开放实验室架构师,《Netty 权威...

    轻量级网络通信框架nSocket.zip

    nSocket与mina、netty、xSocket这类高性能的设计不同之处在于,nSocket将直接使用java7中的异步通道构建异步操作,并在后期将弱化C/S模式,逐步过渡到P2P模式。 编写目的: 简化NIO开发过程,将业务与实现...

    JAVA上百实例源码以及开源项目源代码

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    JAVA上百实例源码以及开源项目

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    java开源包1

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包11

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包2

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包3

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包6

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包5

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包10

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

Global site tag (gtag.js) - Google Analytics