ホームページ  >  記事  >  バックエンド開発  >  nginx フェーズの概要

nginx フェーズの概要

WBOY
WBOYオリジナル
2016-08-08 09:27:311153ブラウズ
1. nginx の 11 フェーズ

リクエストが nginx によって処理されるとき、次の表に nginx のすべてのフェーズと各フェーズのオプションの終了メソッドを示します。含まれるモジュールと対応する命令

フェーズ オプションの出口 モジュール/ディレクティブ 説明
NGX_HTTP_POST_READ_PHASE HttpRealIpMo dule リクエストコンテンツの読み取りフェーズ
NGX_HTTP_SERVER_REWRITE_PHASE (サーバー書き換え) HttpRewriteModule/rewrite リクエストアドレス書き換えフェーズ
NGX_HTTP_FIND_CONFIG_PHASE (場所の選択) HttpCoreModule/location 構成検索フェーズ
NGX_HTTP_REWRITE_PHASE 場所 (場所の書き換え) 場所の選択、
確定request
HttpRewriteModule / rewrite リクエストアドレス書き換えフェーズ
NGX_HTTP_POST_REWRITE_PHASE HttpRewriteModule / rewrite リクエストアドレス書き換え送信フェーズ
NGX_HTTP_PREACCESS_PHASE 劣化、NginxHttpLimitZoneModule / limit_zone、
HttpLimitReqModule / 制限req, HttpRealIpModule
アクセス許可チェック準備フェーズ
NGX_HTTP_ACCESS_PHASE finalize request HttpAccessModule / allowed、deny、NginxHttpAuthBasicMo dule/auth_basic アクセス許可チェックフェーズ
NGX_HTTP_POST_ACCESS_PHASE アクセス許可送信フェーズの確認
NGX_HTTP_TRY_FILES_PHASE 場所の選択 HttpCoreModule / try_files 設定項目try_files処理フェーズ
NGX_HTTP_CONTENT _PHASE HttpAutoindexModule / autoindex、HttpCoreModule / コア、HttpDavModule / DAV、
HttpEmptyGifModule / EmptyGif 、HttpFcgiModule / FastCGI、HttpFlvStreamModul / FLV、
HttpGzipStaticModule / gzip_static、HttpIndexModule / インデックス、
HttpMemcachedModule / memcached、EmbeddedPerlModule / perl、
HttpProxyModule / プロキシ、 pProxyModule / random_index、
HttpScgiModule / scgi、HttpStubStatusModule / stub_status、
HttpUwsgiModule / uwsgi HttpLuaModule / content_by_lua,
HttpCoreModule / proxy_pass
コンテンツ生成フェーズ
NGX_HTTP_LOG_PHASE HttpLogModuel / access_log ログモジュール処理フェーズ
2. 各フェーズの説明:
post readフェーズ: リクエストヘッダーを読み取った後、このステージは nginx が の値を変更できるようにします。リクエストヘッダーの IP アドレス、関連モジュール HttpRealIpModule.

server_rewrite フェーズ: このフェーズは主にグローバル変数またはサーバーレベルの書き換えを初期化します。書き換えコマンドがサーバーに配置されると、サーバー書き換えフェーズに入ります。 (書き換え手順については、書き換えフェーズを参照してください)

find config フェーズ:このフェーズでは、書き換えられた URI を使用して、対応する場所を検索します。場所レベルの書き換えディレクティブ。

書き換えフェーズ: 場所に書き換え命令を入れると、書き換えフェーズに入ります。この段階は場所レベルの URI 書き換え段階であり、書き換え命令は複数回実行される場合もあります。

書き換え命令には、HttpRewriteModuleのset命令と書き換え命令、HttpLuaModuleのset_by_lua命令、ngx_set_miscモジュールのset_unescape_uri命令が含まれます。また、HttpRewriteModuleのほぼすべての命令が書き換えステージに属します。

この時点で、次の質問について考えてみましょう。命令は別のモジュールを使用せずにこのフェーズに存在できるため、これらの命令は同じ場所に共存できますか? 共存できる場合、それらの実行順序は何ですか?

例 1:

次の例の出力について考えてみてください。

 location /test {
        set $a 32;
        set $b 56;
        set_by_lua $c "return ngx.var.a + ngx.var.b";
        set $d "$a + $b = $c";
        echo $d;
    }
http://localhost/test にアクセスすると、出力結果は 32 です + 56 = 88、これは予想と一致するはずです。

