论坛首页 Java企业应用论坛

关于高性能网络应用的研究总结

浏览 14260 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (3) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-12-19  
timerri 写道

windows平台下比较先进的模型是完成端口+重叠IO,完成端口可以看作增强版的select,它可以支持更大量的句柄,并且可以一次返回多个事件。重叠IO是另一个强大的工具,它允许用户异步的进行通讯操作,而且还能允许用户自己管理传输缓冲。使用这二者的组合,完全可以把所有端口的所有传输数据分成一个个等长的小块,让cpu进行基于定长数据块的处理。看起来像什么?是不是更像流水线?这种方式可以处理大量的连接而不会使性能降低很多。

linux平台下使用的是epoll,功能很像完成端口,也支持一次返回多个事件。只不过没有重叠io的支持,不知道这种模型赶不赶得上windows下的方案?


完成端口并不是增强版的 select ,epoll 反倒可以认为是增强版的 select 。
关于完成端口的描述,可以参考一下这个:http://www.iteye.com/post/336628

timerri 写道

(补充一点:jdk1.5 update9 之后,linux下的nio已经支持了epoll)

无论是完成端口还是epoll,我们的程序中都不再需要大量的线程了,但是仅仅使用一个线程完成所有请求的处理这种方式也是不可取的,因为很多情况下,系统都可能会对某些资源进行等待,这样就会降低综合的连接处理速度。比较好的方法是按需使用线程,在不大可能出现等待的逻辑中使用单独线程完成,在可能出现等待的逻辑中建立少量线程用多条流水线的处理方式去完成任务。

使用完成端口或者epoll的解决方案,java在大连接处理上的能力将会大大提高,只不过这时候java就不会再成为项目中的主导,看起来会更像一个嵌入式的解释器...


建立少量线程用多条流水线的处理方式去完成任务的想法已经有一些很经典的做法了,可以看看这个
half-sync/half-async,SEDA 和 生产者/消费者
0 请登录后投票
   发表时间:2007-12-19  
简单说起来,完成端口基于监视线程+消息队列,只不过是内核实现的。
而select就是完全的轮询。这牵扯到二者的具体实现。
不过简化考虑的话,把完成端口当作增强版的select去考虑也是没有什么问题的。在使用上,二者其实很相似....

关于half-sync/half-async,SEDA 和 生产者/消费者
我以前没有研究,大致看起来确实比较符合多流水线架构,多谢提供这样的资料,我研究下看看。
0 请登录后投票
   发表时间:2007-12-19  
timerri 写道
简单说起来,完成端口基于监视线程+消息队列,只不过是内核实现的。
而select就是完全的轮询。这牵扯到二者的具体实现。
不过简化考虑的话,把完成端口当作增强版的select去考虑也是没有什么问题的。在使用上,二者其实很相似....


两者在程序结构上有很大不同。

select 典型的程序结构http://iunknown.iteye.com/blog/41077
for( ; ; ) {  
  nready = select( maxfd + 1, &rset, NULL, NULL, NULL );  
  for( i = 0; i <= maxi; i++ ) {  
    sockfd = client[i];  
    if( FD_ISSET( sockfd, &rset ) ) {  
      n = read( sockfd, line, MAXLINE );  
      write( sockfd, line, n );  
  
      if( --nready <= 0 ) break;  
    }  
  }  
}  


IOCP 的典型结构http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_servrapp.asp
CServerDatabaseProtocol::CServerDatabaseProtocol(int iThreadCount) 
{
  bActive=TRUE;
  m_iThreadCount=iThreadCount;
  if (iThreadCount>MAXTHREADCOUNT)
  m_iThreadCount=MAXTHREADCOUNT;
  DWORD id;
  m_hPort=
     ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,m_iThreadCount);
  for (int iLoop=0;iLoop<m_iThreadCount;iLoop++)
   {
// Now create the worker threads.
    m_coThreads[iLoop]=::CreateThread(NULL,0,
                                   (LPTHREAD_START_ROUTINE)WorkerThreadFunction,
                                   (void *)this,CREATE_SUSPENDED,&id);
    ::SetThreadPriority(m_coThreads[iLoop],THREAD_PRIORITY_BELOW_NORMAL);
    ::ResumeThread(m_coThreads[iLoop]);
    m_coClients[iLoop]=NULL;
   };
};

