Java服务器开发基础知识(1)

因为实际需要所致,我们不得不考虑在现有的开源/商用的应用服务器之外开发一个,有性能要求、有并发要求的服务端应用,从技术要求的角度来分析一下,用Java实现这件事情我们可能关注的知识层面。

在整体上,可能需要我们从下面几个层面出发来考虑:

1.在硬件和操作系统层面:为什么需要关注这两个方面的知识,因为Java并没有自己的线程,使用的也是OS中的IO,所以我们不得不去了解系统在不同的硬件、OS上面的适用情况、运行情况。比方说,多核技术对于操作系统的影响,这种影响直接会传递到JVM层面;对于数据传输操作的DMA(Direct Memory Access, 存储器直接访问)方式的了解,便于我们更好的了解CPU和IO的关系。同样的,对于OS层面的select/poll/epoll的认识,不仅帮助我们去理解Java的IONIO(New IO)AIO(Asynchronous IO)的发展之路,同时让我们对IO/NIO/AIO在Java层面的体现有更清晰的思路。

Select

Select在1983年首次出现,是在4.2BSD中。通过select()的系统调用来监视包含多个文件描述符的数组;当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。

Select方式现在为几乎所有的平台支持,具备良好的跨平台支持。同时,select()方式需要维护一个存储文件描述符的数据结构,随着其的增加,对其的内存操作的开销也会线性增加;每次网络响应,进程在调用select()的时候都会对所有的socket做一次线性扫描,包括那些处于非活跃状态的连接,这也是一个巨大的开销;在系统方面,每个进程能够监视的文件描述符的数量是有最大限制的,通过宏FD_SETSIZE来指定的,在Linux中这个值默认是1024,修改这个宏值并生效,有时候可能需要重新编译OS的内核:).

Poll

Poll是在1986先首次出现,是在System V Release 3中。其和select相比在本质上变化不大,只是poll没有了select方式的最大文件描述符数量的限制。

注:select()和poll()采用的模型都是:水平触发(Level Triggered)。

Epoll

Epoll是在Linux 2.6版本中开始有内核直接支持的实现方式。这种方式的三个特点:

a. 同时支持水平触发LT和边缘触发ET。

LT(Level Triggered)是缺省的工作方式,同时支持block和no-block socket。在这种模式中,内核将就绪的文件描述符告诉进程后,进程可以对这个就绪的fd进行IO操作。如果进程不作任何操作,那么内核会在下次调用中继续将这些文件描述符报告给进程,所以,这种模式在编程中出错误可能性要小一点。传统的select/poll都是这种模型的代表.

ET (edge-triggered)是高速工作方式,只支持no-block socket。在这种模式中,当文件描述符从未就绪状态变为就绪状态时,内核通过epoll报告给进程。然后内核会假设进程知道文件描述符已经就绪,并且不会再为这个(种)文件描述符发送更多的就绪通知,直到进程做了某些操作导致这个(种)文件描述符不再为就绪状态了(比如,进程在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致 了一个EWOULDBLOCK 错误)。同时请注意,如果一直不对这个(种)fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)。不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认。

b. epoll模式在操作中获得就绪的文件描述符时,返回的不是实际的文件描述符,而是一个代表就绪文件描述符的值,然后在文件描述符数组中查询对应的的文件描述符。这样避免系统调用时候在内存中数据结构复制的开销。

c. epoll采用事件通知方式。即每一个文件描述符都对应的注册了一个类似callback,当就绪激活时,通过callback和进程进行匹配操作。避免了select在每次调用的时候都遍历整个socket的扫描开销。

因此epoll具备优势:支持一个进程打开大数目的socket描述符(FD);IO效率不随FD数目增加而线性下降;用mmap加速内核与用户空间的消息传递;和内核微调一起协调工作。

注:似乎Apache主要采用的是select模式;而lighttpd和nginx主要采用epoll模式—带考证确认。