しかし、これは、同じフェーズに属する異なるモジュールのすべての命令が、フェーズ内に共存する場合に順番に実行される必要があることを証明するものではありません。 実際、上記のサードパーティ モジュールはすべて特別な手法を使用して、独自の構成命令を HttpRewriteModule の命令シーケンスに「挿入」します (これらはすべて、Marcus Clyne によって作成されたサードパーティ モジュール ngx_devel_kit を使用します)。言い換えれば、Nginx でのより従来的な書き換え 登録をステージングして命令を実行するサードパーティ製モジュールはそれほど幸運ではありません。これらの「通常のモジュール」の命令も書き換えステージで実行されますが、その構成命令と HttpRewriteModule (および同じステージ内の他のモジュール) は独立して実行されます。実行時、異なるモジュールの構成命令セット間の順序は通常不確実です (厳密に言うと、通常はモジュールのロード順序によって決まりますが、例外もあります)。たとえば、モジュール A と B は両方とも書き換えステージで命令を実行するため、モジュール B の命令を実行する前にモジュール A のすべての命令が実行されるか、その逆にモジュール B のすべての命令が実行されてから A が実行されます。実行された指示。モジュールのドキュメントに明示的に記載されていない限り、ユーザーは通常、この不確定な順序に依存する構成を作成すべきではありません。 ngx_array_var などのサードパーティ モジュールも多数あります。 また、ユーザー セッションの暗号化と復号化に使用される ngx_encrypted_session も、HttpRewriteModule の命令とシームレスに連携できます。標準の HttpRewriteModule は非常に広く使用されているため、その構成ディレクティブと混合できるサードパーティ モジュールは幸いです。 HttpRewriteModule と混合できない命令は、実際の使用時に注意する必要があります。その出力は、構成ファイル内の順序とは関係ありません。

結論: スコープが同じフェーズにある異なるモジュールの命令は、モジュール間で特別な互換性が作成されている場合、構成ファイルにある命令の順序で順番に実行されます

例 2:

について考えてみましょう。次の出力は何ですか?

location /test {
        set $value dog;
        more_set_input_headers "X-Species: $value";
        set $value cat;
        echo "X-Species: $http_x_species";
    }

访问:curl 'http://localhost/test'
输出:X-Species: cat
是不是和你的预期有点儿不一样呢?

说明:第三方模块 ngx_headers_more 提供了一系列配置指令,用于操纵当前请求的请求头和响应头。其中有一条名叫 more_set_input_headers 的指令可以在 rewrite 阶段改写指定的请求头(或者在请求头不存在时自动创建)。该指令的文档中有这么一行标记 phase: rewrite tail,是说这条指令总是运行在 rewrite 阶段的末尾。显然,写在 more_set_input_headers 指令之后的 set $value cat 语句却先执行了。也就是说属于HttpRewriteModule的set指令先执行完了,才执行ngx_header_more 的set_input_headers指令。
结论:即使运行在同一个请求处理阶段,分属不同模块的配置指令也可能会分开独立运行(除非像 ngx_set_misc 等模块那样针对 ngx_rewrite 模块提供特殊支持)。换句话说,在单个请求处理阶段内部,一般也会以 Nginx 模块为单位进一步地划分出内部子阶段。下面的例子3同例子2:

例子3:

location /test {
         set $a 1;
         rewrite_by_lua "ngx.var.a = ngx.var.a + 1";
         set $a 56;    
         echo $a;
     }

访问: curl 'http://localhost/test'
输出: 57

说明:HttpLuaModule的rewrite_by_lua 指令也是处在 rewrite tail phase,它也会在rewrite 阶段的末尾执行。因此HttpRewriteModule的所有set执行完后,才执行它。
显然,rewrite_by_lua 指令的行为不同于我们前面在 (二) 中介绍过的 set_by_lua 指令。
小伙伴们可能要问,既然 more_set_input_headers 和 rewrite_by_lua 指令都运行在 rewrite 阶段的末尾,那么它们之间的先后顺序又是怎样的呢?答案是:不一定。我们应当避免写出依赖它们二者间顺序的配置。

结论:作用域在同一个phase的不同modules的指令,如果没有做特殊兼容处理,则它们指令的执行顺序与指令在配置中出现的顺序无关,结果具有不确定性

post rewrite phase:

location级别重写的下一阶段,用来检查上阶段是否有uri重写,并根据结果跳转到合适的阶段;

preaccess phase:

访问权限控制的前一阶段,该阶段在权限控制阶段之前,一般也用于访问控制,比如限制访问频率,链接数等;相关模块/指令 :NginxHttpLimitZoneModule / limit_zone, 
HttpLimitReqModule / limit req, HttpRealIpModule

access phase:

访问权限控制阶段,比如基于ip黑白名单的权限控制,基于用户名密码的认证控制等;相关模块/指令 HttpAccessModule / allow, deny, NginxHttpAuthBasicModule / auth_basic。 HttpAccessModule提供的 allow 和 deny 配置指令可用于控制哪些 IP 地址可以访问,哪些不可以。HttpAccessModule模块还支持所谓的“CIDR 记法”来表示一个网段,例如 169.200.179.4/24 则表示路由前缀是 169.200.179.0(或者说子网掩码是 255.255.255.0)的网段。

思考下下面两个例子(例子5,例子6)
例子4:

    location /hello {
        allow 127.0.0.1;
        deny all; 
        echo "hello world";
    }

本机访问:curl http://localhost/hello ,输出:hello world
其他机器访问:curl http://localhost/hello ,报403错误

例子5:

    location /hello {
        deny all; 
        allow 127.0.0.1;
        echo "hello world";
    }

本机访问:curl http://localhost/hello ,报403错误
其他机器访问:curl http://localhost/hello ,报403错误

