[转][转]Web server调研分析

标签: web server 分析 | 发表时间:2012-07-20 15:00 | 作者:heiyeshuwu
出处:http://blog.csdn.net/heiyeshuwu

作者:liqiang (http://blog.xiuwz.com/)

来源:http://stblog.baidu-tech.com/?p=755 


摘要

简单可依赖的架构首先需要有一个简单可依赖的前端WebServer集群。本文通过深入调研当前主流的异步web服务器Lighttpd和Nginx,从业界使用情况、架构原理、扩展开发、功能对比、性能对比等多个方面进行分析。

调研分析

业界相关

从业界使用情况来看,最新Web Server使用情况的数据如下:Nginx的使用率是6.6%,Lighttpd的使用率是0.51%。

从文档来看,nginx中文相关文档越来越多。来自最新的百度搜索数据显示,nginx的网页数量是lighttpd的10倍。目前国内对于Nignx内核深入研究的人越来越多,有淘宝、sina、腾讯等许多大公司的技术人员参与研究,并进行相关的技术交流。对于Lighttpd的研究,目前主要是公司内部和一些学生。

从业界的点评来看,国内外基本上结论如下:

  • 两者都是异步WebServer,都采用了状态机。本质上是相同的。
  • Nginx稳定度高于Lighttpd。Lighttpd一直存在一定的内存泄漏。
  • 性能上两者都非常优秀,Nginx有一定优势。
  • Nginx在综合性能上更加优秀,更有可能成为未来的apache。

从社区活跃度来看,Nginx每月2到3个三位版本发布。Lighttpd3位版本更新较慢,目前1.5的版本基本上没有更新过。同时Nginx有丰富的第三方库类。

架构原理

代码层次

Nginx的代码量10W行,Lighttpd是5W左右。相对来说,Nginx的代码层次结构更加分明,具体代码结构如下:

Nginx和lighttpd都是采用C语言编写的,对于基础数据结构都有一定的处理。Nginx中关于数据结构的代码主要放在core文件夹里面。

Nginx主要的基础代码有:array、string、buf、file、hash、md5、内存池、队列、红黑树、time、共享锁等。这些数据结构对于扩展开发都非常有帮助。Lighttpd有一定的基础数据封装,但相对没有那么明显的设计。目前观察到的基础代码有:bitset、buffer等。

内存管理是所有C程序中非常值得关注的一点。Lighttpd在内存管理上没有做特殊的考虑,基本上都是采用系统内存管理函数,比如malloc/calloc等。在扩展开发中的内存也需要扩展模块自己考虑。Nginx在内存管理上提供了两种方式:1、原生malloc等的二次封装。2、内存池。在nginx内部大量的使用内存池。在扩展开发中也能直接调用内存池进行内存管理。此外,nginx还内置了对tcmalloc的支持。把内存优化做到极致。

架构层次

从总体架构来看,Nginx/Lighttpd都属于master+worker的工作模型。

但nginx相比lighttpd,在细节上处理的更加优化,具体可以从几个方面来谈

1、  配置文件热加载。Nginx从设计开始就支持配置文件热加载,甚至程序的热加载。Lighttpd本身不支持,目前业界有采用扩展方式,比如说lua,可以实现部分配置热加载。

2、  强大的master进程,实现worker进程和master进程的各司其职。Lighttpd的master进程在fork完worker进程后,就单独的等待worker进程的结束(或者在worker进程结束后再创建新的worker子进程)。Nginx的master进程负责对worker子进程的管理,并通过socket pair通信方式实现热配置文件升级、优雅重启、热应用程序升级等功能。

3、  线程锁。Lighttpd在进程之外还启动了线程进行相关方面的工作,这会对lighttpd的性能带来一定影响。Nginx内部虽然提供了对线程模式的支持,但在主推的进程模式中不会出现额外的线程。

4、  多核机器优化,cpu affinity。Nginx设计中考虑了对多核机器的优化方案,能降低进程在不同cpu之间的切换次数,从而提升性能。

超时处理

Lighttpd的超时处理原理非常简单:通过alarm信号量来实现的。每1s出发一个alarm信号,从而切换到超时处理函数。该函数也非常简单:循环简单当前所有连接的读和写,如果事件超时了,则直接close掉。这会有几个问题:

1、  连接非常多的时候。超时处理还是会非常耗事件的。随着连接数而递增。

2、  在不可重入的函数中出发alarm的时候,有可能出现意想不到的问题。

3、  需要轮询。

Nginx在超时处理上实现的巧妙的多:采用数据结构和巧妙的策略来实现。

1、  使用红黑树来存放定时器的相关数据。红黑树的重要特点是:插入删除都会在O(logN)完成,同时具有优秀的查找性能。所以很多C++的库(map)等都用到了它。

2、  通过红黑树计算出当前节点的超时时间差,使用这个时间差作为调用多路复用I/O操作的参数,当函数返回,只可能是I/O事件被触发,或者超时。

3、  处理完I/O事件之后,得到处理前后的时间差,根据这个时间差依次查看红黑树中哪些定时器可以被处理。

这也是在高压力下,Nginx更优于Lighttpd的一个重要原因。

Accept处理

Lighttpd中对于Accept的处理有几个特点:1、不加锁。2、连接处理达到0.9的时候会禁止接收新的连接。3、1次性accpet 100个。这样有一个好处, 假如服务器监听fd是每次触发只接收一个新的连接, 那么效率是比较低的,不如每次被触发的时候”尽力”的去接收, 一直到接收了100个新的连接或者没有可接收的连接之后才返回。4、提供了fdwaitqueue。在fd不够用的时候备用。

Nginx:1、进程加锁,避免惊群,同时控制了获取accpet的概率,一定程度上控制各个子进程之间的请求数目。2、7/8阀值。连接数目达到最大连接数的7/8的时候,该进程将获取不到对应的accept锁。从而进入安全控制阶段。3、提供了multi_accept指令,在开启的情况下也和lighttpd一样尽可能的多accept。

状态机

Lighttpd和nginx都是状态机驱动模型,两者之间主要体现在细节的差异性上。

  1. Nginx对整个状态进行了分类,分成预处理、状态机、filter流程三个明显的阶段。
  2. Lighttpd的状态机相对简单固定。Nginx则相对灵活。
  3. Nginx的大部分处理状态都是可以扩展的并且可中断的。Lighttpd在部分状态中也可以扩展的。
  4. 耦合程度。nginx状态处理函数之间的耦合紧密,状态切换时的下一步处理由状态处理函数来决。而lighttpd将状态切换的动作放在状态机里,各个状态处理函数不关心下一步需要做什么,状态之间的耦合小。但同时会对扩展性带来一些问题,比如说subrequest的实现。

后端处理

Nginx针对不同的后端处理方式进行了封装,提供upstream来支持不同的协议(HTTP/FASTCGI/Memcache),提供扩展来支持不同的负载均衡算法。同样的Lighttpd在新版中也对不同的后端协议进行了封装,并提供了不同可供选择的负载均衡算法。

从原理层次来看,两者在后端处理上的思路是基本一致的。更多的对比需要从功能和性能上来对比。

扩展开发

Nginx和Lighttpd都支持扩展,Lighttpd是通过预留系统钩子来实现的,相对来说不够灵活,如果有一些特殊的修改则不得不修改源码。Nginx则通过预留系统钩子和控制反转结合,从而能够实现更多的功能。所以,nginx扩展的灵活性高于Lighttpd。

总结如下:

1、  nginx不支持动态扩展模块。

2、  扩展开发上,nginx更加灵活。提供了多种扩展切入方式。

3、  Nginx提供了丰富的类库,方便扩展开发。

功能对比

反向代理

对比分析如下:

1、  性能。

  • 同等压力下,nginx的cpu消耗要低于lighttpd。但整体差别不大。
  • 极限压力下,nginx处理能力高于lighttpd。原因未知。

2、  功能。

功能点 Lighttpd Nginx 备注
灵活的反向代理方式 支持 支持 都非常好
正则 支持 支持  
自定义header头 部分支持 支持 目前gm有库支持IP的传递
负载均衡 支持 支持  
超时处理 支持 支持连接、读写等  
故障处理 支持 支持  
Cache 不支持 支持  
文件上传 未知 支持,可配置,有优化 Transmit不支持
输出过滤 不支持 支持 头部过滤和内容过滤。

结论:

1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在这方面明显优于lighttpd,更加完整的细节考虑和优化。主要体现在超时处理、文件上传、输入输出的过滤、cache等等。

2、性能上,Nginx稍优于lighttpd。

Fastcgi支持

Nginx和lighttpd在Fastcgi方面功能上基本上相同,主要调研是从性能上对比。

10k的php请求

前端压力 Lighttpd Nginx 备注
1000QPS 96% 处理1000QPS 98%  
2000QPS 91% 96%  
4000QPS 81% 92%  
8000QPS 65% 85%  

20k的PHP请求

前端压力 Lighttpd Nginx 备注
1000QPS 95% 处理1000QPS 98%  
2000QPS 90% 95%  
4000QPS 80% 90%  
8000QPS 63%实际处理5588 QPS 86%。实际处理5220QPS  

从性能数据来看,2000QPS以内,两者性能差别不大,但高压力下,两者性能差别非常大。甚至有可能达到20%cpu差别。

页面Cache和运维

Lighttpd目前暂无页面Cache的支持。Nginx从设计之初就考虑了更改Cache。甚至有单独的Cache管理进程。

从功能上来看,目前Nginx已经支持proxy cache和ssl filter,并且实现了对esi cache的支持。

从运维上来看,Nginx支持配置热加载,支持程序热加载。更适合完成24*365的全天候不间断服务。

总结

对比点汇总整理后如下

对比点 Nginx Lighttpd 备注
市场占有率 6.6% 0.5%  
文档     百度文档10:1Google文档 1:1

国内研究人员nginx>lighttpd

业界点评     更加看好Nginx
代码量 10W 5W Nginx的代码结构层次较好。
基础数据结构 array、string、buf、file、hash、md5、内存池、队列、红黑树、time、共享锁 bitset、buffer 丰富的库类对扩展开发有很大帮助
内存管理 原生malloc、内存池、支持tcmalloc 原生malloc  
配置文件热加载 支持 不支持  
进程模型 Master负责管理,worker负责处理请求,各司其职。 Master简单。Worker复杂  
进程额外线程 存在线程锁
多核机器优化 支持 不支持  
连接管理 静态数组+单链表 动态数组,key交互 Nginx更加稳定高效。
超时处理 红黑树+巧妙的策略 Alarm+for循环  
Accept处理 锁+7/8阀值,支持mult  accept 0.9策略,一次性aceept100个。  
状态机
  1. Nginx对整个状态进行了分类,分成预处理、状态机、filter流程三个明显的阶段。
  2. Lighttpd的状态机相对简单固定。Nginx则相对灵活。
  3. Nginx的每一个状态都是可以扩展的并且可中断的。Lighttpd在部分状态中也可以扩展的。
  4. 耦合程度。nginx状态处理函数之间的耦合紧密,状态切换时的下一步处理由状态处理函数来决定ligty将状态切换的动作放在状态机里,各个状态处理函数不关心下一步需要做什么,状态之间的耦合小。
后端处理 都支持多种协议,并且方便扩展,都支持负载均衡算法扩展。
扩展开发 1、  预定义钩子2、  控制反转

3、  丰富库类

预定义钩子  
反向代理 1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在这方面明显优于lighttpd,更加完整的细节考虑和优化。主要体现在超时处理、文件上传、输入输出的过滤、cache等等。2、性能上,Nginx稍优于lighttpd。
fastcgi 功能上两者差别不大,主要体现在性能上。在性能上,2000QPS以内,两者性能差别不大,但高压力下,两者性能差别非常大。
页面Cache 支持proxy_cache。支持esi页面cache 不支持,需要额外开发。  
运维相关 支持配置文件热加载支持应用程序热加载 支持有限的配置文件热加载  

通过上述对比分析,可以得出如下结论:

“lighttpd和nginx一样具有非常好的架构,但在数据结构、内存管理都多个细节方面处理nginx考虑更加完善。如果说lighttpd是异步web server的先驱,那么nginx则是对lighttpd做了整体的优化的。而这些优化是全面的,根本性质的。无法简单的通过升级lighttpd来实现。因为nginx从一开始设计就希望做成一个完美的异步web server。nginx从event、跨平台、基础数据结构都很多细节方面进行了考虑和优化。应该来说,nginx必定是未来的apache,未来的主流。”


作者:heiyeshuwu 发表于2012-7-20 15:00:19 原文链接
阅读:9 评论:0 查看评论

相关 [web server 分析] 推荐:

Web server调研分析

- flychen50 - 搜索研发部官方博客
简单可依赖的架构首先需要有一个简单可依赖的前端WebServer集群. 本文通过深入调研当前主流的异步web服务器Lighttpd和Nginx,从业界使用情况、架构原理、扩展开发、功能对比、性能对比等多个方面进行分析. 从业界使用情况来看,最新Web Server使用情况的数据如下:Nginx的使用率是6.6%,Lighttpd的使用率是0.51%.

Web server调研分析 - (转发)

- jiaosq - kernelchina
原文地址:http://stblog.baidu-tech.com/?p=755. 简单可依赖的架构首先需要有一个简单可依赖的前端WebServer集群. 本文通过深入调研当前主流的异步web服务器Lighttpd和Nginx,从业界使用情况、架构原理、扩展开发、功能对比、性能对比等多个方面进行分析.

[转][转]Web server调研分析

- - heiyeluren的blog(黑夜路人的开源世界)
作者:liqiang (http://blog.xiuwz.com/). 来源:http://stblog.baidu-tech.com/?p=755 . 简单可依赖的架构首先需要有一个简单可依赖的前端WebServer集群. 本文通过深入调研当前主流的异步web服务器Lighttpd和Nginx,从业界使用情况、架构原理、扩展开发、功能对比、性能对比等多个方面进行分析.

Apach警告Web Server发现拒绝服务漏洞

- coofucoo - Solidot
Apache发出警告,Apache HTTPD Web Server中发现拒绝服务漏洞,受影响的版本包括Apache 1.3分支和Apache 2分支的所有版本. Apache表示将在未来48小时内发布补丁. 名叫Apache Killer的攻击工具上周五发布在Full Disclosure邮件列表.

阅读 py-web-server: 让你了解 webserver 的实现方式

- Eric - python.cn(jobs, news)
这个系统的写作目的,是让对web编程有兴趣的程序员,了解webserver的实现方式. 根据这个目的,系统遵循以下几个设计原则:. 效率,安全性,特性不是最重要的. 目前稳定使用请用stable分支,不要使用default分支. 开始是从prefork模式开始,做到threading模式,然后是poll模式,把所有python下的服务器模式学了一遍,目前是用greenlet加上epoll来做出一个高性能socket抽象,然后在上面实现rfc2616,——而且是比较完整的实现.

构建实时Web的JAVA选择组合:socket.io client + socketio-netty server

- - BlogJava-首页技术区
     摘要: 很显然,实时Web,是一种技术趋势,将成为一种人们的默认技术选择,用以拉近和桌面应用的距离. socket.io是一种数据实时推送、事件驱动模型的框架,支持事件订阅,简单易用. 其价值目前看来,还未被完整的挖掘出来. socket.io即提供了node.js服务器端(地址)又提供了客户端(地址)的整体解决方案,而socketio-netty则是基于JAVA服务器端,支持最新socket.io client最新版规范.

通过ngxtop实时监控web server的访问情况

- - CSDN博客系统运维推荐文章
ngxtop现在虽然还有些问题,如本文最后,但开源才15天,值得期待. 安装后python2.7所在路径. 为保持python2.4不变,建立python2.7的软连接指向python2.7所在路径. 2、安装setuptools. 3.1、通过pip安装ngxtop,因为源在国外,可能下载、安装过程会很慢.

Web 日志安全分析技巧

- - IT瘾-dev
Web访问日志记录了Web服务器接收处理请求及运行时错误等各种原始信息. 通过对WEB日志进行的安全分析,不仅可以帮助我们定位攻击者,还可以帮助我们还原攻击路径,找到网站存在的安全漏洞并进行修复. 我们来看一条Apache的访问日志:. 通过这条Web访问日志,我们可以清楚的得知用户在什么IP、什么时间、用什么操作系统、什么浏览器的情况下访问了你网站的哪个页面,是否访问成功.

SQL Server--索引

- - CSDN博客推荐文章
         1,概念:  数据库索引是对数据表中一个或多个列的值进行排序的结构,就像一本书的目录一样,索引提供了在行中快速查询特定行的能力..             2.1优点:  1,大大加快搜索数据的速度,这是引入索引的主要原因..                             2,创建唯一性索引,保证数据库表中每一行数据的唯一性..

SQL Server 面试

- - SQL - 编程语言 - ITeye博客
在SQL语言中,一个SELECT…FROM…WHERE语句称为一个查询块,将一个查询块嵌套在另一个查询块的WHERE子句中的查询称为子查询. 子查询分为嵌套子查询和相关子查询两种. 嵌套子查询的求解方法是由里向外处理,即每个子查询在其上一级查询处理之前求解,子查询的结果作为其父查询的查询条件. 子查询只执行一次,且可以单独执行;.