一个关于动态应用单核千级 rps 的传说

我们在过去的四个月中,已经开发了 8 个 nginx C 模块(第 8 个这两天刚放到 GitHub 上面,名为 ngx_set_misc ),后面还会有更多更精彩的模块甚至应用面世。这些模块的功能看起来很碎很零散,但其实是一个更宏伟的项目的组成部分。这个项目叫做 ngx_openresty.

我们的一个方向是几个客户端 .js 文件 + 几个 .html/.css 文件 + nginx.conf + 一个 mysql/oracle/pgsql 数据库,就轻松搞定一个完整的交互式 web 应用,或者至少是一个很复杂应用的一部分。

不幸的是,业界的一些同仁对这种应用开发模式产生了质疑,认为我们对 nginx 的各种应用层面的扩展让 nginx 自身变得臃肿和低效。本文旨对这些质疑进行一次非正式的反驳。目的不在于驳人面子和树己威风,而是为了争取更多的朋友加入我们在 nginx 领域的努力。

我们已经在 ngx_openresty 原型的基础上,使用 nginx.conf 和纯客户端 JavaScript 开发了一个比较完整的 blog 应用(blog 应用的源码在这里: http://github.com/agentzh/ngx_openresty/tree/master/demo/Blog/,服务器端使用的 nginx.conf 文件在这里: http://agentzh.org/misc/nginx.conf

在我们的压力实测中(利用我的 ThinkPad),上面这个 blog 应用的 AJAX 接口单核就能扛千级 rps,小请求在 keepalive 下几百并发也可以扛到 ~ 6000 rps,且禁用了 nginx 级别的 mysql 结果集 cache,内存、CPU 等资源的占用只是 php 等传统应用的一个零头,呵呵。其主要原因是:

  1. 都是认真书写的高度可复用的 C 代码来完成原先 PHP 等代码来完成的事情,
  2. 绝大部分应用都是 I/O 密集型的,所以让 nginx 高效的事件模型来统一调度整个应用的所有网络 I/O 操作(包括到 DB 等后端的),只会进一步提高性能,而非降低。相比之下,用 PHP 等脚本语言访问 mysql,一定会阻塞当前 PHP 进程或者线程,而 PHP 解释器的阻塞开销是非常大的。
  3. 我们总是可以通过 LVS + 多机 nginx 来线性 scale. 总体资源是一个常量,不会因为多启几个进程和线程就会增加,只要不是浪费。阻塞在 I/O 操作上、在多进程多线程间无谓地切换和争用、在后端应用和 nginx 之间通过 socket 复制请求和应答数据,等等等等,这些才是浪费。
  4. 通过 fastcgi 等协议,PHP 这些脚本语言不免要自己再解析一遍 HTTP 头和 URL 参数啥的,还要自己做 URL 分发;而 nginx 其实一般都已经解析和处理过了。
  5. 根据模版渲染 HTML 展现的工作现在改由客户浏览器去做了,通过 Jemplate 等客户端模版来从 JSON 数据生成最终的 HTML 等内容,于是这进一步节约了服务器端的计算。如果一秒有几千请求,在 cache miss 的情况下,就可以节约几千次 HTML 渲染,这累积起来,相比生成 JSON 是相当可观的,呵呵。
  6. 在现有的 FastCGI 后端应用的解决方案中(特别是 PHP),不可避免地会 buffer 输入请求和输出应答的所有数据(无论在 RAM 里,还是写到磁盘临时文件),无法高效地实现流式处理,所以在大数据量的应用中,开销甚巨。

如果还有我没有想到的理由,请来信补充,呵呵。

其实我们的方向不算特别新奇,Apache 2.2 早在几年前就提供了强大的 apr-dbd APImod_dbd 模块来提供从 server 到 mysql/pgsql/oracle/odbc 这些数据库后端的直连服务。

我们在雅虎工作的时候,也曾经通过 Apache 2.2 mod_dbd + PostgreSQL 后端搭建过单机几千 rps 的在线服务,当时这个东西是服务于雅虎财经。即使在那个 DB I/O 阻塞 apache worker 线程的场景中,我们也没觉得 Apache 在线上的性能差到哪儿去了,呵呵。

当然,我们有机会在 nginx 世界中做得比 Apache dbd 更好 😉 nginx 的内部架构比 Apache2 优秀多了,这是真的,呵呵。

所以还是面对现实,让我们一起拥抱高简洁和高性能吧!呵呵!

Update: 近期我们会推纯 nginx.conf 配置文件编程。长期的目标是:整合 coco luaconcurrent lua 到 nginx core,这样就可以直接在 nginx.conf 中使用 Lua 来 script nginx 核心了,同时提供类似 erlang 的透明的非阻塞 I/O、透明的跨 worker 跨机器的消息传递、以及 JIT 加速 😀

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

21 Responses to 一个关于动态应用单核千级 rps 的传说

  1. Googol Lee says:

    理解一下,目标是直接用js通过http给nginx发sql请求么?很有意思的想法。

  2. agentzh says:

    Googol Lee: 不是直接发 sql 请求,而是 REST 风格的 ajax 请求 🙂

  3. Googol Lee says:

    我看nginx.conf里直接写有sql语句,ajax请求的结果应该直接是这些sql的结果吧?不过sql有变化时要重启整个nginx服务器吧?

  4. agentzh says:

    在 nginx.conf 中的只是 SQL 查询模版。并非从客户端 JS 向服务器发送 SQL 请求。此二者有本质区别。客户端发起的 web service 请求中的参量,在 nginx 层面上拼接到 SQL 串中。(当然,未来亦可在此地引入服务器端 prepare 机制,在大数据量下是有意义的。)当然,出于维护性方面的考虑,可以将这些接口的定义单独列到一个 .conf 文件中,然后在主配置文件 nginx.conf 中包含之。当查询变化时,需要重启 nginx 服务器,或者仅通知 nginx 进程重新加载 config ;)动态接口定义是 ngx_openresty 的一个 TODO,这样查询变化,无需重启服务器或者重新加载服务器配置,但那样无疑会引入一些开销,即便启用元数据缓存 🙂 所以在现阶段,我们倾向于性能最大化,这样我们可以知道“天花板”在哪儿 😉

  5. Fenng says:

    我只是好奇应用场景在什么地方…

  6. agentzh says:

    应用场景是我们每天见到的那些 Web 应用 😉

  7. says:

    第五条我觉得写的不是很清楚,希望能再解释一下。

  8. agentzh says:

    骏马: 我又加了一些解释,希望更清楚一些了,呵呵。

  9. Linfeng says:

    nginx的多线程可以完善吗,有相关计划吗

  10. agentzh says:

    Linfeng Qiu: 很难实现多线程化,Igor 自己做了一半放弃了,现在 core 里还随处可见散乱的多线程的死代码。我们自己也没有去实现多线程支持的计划,因为在目前的 nginx 现状下,意义不是太大。。。呵呵。

  11. Linfeng says:

    想法挺不错的,确实可以获得很高的性能,但是复杂的配置会导致应用与运维都比较麻烦吧比较看好未来的lua版本,能把动态逻辑用外部的lua来实现,而内部还是高效的nginx;不知道lua的版本甚么时候会发布呀

  12. agentzh says:

    Lingfeng Qiu: 我们总是可以通过上层语言或者配置来生成最终的 nginx.conf 😉 把 nginx.conf 里的语言看作是机器语言好了,呵呵。ngx_lua 确实是未来的方向,对于很复杂的应用,需要全功能的脚本语言来编程 nginx 的基础设施 🙂

  13. agentzh says:

    Lingfeng Qiu: 我们希望在这个月得到 ngx_lua 的第一个 rewrite phase 的简单原型 🙂

  14. Matthew says:

    貌似是我需要的东东

  15. tiplip says:

    是用web server端c代码返回JSON,客户端js创建html页,从而比php,asp…更高效的提供服务吗?

    • yichunzhang says:

      嗯,这是一种玩法。另一种玩法是使用服务器端模版生成 HTML,和 PHP 的形式类似,但却是 100% 网络非阻塞的东西 🙂

      • tiplip says:

        我也在做这样的尝试,这个主要的优点就是性能优越,缺点我觉得是灵活性稍差,看需求了:)

  16. tiplip says:

    google instant是不是就是使用了js根据json创建了搜索结果?对js的要求比较高吧,比如代码质量,执行速度,要不在客户端会有慢的感觉?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s