例5和例6的区别在于deny all ,和allow 127.0.0.1 这两条指令的顺序不同。但例5中/hello 只允许从本机(IP 地址为保留的 127.0.0.1)访问,而从其他 IP 地址访问都会被拒(返回 403 错误页)。而例6中被配置为任何IP访问都会返回403错误。
原因说明:同属于HttpAccessModule这个模块的多条配置指令之间是按顺序执行的,直到遇到第一条满足条件的指令就不再执行后续的 allow 和 deny 指令。如果首先匹配的指令是 allow,则会继续执行后续其他模块的指令或者跳到后续的处理阶段;而如果首先满足的是 deny 则会立即中止当前整个请求的处理,并立即返回给客户端 403 错误页。

结论:同一个phase的同一个module内的多条指令的执行顺序由这个module自己来定义。

因为 HttpAccessModule的指令运行在 access 阶段,而 access 阶段又处于 rewrite 阶段之后,所以前面我们见到的所有那些在 rewrite 阶段运行的配置指令,都总是在 allow 和 deny 之前执行,而无论它们在配置文件中的书写顺序是怎样的。所以,为了避免阅读配置时的混乱,我们应该总是让指令的书写顺序和它们的实际执行顺序保持一致。

post access phase:

访问权限控制的后一阶段,该阶段根据权限控制阶段的执行结果进行相应处理;

try files phase:

HttpCoreModule的try_files指令的处理阶段,如果没有配置try_files指令,则该阶段被跳过; 该指令作用域: server ,location。
当try_files用于server阶段时一般是初始化作用,用来加载一些文件。

语法: try_files file1,file2,..,fileN-1 ... ,fallback 或者try_files file1,file2,..,fileN = code
用来顺序检查file1,file2,...fileN-1是否存在,如果最后一个字符为/表示这是一个目录。只要找到一个file存在,则进入到content phase,输出内容。如果前N-1个参数代表的file都不存在,此时最后一个参数发挥作用,最后一个参数用于内部跳转,并且只有最后一个参数是用作内部跳转,因此最后一个参数必须存在,否则将会引发一个内部错误。前面的file参数只是设置uri指向,不会引发内部跳转。此外注意: try_files和rewrite不同,rewrite指令会自动保存原请求的参数$args,而try_files最后的fallback参数如果需要带上请求的参数,则需要明确指出,如:

try_files $uri $uri/ /index.php?q=$uri&$args
content phase:

内容生成阶段,该阶段产生响应,并发送到客户端; 这个阶段相关的模块和指令较多。这里仅拿HttpLuaModule的content_by_lua和HttpEchoModule的echo指令来举个例子再次证明上述谈论到的一个结论。
例子:

 location /test {
          set $a 123;
          set $b 456;
          echo $b;
          content_by_lua '
             ngx.say(ngx.var.a)
           ';
    }

访问: curl http://localhost/test
输出: 123 
即只有content_by_lua里面的ngx.say执行了,外面的echo $b指令没有执行。echo和content_by_lua分别属于两个module的指令,他们的作用phase都是content phase。这两个module不兼容,
这两条指令不是顺序执行,至于执行结果是什么,不确定,这里是只有content_by_lua被执行了。再次证明之前的结论:作用域在同一个phase的不同modules的指令,如果没有做特殊兼容处理,则它们指令的执行顺序与指令在配置中出现的顺序无关,结果具有不确定性,需要尽量避免这种情况出现。
 location /test_echo {
          content_by_lua '
             ngx.say(ngx.var.a)
           ';
          set $a 123;
          set $b 456;
    }
log phase:

日志记录阶段,该阶段记录访问日志;

三、小结:
  • 11个phases粗略介绍完了。这11个phases,不是每个请求都会经历所有的11个phase。有可能某些phase没有经历,如果请求内部包含子请求,某些phase可能会出现多次。
  • 在单个请求的处理过程中,前面的phase总是在后面phase之前执行。这里的前后值得是本文phase的介绍顺序,而不是phase相关的指令在配置文件中出现的顺序。
    例如,rewrite phase总是在content phase之前执行,与指令在配置文件中出现顺序无关,下面的例子
    location /test {
        set $a 11;
        echo $a; 
        set $a 22;
        echo $a;
    }
    

    实际执行顺序为set $a 11;set $a 22;echo $a;echo $a;
    访问:curl http://localhost/test
    输出:
    22 
    22
    理由是rewrite phase总是在content phase之前执行
  • 作用域为同一个phase的不同modules的指令,如果modules之间做了特殊的兼容,则它们按照指令在配置文件中出现的顺序依次执行下来
  • 作用域在同一个phase的不同modules的指令,如果没有做特殊兼容处理,则它们指令的执行顺序与指令在配置中出现的顺序无关,结果具有不确定性
  • 同一个phase的同一个module内的多条指令的执行顺序由这个module自己来定义。

参考资料:

http://wiki.nginx.org/

http://wiki.nginx.org/Phases

http://blog.sina.com.cn/s/blog_6d579ff40100xpff.html

上記は、関連コンテンツを含む nginx フェーズの紹介であり、PHP チュートリアルに興味のある友人に役立つことを願っています。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:微信支付之公众号支付次の記事:php soap用法