由浅入深,切身体会高并发socket java程序设计

来源:互联网 发布:热仿真软件icepak 编辑:程序博客网 时间:2024/05/20 06:24

首先,我并不是什么大神,我只是一个普普通通的码农而已,这里也不会涉及到代码层面的东西。

我所体会的只是我写程序的时候感受到的东西,并不代表真理。

这是一个针对入门菜鸟的文章,老鸟们欢迎挑刺。

起因是因为要做一个车载的GPS设备的平台,机器上传时通过socket来传输 ,我那个时候只是一个未毕业的还不是学计算机的孩子,做这个东西实在是难以下手的。

我想到用是java,为什么?那时候的我,认为因为只有java才能适应linux,windows,unix。

于是我用着半生不熟的语句完成了这个程序,当时是照着socket的聊天室来做的。

想必大家都知道的,用的是BIO。也就是堵塞模型,利用多线程来实现多个监听。

不得不说,java确实是非常优秀的语言,这个程序只有区区几十k,而且功能非常简陋,仅仅接受解析转存到数据库,当时用的mysql。

对于一个入门的人来,BIO是一个非常简单易懂的模型,完成也相对容易,当时机器的数量也不多。

但是随着业务的发展,很快我就发现了问题,原因在于我写php程序的时候,发现php的写入速度居然比java还快。那时候已经是一个多月后了,我又翻出了以前的代码,发现数据库的连接是一个瓶颈,并没有使用数据库连接池这样的东西。于是百度了一下,找了一个简单的连接池放了进去。速度立马提升。还修正了一个由于意外断掉socket连接的问题。做了一个简单的超时处理。

随后,又有新的需求,就是我上篇文章里说到过的算法,这里需要查询数据库,这又遇到了一个问题,查询数据库相对来说是一个费时的事情,而且还有大量的cpu集中的运算,消耗不少时间。

而在堵塞模型里,费时的操作会引发各种问题。所以我需要一个异步的操作,这时候我想到的就是将socket连接存到hashmap里面,实现一个单例模型,处理算法另开一个线程。完成后往相应的socket管道写入数据。

到这里就有一点select and poll的味道,当然这是完全不同的,但是这随之引发另外一个问题,线程数的开销。

在这个时候,我依旧是个菜鸟(当然现在还是),用之前的数据库连接池的思想,理所当然,我需要引入线程池。很正常的,我使用jdk里面线程池技术。

在查阅资料的过程中,我发现jdk7里面有一个AIO的异步I/O,号称将远远提升I/O性能。

于是我又有了使用AIO的想法,事实上AIO在网上的资料是比较贫乏的。我最后只是完成了一个粗糙的程序,会引发轻微的内存泄露,但是对于实验的狂热让我丧心病狂的将其投入了实际环境中。

到了这里,线程池,连接池,异步I/O都已经齐全了。但是实际上这个东西并不是成熟的。

为什么呢?它的代码实在是太混乱了,缺乏有效统一的调度。我又花了好长的一段时间去整理抽象出接口,分类设计。

业务增加实在太快,很快我们又有新的通讯的协议加入,这回不单纯是接受->反馈信息这样的模式,还需要额外的能够直接操作的对象。也就是越来越接近及时聊天这样的软件。

协议的复杂性和网络的不稳定超过pc上的聊天软件。平台很快要搬上云平台。

而云平台是jdk6,AIO并不能使用。寻找替代品的我最后选用的是mina框架。看中的是它文档齐全,资源完整。

在这里我要谈一下,jdk6后面的NIO和 JDK7的AIO在linux系统上都是采用epoll实现,并不是像某些人说的采用的是select and poll,这点在dump heap可以看出来,所以理论上说,它们之间的性能差距并不会像windows上面那么明显,jdk7在windows上是IOCP实现。

于是我花了不少时间,将这个程序转写成了mina的,加入对外控制的接口,数据库连接池换成了BoneCP,而并发写入非常高的一个表,我直接使用mongodb代替。对外的resetAPI访问采用缓存层减少访问量。

这里面还出现了TCP/IP协议中常见的断包粘包问题,于是又不得不花精力去解决这个问题。

经过几周的运行,表现非常完美。整个jar文件大小达到了6M。但是健壮性和稳定性却不可同日而言。

目前看来,暂时不需要再更改代码了,等到哪天再看看吧。


一个高并发的java程序,必须具备几个要素。

一、数据库连接的控制,连接池和数据库的优化必不可少,大并发写入会引起写锁的问题,可以通过分库分表来减少压力,最根本的解决办法,就是直接换成大并发写入优化的DB,适用于一些单个价值不高的数据。

二、高cpu运算和数据库读取造成费时的问题,最好单独开一个线程,充分利用多核cpu性能。相应的线程池也是不可少的。

三、新技术不一定就是最好的,使用成熟的技术,丰富的技术文档和广泛的使用实例是理解应用这些技术不可忽视的决定性要素。事实上BIO的稳定性使我记忆忧新。在小并发时候消耗是很让人满意的。

四、程序的设计永远是最重要的,一定要经常思考优化的余地,能不能再改进。

五、重视细节,给不用的变量赋予null,一个网络程序,断包和粘包要做好,还真的得花不少心思,尤其是在一些根本没有考虑过这种情况的协议下做,真是一场思维风暴啊。


写给自己,永远要有自信。


原创粉丝点击