int CServerDatabaseProtocol::Associate (HANDLE hComm, int iIndex)
{
CreateIoCompletionPort (hComm,
                        m_hPort,
                        (DWORD)iIndex,
                        m_iThreadCount);

 return 1;
}

long WINAPI WorkerThreadFunction(void *vArg)
{
 CServerDatabaseProtocol *csdp=(CServerDatabaseProtocol *)vArg;
 DWORD nBytes;
 DWORD WorkIndex;
 OVERLAPPED ovl;
 LPOVERLAPPED pOvl=&ovl;
 CClientObject *cpCurrentContext;
 BOOL b;
 while (csdp->bActive)
 {
  b = GetQueuedCompletionStatus(csdp->m_hPort,
                                &nBytes,
                                &WorkIndex,
                                &pOvl,
                                INFINITE);
  if (!b || !pOvl)
  { // Something has gone wrong here...
   GetLastError();
   continue; 
  };
  cpCurrentContext=csdp->m_coClients[WorkIndex];
  if (cpCurrentContext->DispatchFn((STATE_ENUMERATOR)cpCurrentContext->m_se,&ovl)
      == CMD_CLIENT_TERMINATED)
    csdp->DeAssociate(WorkIndex); 
};
 return 0;
};
0 请登录后投票
   发表时间:2007-12-20  
while(1) {  
  nready = select( maxfd + 1, &rset, NULL, NULL, NULL );  
  for( i = 0; i <= maxi; i++ ) {  
    sockfd = client[i];  
    if( FD_ISSET( sockfd, &rset ) ) {  
    //有事件了,做爱做的事
    }  
  }  
}  


 while (1)
 {
  b = GetQueuedCompletionStatus(csdp->m_hPort,
                                &nBytes,
                                &WorkIndex,
                                &pOvl,
                                INFINITE);
  if (b && pOvl)
  {  
    //有事件了,做爱做的事

  };

  };


这两个结构区别很大么?他们只是实现细节不同,后续操作大同小异......

这个问题不用再深究了,我们的分歧在于关注点不同。倒是IOCP用法的多样性,确实是个值得研究一下的方向。
0 请登录后投票
   发表时间:2007-12-21  
timerri 写道
xgyxgy 写道
timerri 写道
一般对java底层不了解的人都会反对jni,不过大可不必敌视它。因为java中对于底层的操作全部是通过jni实现的,包括那些耳熟能详的ServerSocket,FileInputStream等等...

对于超大访问量的系统,用纯java来做应该是糟糕的设计...除非硬件成本能大大低于软件成本.

J2EE的优势在于快速开发,而不在于性能优化。


超大访问量的系统不能用纯JAVA来做这种观点是非常错误的。怎样才算超大访问量?千万级别的算不算?我手头上就有N个N千万级别的系统,有些还是单机上千万级别的,纯JAVA打造。事实上,JDK1.4和JDK5.0与及现在的JDK6.0,性能上的提升是非常惊人的。现在在server端,没什么是纯JAVA做不了的。不止千万,亿级别的系统,同样可以用JAVA来做,而且性能不会比C/C++的要低。


对于超大访问量的系统,用纯java来做应该是糟糕的设计...除非硬件成本能大大低于软件成本.

请仔细看我这句话,我并没有说大型系统不能用java实现。
只不过,在同样的硬件配置下,使用纯java开发的系统将比经过c或c++性能低。要弥补这样的差距,就只能提高硬件配置达到。而在超大型系统中,提高硬件配置的代价是惊人的,一般情况下远远大于通过软件优化的方式的成本。所以,局限于纯java来解决是十分不明智的。

