Web server调研分析 Filed under: Web Server — cmpan @ 2012-10-29 20:38:34 摘要 简单可依赖的架构首先需要有一个简单可依赖的前端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都是状态机驱动模型,两者之间主要体现在细节的差异性上。 Nginx对整个状态进行了分类,分成预处理、状态机、filter流程三个明显的阶段。 Lighttpd的状态机相对简单固定。Nginx则相对灵活。 Nginx的大部分处理状态都是可以扩展的并且可中断的。Lighttpd在部分状态中也可以扩展的。 耦合程度。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个。 状态机 Nginx对整个状态进行了分类,分成预处理、状态机、filter流程三个明显的阶段。 Lighttpd的状态机相对简单固定。Nginx则相对灵活。 Nginx的每一个状态都是可以扩展的并且可中断的。Lighttpd在部分状态中也可以扩展的。 耦合程度。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,未来的主流。”
以前我们为nginx做统计,都是通过对日志的分析来完成.比较麻烦,现在基于ngx_lua插件,开发了实时统计站点状态的脚本,解放生产力. 项目主页: https://github.com/skyeydemon/ngx-lua-stats 功能 支持分不同虚拟主机统计, 同一个虚拟主机下可以分不同的loca
介绍
以前我们为nginx做统计,都是通过对日志的分析来完成.比较麻烦,现在基于ngx_lua插件,开发了实时统计站点状态的脚本,解放生产力.
项目主页: https://github.com/skyeydemon/ngx-lua-stats
功能
支持分不同虚拟主机统计, 同一个虚拟主机下可以分不同的location统计.
可以统计与query-times request-time status-code speed 相关的数据.
环境依赖
nginx + ngx_http_lua_module
安装
http://wiki.nginx.org/HttpLuaModule#Installation
使用方法
添加全局字典
在nginx的配置中添加dict的初始化, 类似如下
lua_shared_dict log_dict 20M;
lua_shared_dict result_dict 20M;
为特定的location添加统计
只需要添加一句即可~~
将lua脚本嵌套进nginx的配置中, 例如:
server {
listen 8080;
server_name weatherapi.market.xiaomi.com;
access_log /home/work/nginx/logs/weatherapi.market.xiaomi.com.log milog;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://weatherapi.market.xiaomi.com_backend;
log_by_lua_file ./site-enable/record.lua;
}
}
输出结果
通过配置一个server, 使得可以通过curl获取到字典里的所有结果
server {
listen 8080 default;
server_name _;
location / {
return 404;
}
location /status {
content_by_lua_file ./site-enable/output.lua;
}
location /empty_dict {
content_by_lua_file ./site-enable/empty_dict.lua;
}
}
可以通过如下命令获取
curl ip_addr:8080/status
清理字典
运行一段时间之后, 字典会变大. 可以通过如下接口清理
curl ip_addr:8080/empty_dict
支持的统计数据说明
目前支持统计以下数据,返回的原始数据类似于
--------------------------
key: weatherapi.market.xiaomi.com__upstream_time_10.0.3.32:8250_counter
0.375
key: weatherapi.market.xiaomi.com__upstream_time_10.0.3.32:8250_nb_counter
124
key: weatherapi.market.xiaomi.com__upstream_time_10.0.4.93:8250_counter
0.131
key: weatherapi.market.xiaomi.com__upstream_time_10.0.4.93:8250_nb_counter
123
key: weatherapi.market.xiaomi.com__upstream_time_10.20.12.49:8250_counter
0.081
key: weatherapi.market.xiaomi.com__upstream_time_10.20.12.49:8250_nb_counter
127
key: weatherapi.market.xiaomi.com__query_counter
500
key: weatherapi.market.xiaomi.com__request_time_counter
0.683
key: weatherapi.market.xiaomi.com__upstream_time_counter
0.683
key: weatherapi.market.xiaomi.com__upstream_time_10.20.12.59:8250_counter
0.096
key: weatherapi.market.xiaomi.com__upstream_time_10.20.12.59:8250_nb_counter
126
key: weatherapi.market.xiaomi.com__bytes_sent_counter
81500
其中 __ 用来分割虚拟主机(包含prefix)与后面的数据项,便于数据处理.
counter表示此值一直在累加
nb表示次数
可以得到的数据包括: query次数 request_time bytes_sent upstream_time
其中 upstream_time_10.20.12.49:8250_counter 表示到某个特定后端的upstrea_time耗时累加
upstream_time_10.20.12.49:8250_nb_counter 表示到到某个特定后端的upstrea_time次数累加
如何处理数据
因为采集到的数据大多都是counter值,需要监控系统支持对于delta的处理.目前我们公司的perf-counter监控系统支持简单运算。所以这个处理起来比较简单,对于没有这种系统的同学来说,需要自己处理数据,得到delta值以及更复杂的数据,比如:
delta(bytes_sent_counter)/delta(query_counter) 得到就是这段时间的http传输速度
delta(upstream_time_10.20.12.49:8250_counter)/delta(upstream_time_10.20.12.49:8250_nb_counter) 得到的就是这个后端upstream_time的平均值
Nginx是什么?Nginx介绍
开源中国
发表于 2014-09-12 20:09:45
Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”, 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理服务器.Nginx是由俄罗斯人 Igor Sysoev为俄罗斯访问量第二的 Rambler.ru站点开发的,它已经在该站点运行超过两年半了。Igor Sysoev在建立的项目时,使用基于BSD许可。
据说他当初是F5的成员之一,英文主页:http://nginx.net。
俄罗斯的一些大网站已经使用它超过两年多了, 一直表现不凡,相信想了解nginx的朋友都读过阿叶大哥的利用nginx实现负载均衡.直到2007年4月,俄罗 斯大约有20%左右的虚拟主机是由nignx服务或代理的。Google在线安全博客中统计nginx服务或代理了大约所有Internet虚拟主机的4%。而netcraft的统计显示,nginx服务的主机在过去的一年里以四倍的速度增长。短短的几年里,它的排名已跃进第9。(参见:http://survey.netcraft.com/Reports/200707/)
Nginx以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。其拥有匹配 Lighttpd的性能,同时还没有Lighttpd的内存泄漏问题,而且Lighttpd的mod_proxy也有一些问题并且很久没有更新。
因此我打算用其替代Apache应用于Linux服务器上。但是Nginx并不支持cgi方式运行,原因是可以减少因此带来的一些程序上的漏洞。那么我们必须使用FastCGI方式来执行PHP程序。
现在,Igor将源代码以类BSD许可证的形式发布。Nginx因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名.业界一致认为它是Apache2.2+mod_proxy_balancer的轻量级代替者,不仅是因为响应静态页面的速度非常快,而且它的模块数量达到Apache的近2/3。对proxy 和 rewrite模块的支持很彻底,还支持mod_fcgi、ssl、vhosts ,适合用来做mongrel clusters的前端HTTP响应。
nginx做为HTTP服务器,有以下几项基本特性:
处理静态文件,索引文件以及自动索引;打开文件描述符缓冲. 无缓存的反向代理加速,简单的负载均衡和容错. FastCGI,简单的负载均衡和容错. 模块化的结构。包括gzipping, byte ranges, chunked responses,以及 SSI-filter等filter。如果由FastCGI或其它代理服务器处理单页中存在的多个SSI,则这项处理可以并行运行,而不需要相互等待。 支持SSL 和 TLSSNI.
Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率 。它支持内核Poll模型,能经受高负载的考验,有报告表明能支持高达 50,000个并发连接数。
Nginx具有很高的稳定性。其它HTTP服务器,当遇到访问的峰值,或者有人恶意发起慢速连接时,也很可能会导致服务器物理内存耗尽频繁交换,失去响应,只能重启服务器。例如当前apache一旦上到200个以上进程,web响应速度就明显非常缓慢了。而Nginx采取了分阶段资源分配技术,使得它的CPU与内存占用率非常低。nginx官方表示保持10,000个没有活动的连接,它只占2.5M内存,所以类似DOS这样的攻击对nginx来说基本上是毫无用处的。就稳定性而言,nginx比lighthttpd更胜一筹。
Nginx支持热部署。它的启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够在不间断服务的情况下,对软件版本进行进行升级。
Nginx采用master-slave模型,能够充分利用SMP的优势,且能够减少工作进程在磁盘I/O的阻塞延迟。当采用select()/poll()调用时,还可以限制每个进程的连接数。
Nginx代码质量非常高,代码很规范,手法成熟, 模块扩展也很容易。特别值得一提的是强大的Upstream与Filter链。 Upstream为诸如reverse proxy,与其他服务器通信模块的编写奠定了很好的基础。而Filter链最酷的部分就是各个filter不必等待前一个filter执行完毕。它可以把前一个filter的输出做为当前filter的输入,这有点像Unix的管线。这意味着,一个模块可以开始压缩从后端服务器发送过来的请求,且可以在模块接收完后端服务器的整个请求之前把压缩流转向客户端。
Nginx采用了一些os提供的最新特性如对sendfile (Linux2.2+),accept-filter (FreeBSD4.1+),TCP_DEFER_ACCEPT (Linux 2.4+)的支持,从而大大提高了性能。
当然,nginx还很年轻,多多少少存在一些问题,比如:Nginx是俄罗斯人创建,目前文档方面还不是很完善.因为文档大多是俄语,所以文档方面这也是个障碍.尽管nignx的模块比较多,但它们还不够完善。对脚本的支持力度不够。
这些问题,nginx的作者和社区都在努力解决,我们有理由相信nginx将继续以高速的增长率来分享轻量级HTTP服务器市场,会有一个更美好的未来。