[DOC] 关于php-dws的重要说明

1. 什么是 php-dws ?

php-dws 是 PHP Direct Web Server 的缩写, 是针对 php 的一个新型 sapi 工作模块,
通过 dwsgi 协议与 web server (如 nginx) 协同工作.
(dwsgi: Direct Web Server Gateway Interface)

之所以叫 Direct , 是因为它在执行 php 脚本过程中是直接把输出结果传递给 http client 的
而不是转交 webserver(nginx) 再由 webserver 发送给 http client.

在多数情况下, php-dws 可以用于取代 php/fastcgi 的工作, 并且能更出色的完成.

2. 和 PHP/FastCGI 相比较有什么不同?

1) 我们先看一下下面的示意图了解它们的不同工作原理:

      [PHP/FATCGI]
      ============

            i)request header+body     ii)request header+body
           +~~~~>~~~~>~~~~>~~~+     +~~~~~>~~~~~>~~~~>~~~~~+
           |                  |     |                      |
          /|\                \|/   / \                    \|/
      WebVisitor             Web Server               FastCGIServer
        (user)                (nginx)                  (php-cgi)
          /|\                \ /   /|\                    \ /
           |                  |     |                      |
           +~~~<~~~~<~~~~<~~~~+     +~~~~~<~~~~~<~~~~<~~~~~+
          iv)response header+body    iii)response header+body

      [PHP/DWSGI]
      ===========

            i)request header           ii)request header
           +~~~~>~~~~>~~~~>~~~+     +~~~~~>~~~~~>~~~~>~~~~~+
           |                  |     |                      |
          /|\                \|/   / \                    \|/
      WebVisitor             Web Server               DWSCGI Server
        (user)                (nginx)                   (php-dws)
       /|\  \ /                                         /|\   \ /
        |    |                                           |     |
        |    +~~~~~~~~>~~~~~~~~~~~~>~~~~~~~~~~~~>~~~~~~~~+     |
        |     iii) request body                                |
        |                                                      |
        +~~~~~~~~~~~~~<~~~~~~~~~~~<~~~~~~~~~~~~~<~~~~~~~~~~~~~~+   
        iv)response header+body

2) 由图可以看出 DWSGI 相比 FASTCGI 有如下明显优势:

i) 节省了很多数据传输, 大大降低繁忙时期的 IO 负载和性能, 由于通常 HTTP 数据都不大,
所以测试数据并不是很明显 100KB 左右的 HTTP 输出大约提升 10~15% 的性能, 输出数据
越大则性能提升越明显;

ii) 给了 php 更直接的输出操控权限, 真正让 php 程序员有机会直接构造自己的 HTTP 输出,
而不再需要受到 webserver 的牵制, 典型的一个情况就是对于长时运行的脚本可以做到
一边执行一边输出, 如下代码:

for($i=1;$i<100;$i++) 
{ 
  echo "$i\n";
  ob_flush();
  flush();
  sleep(1); 
}

iii) 从此与那恼人的 502 Gateway error 说 byebye!

3) DWSGI 的不足之处, 并不是说 dwsgi 就绝对好了, 它也有以下缺陷:
i) 由于采用 unix domain socket 来实现描述字传递, 所以必须和 web server 同一台服务器;
ii) 目前不支持 win32 系统;
iii) 目前不支持 SSL 传输, 即 https.

3. DWSGI 是个怎么样子的协议?

出于FastCGI的优秀设计以及移植的方便考虑, DWSGI 几乎采用和 FastCGI 一样的协议格式, 但
略有不同.

1) 由于需要传递描述字, 所以 dwsgi server 只能绑定运行在 Unix domain socket 上;

2) 在首次会话发送请求头部时(16bytes), 采用 Sendmsg() 将 HTTP 连接的 socket fd
一并传递给 dwsgi server.

3) dwsgi 收到完整的请求后会发送一个结束包给 webserver, webserver收到后就关闭自身的
HTTP 连接描述符, 把连接读写的权限完全地交给 dwsgi, dwsgi 则可以直接将运行结果以
标准的 HTTP 协议规范发送给用户.

而 fastcgi 是全程保持和 webserver 相连, 输出结果先转交 webserver 由 webserver
作相应的缓冲和处理再转交给用户.

4. php-dws 的工作方式是如何的?

当前的 php-dws 是从原 sapi/cgi 的代码直接修改而来的, 还比较粗糙只支持固定进程数的. 计划
将来改变采用动态 prefork, 并记录相应的进程状态以及统一的配置文件等.

此外, php-dws 把子进程数和每个进程处理的最大请求数均改为启动选项而不再是环境变量, 同时支持
指定较低权限的用户身份来运行.

[DOC] 关于php-dws的重要说明》上有3条评论

  1. Sunyanzi

    这东西好有趣 …

    原理似乎是当 nginx 收到用户请求之后把源连接关闭 …

    由 dwscgi 来接管用户的当前请求 … 处理请求的文件并自己添加 HTTP 头返回结果给用户 …

    我是个新手 … 问个小白问题别见怪 …

    我不明白的一件事是 … 80 端口已经被 nginx 持有了 …

    dwscgi 如何做到不经过 nginx 直接由 80 端口返回数据给用户呢 ..?

    又或者是直接从服务端开一个新端口直连客户端的那个五位数的数据端口么 ..?

    说到这个我想起自己之前写过的一个 php 的 webserver … 用于处理长连接 …

    由 php 实现对 80 端口的监听和请求的处理 …

    收到新请求之后 fork 一个处理进程 … 使用新的端口 …

    然后由主进程把用户请求转到那个新的端口上 …

    由 fork 出来的进程在新的端口上继续充当 webserver 完成和用户的即时交互 …

    简而言之就是 80 端口只用于转发 … fork 出来的进程在新端口上完成命令处理 …

    我当时的这个作品是为了赌一口气 … 用 php 这种没有线程概念的语言实现长连接 …

    但是最后有个问题我无法解决 … 于是最后放弃了 …

    因为每个 fork 出来的进程都会一直存在直到用户关闭浏览器 …

    当并发超过 300 的时候也就是后台有 300+ 的 php 进程时有一定概率所有的进程会同时崩溃 …

    不知道如果我在 dwscgi 上写一个类似的 while ( 1 ) { sleep( 1 ); } …

    然后在高并发的情况下会不会发生一样的事情呢 ..?

    回复
  2. hightman

    你的问题大概可以分成2部分:

    1. DWSGI强调的是同一机器上并绑定在 unix domain socket上,因为透过这个可以在跨进程传递描述字(socket fd)。
    也就是说 nginx 发送请求给 php-dws 时会连同之前建立好的HTTP连接的描述字(socket fd)发送给 php-dws。

    这必须是通过 sendmsg() 调用在内核完成的,并不是简单的整型数值传递!

    2. 其实PHP的设计本身就是作为其它应用的一个小模块,统一的入口可以视为 php_execute_script(); 那么在这个函数
    内部是无法中断和并行处理多个请求的。所以 无论是 dwsgi 还是 fastcgi(含fpm)以及mod_php/apache,必然都是
    每个线程或进程只能处理一个请求,如果你的请求长时间不能释放,那么这个线程或进程也不能处理别的请求了。

    所以如果你写一个 while(1) sleep(1); 的脚本,然后再用 ab 之类的工具发起大量的并发请求直到占用所有的 fastcgi/dws进程,
    那么此时它将无法处理别的PHP运行请求了。

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注