不要盲目相信java的性能,jdk中的实现大部分只是最通用的,而不是最优化的。某些时候,我们必须用自己的本地代码去替换掉jdk中的本地代码的实现以取得更优化的性能。


我明白你的意思,不过我还是觉得你的看法是错误的。对于超大访问量的系统,用纯JAVA来做,硬件成本会比用C/C++做的要高很多?这个是大错特错的!对于一个设计和实现得较好,超大访问量的系统,其最后的瓶颈,会在你的I/O层面,而不会在你的逻辑层。诚然,如果单纯密集型计算,单耗CPU的那种,JAVA会比C/C++的性能会低10% --20%,但是你有几个节点是密集型计算的?在当今的互联网和企业应用,密集型计算的节点,占不到你整个系统的5%。此时,再怎样讨论提升这个10%,已经毫无意义了。对于网络应用来看,单机的情况下,用纯JAVA来做,如果精益求精,其整体性能和C/C++实现的是不相上下的。大型系统最重要是看怎样负载均衡,怎样解决I/O,怎样做cluster。而JAVA在实现这些方面来说,有其天生的优势。在我所看过的团队,有很多花了几个月时间才用C/C++完成一个网络应用(当然都是非常高负载的),但还是较容易coreDump,维护方面较麻烦。而我们的团队可以花不到一个月的时间就完成这个,而且非常稳定,基本上没有出现问题。这两个实现的单机负载能力也不相上下,纯JAVA实现的并不差。我不认为两个团队的水平有很大差别,只是我认为用纯JAVA,会占了很多优势,在开发效率和稳定性上都不错。

windows下的应用我没有经验,也没有发言权了。以上所说的全是在*NIX的。
0 请登录后投票
   发表时间:2007-12-21  
[quot]对于一个设计和实现得较好,超大访问量的系统,其最后的瓶颈,会在你的I/O层面,而不会在你的逻辑层。[/quot]

你这句话说得很好么,可是你怎么又拿密集型计算去比较了?既然你知道高性能系统比较的是io性能,那你可以比较一下java和本地代码的io性能差别到底有多大.....(你不妨比较一下iis和tomcat在区区1000并发下的处理速度,我这里的结果是4倍)。

[quot]用纯JAVA来做,如果精益求精,其整体性能和C/C++实现的是不相上下的。[/quot]
还是用iis的性能说事吧,希望你能找到一个纯java的实现,性能接近iis....
linux下嘛,性能接近lighttp也好啊。




0 请登录后投票
   发表时间:2007-12-30  
赞同楼主的意见。
目前JDK 6中已经有了部分epoll支持,但是不是那种真正的ET模式的支持。
本人在JSRB项目中(jsrb.sourceforge.net)实现了一个基于JNI+EPOLL的支持,如有兴趣可以深入探讨。
0 请登录后投票
   发表时间:2007-12-30  
facebook等大网站用php,只是做前端页面,中间件都是自己用c++开发的,facebook不是发布了一个thrift嘛?和 ICE有点像
0 请登录后投票
   发表时间:2008-01-01  
楼主对IOCP与EPOLL的理解有错误,不应该拿SELECT与它们相比较,根本就不是同个档次的。我一直在期待JAVA真正能实现EPOLL的那一天。这样我们网游服务器就可以尝试转到JAVA上了。还有JDK 6中为什么不是真的ET?有没应用JAVA的EPOLL的例子?
0 请登录后投票
   发表时间:2008-01-02  
timerri 写道

J2EE的优势在于快速开发,而不在于性能优化。




这个观点很新颖嘛.呵呵.
有创意哟.
难道是说做企业应用,java比.net开发快,性能不如.net,
       做网站 ,java比php开发快,性能不如php?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics