上一篇讲到g-chatV1.0的原理,事隔一年,已经有很多感悟和变化。经常在一些bbs看到有人说. net或者Java做的Socket服务器性能如何不好,一些开源组件如何不给力,我只能在这里偷笑,哥们,你们太幼稚了!

现在,新的思路基本成型了。所以才敢写出来。g-chat 1.0 在商业领域上测试过,结果并不乐观,当然和我经验不足有很大关系。不过,吃一堑,长一智。我先来分析一下之前遇到的问题和解决方案。

Q1:

在最初进入测试阶段,用户抱怨最多的问题是连接速度慢(客户端是flash,socket连接成功后flash需要先查询安全验证然后登录),而互联网用户 往往没有那个耐心等待三个过程都走完就刷新了页面。结果导致server thread需要过度频繁得处理连接请求。在我们程序的最初版本中,server thread使用了NIO的选择器。选择器会把所有新进的连接选择出来然后用for循环处理。在每次处理过程中,再次查询了isAcceptable,很 明显每个连接被查询了2次。另外,鉴于系统中ServerThread是单例的(具体为什么参见下文),也就是说不存在多线程之间争抢资源的问题,所以 clientAcceptSelector.select()过程纯粹是在浪费时间!当然,NIO在处理select过程比较耗时间。

Q2:

在进阶的测试阶段,我们发现很多时候客户端接收数据有严重的延迟,甚至某些时候会掉线。大家都知道互联网并不是我们想象的那么稳定,用户的链接在某些时候会 遇到切换路由的情况。例如:用户到服务器需要经过A、B、D三个路由器,恰好当用户连接以后B路由器由于某种原因故障,这时候路由系统采取了备用路由,用 户与服务器连接改用A、C、E、D四个路由器来完成,整个过程需要一点点时间。但这一切都是由比TCP协议层更低的层次来完成的。当一个数据包从D路由器 发送出去之后,恰好B路由器失效,D路由器会收到一个数据包未送达的消息(路由故障的发现),D决定采取备用路由向E路由器发送数据包,E路由器选择了C 路由器作为下一跳,C路由器把数据送往A路由器,最终数据由A路由器送至用户。在这整个一系列动作中和我们服务器端基本没有什么太大关系,但是却会导致数 据送达的数据包回来的异常缓慢!

这也就是为什么用户接受数据延迟的原因。在我镇,本身互联网发展就比较缓慢,再加上省与省之间,联通和电信之间现在都加装了GFW网桥,导致网络环境更加恶化。不信,你要是电信网络就去访问网通的站点,你要是网通的网络就去访问电信的站点^_^

Solutions:

基于上述的两个问题,现在新版核心设计和代码已经基本完成,基本的思路没有变化,即:不用的职责交给不同的线程,一个输出线程可能负责N和socket的 OutputStream,一个输入线程也负责N个socket的InputStream,但ServerThread只有一个。

也许有人会问,为什么非要ServerThread单例,其实多例也没什么不好,例如采用NIO方式,由N个线程接待新进入的链接,但刚才也谈到 了,NIO模式中选择器会占有相当的CPU,为了性能考虑再加上我们不是一个处理短时间连接的服务器(例如Weblogic、Apache之类),没有必 要做。退一步来说,如果调试过Tomcat的话,您将会发现Tomcat在默认配置下也是用一个线程处理ServerSocket的accept工作。

下一个版本的改进,主要有:

1.    ProcessThread与InputThread/OutputThread的解耦,同时ProcessThread将允许多实例。

2.    ProcessThread将不再与OutputThread打交道,改为与OutputDespatcher打交道,OutputDespatcher允许异步发送数据,用于保证ProcessThread的高效。

3.    协议层将单独封装,允许用户自定义协议。

4.    系统自身的数据格式不变,但允许做扩展。

就这些,g-chat 1.1会尽快出炉的。