nginxソース分析のupstream設計

6406 ワード

nginxの神秘的な武器江湖については、そのレンダリングを止めたことがありません.間違いなくupstreamです.nginxには、高性能、高同時性、強い安定性など、多くの切り札があります.しかしupstreamがなければかなり色が落ちます.upstreamはnginxをエージェントサーバにし、fastcgiプロトコルのphpに接続することができ、memcached、redis、mongodb、mysql handlersocket、uwsgiプロトコルのサーバ、さらにはすべてのサーバに接続することができます.本文は一歩一歩その神秘的な色彩を明らかにする.
今、あなたの直感には、upstreamはnginxの神秘的なメカニズムであり、nginxがバックエンドのサーバに接続できるようにしています.バックエンドに何台のサーバがあるかにかかわらず、指定したポリシーに基づいて1台を選択し、接続し、要求データを送信し、バックエンドサーバの応答を得て、最後にクライアントに応答します.もしこの説明がupstreamがnginxのために何をしたかを明らかにすれば、私たちはその実現を深く探求します.想像以上に簡単になる心配はありません.
nginxでupstreamをどのように使用するかは、upstream backend{server backend 1.example.com weight=5;server backend 2.example.com:8080;server unix:/tmp/backend 3;server backup 1.example.com:8080 backup;server backup 2.example.com:8080 backup;server {     location/{         proxy_pass http://backend;     } }
nginxのライフサイクルには、解析構成、起動プロセス、処理要求の3つの重要なプロセスがあります.この3段階をめぐってupstreamがどのように実現されるかを分析する.
1、解析構成:
nginxには複数のupstreamがあり、各upstreamには上のupstreamのような独自の名前があります.各upstreamは、指定した複数のサーバ情報に対応します.サーバはドメイン名、ip、unixであってもよい.最終的にはsocket操作可能なip:portとして解析されるので、ドメイン名であればgetservernameでより多くのサーバ情報に変換されます.そしてproxy_passは、nginxがリクエストを処理するときにusptream内のサーバを見つけるために、特定のupstreamにバインドされます.ここにはproxy_passの値はupstream nameではありません.upstreamの値を作成し、バインドします.これはfastcgi,memcachedなどupstreamを使用する他のモジュールにも適用されます.
構造体は次のとおりです.
typedef struct {
    ngx_http_upstream_conf_t       upstream;
...
} ngx_http_proxy_loc_conf_t;


typedef struct {
    ngx_http_upstream_srv_conf_t    *upstream;


    ngx_msec_t                       connect_timeout;
    ngx_msec_t                       send_timeout;
    ngx_msec_t                       read_timeout;
    ngx_msec_t                       timeout;
    ngx_msec_t                       next_upstream_timeout;


    size_t                           send_lowat;
...
} ngx_http_upstream_conf_t;


struct ngx_http_upstream_srv_conf_s {
    ngx_http_upstream_peer_t         peer;
    void                           **srv_conf;


    ngx_array_t                     *servers;  /* ngx_http_upstream_server_t */


    ngx_uint_t                       flags;
    ngx_str_t                        host;
    u_char                          *file_name;
    ngx_uint_t                       line;
    in_port_t                        port;
    in_port_t                        default_port;
    ngx_uint_t                       no_port;  /* unsigned no_port:1 */
};


typedef struct {
    ngx_str_t                        name;
    ngx_addr_t                      *addrs;
    ngx_uint_t                       naddrs;
    ngx_uint_t                       weight;
    ngx_uint_t                       max_fails;
    time_t                           fail_timeout;


    unsigned                         down:1;
    unsigned                         backup:1;
} ngx_http_upstream_server_t;


typedef struct {
    ngx_http_upstream_init_pt        init_upstream;
    ngx_http_upstream_init_peer_pt   init;
    void                            *data;
} ngx_http_upstream_peer_t;


struct ngx_http_upstream_rr_peer_s {
    struct sockaddr                *sockaddr;
    socklen_t                       socklen;
    ngx_str_t                       name;
    ngx_str_t                       server;
        
    ngx_int_t                       current_weight;
    ngx_int_t                       effective_weight;
    ngx_int_t                       weight;


    ngx_uint_t                      conns;
};

upstreams = {}; server_infos = []; upstreams[upstream_name] = server_infos; server_infos = [server1, server2, ...];
umcf->upstreams = [ngx_http_upstream_srv_conf_t*, ngx_http_upstream_srv_conf_t*, ...];
plcf->upstream = ngx_http_upstream_conf_t;
plcf->upstream.upstream = ngx_http_upstream_srv_conf_t*;
plcf->upstream.upstream.servers = [ngx_http_upstream_server_t*, ngx_http_upstream_server_t*, ...];
plcf->upstream.upstream.servers[i].addrs = [ngx_addr_t*, ngx_addr_t*, ...];
init_main発生後:
plcf->upstream.upstream.peer.init = ngx_http_upstream_init_round_robin_peer;
plcf->upstream.upstream.peer.data = [ngx_http_upstream_rr_peer_t*, ngx_http_upstream_rr_peer_t*, ...];
賢いあなたは、nginxが要求を処理するときに、どのように具体的なサーバーを見つけるかがpeerのinitとdataに基づいて計算されることを予見することができます.
2、プロセスの開始
ほっとして、upstreamはnginxの起動プロセスの段階で、何も起こらなかった.
3、処理要求
要求を処理するには、あるサーバを見つけて、指定したプロトコルに基づいて要求を送信し、応答を受信して解析し、最後にクライアントに応答します.
upstreamはどのようにして指定されたサーバーを見つけたのですか?
nginxには構造体ngx_がありますhttp_request_t:対応するのはリクエストです
struct ngx_http_request_s {
    uint32_t                          signature;         /* "HTTP" */
    ngx_connection_t                 *connection;
    ...
    ngx_http_upstream_t              *upstream;
    ngx_array_t                      *upstream_states;
                                         /* of ngx_http_upstream_state_t */
    ...
};

struct ngx_http_upstream_s {
    ...
    ngx_peer_connection_t            peer;
    ...
};

struct ngx_peer_connection_s {
    ngx_connection_t                *connection;


    struct sockaddr                 *sockaddr;
    socklen_t                        socklen;
    ngx_str_t                       *name;


    ngx_uint_t                       tries;
    ngx_msec_t                       start_time;


    ngx_event_get_peer_pt            get;
    ngx_event_free_peer_pt           free;
    void                            *data;
};

解析構成段階の最後にnginxはpeerのinitとdataの処理に基づいて計算される.requestにupstream、upstreamにpeer、peerのsocketaddr、socketlenに値があるようにして、nginxは具体的なサーバーに接続できるようにしましょう.
もともとこれに対して大きな幅を書きたいと思っていましたが、ソースコードを読む楽しみは細部を体得することで、書くのはずっと流れを整理するだけで、これらの構造体を除いて、他はすべてこの考え方に基づいて書いて、間違いを避けられないかもしれません.
3、upstreamには何がありますか.
upstreamはhttpの半分を占めていると言えます.タイマ、タイムアウト処理、リクエスト処理、リクエストの構築方法、レスポンスの解析方法、長接続、ポリシーなど.どの小さなテーマがもっと深く知りたいのか、読書量を見てから深く考えてみましょう.
nginxはhttpサーバだけでなくmailエージェントサーバ、streamエージェントサーバでもあります.はい、1.9バージョンのnginxはstream(tcp)をサポートし始めました.しかしhttpとstreamはupstreamをサポートしていますが、mailはサポートしていません.
nginxはwebsocketサーバ,rtmpサーバにも処理できる.upstreamの機能がhttp、streamから独立すれば、非常に優れた再構築になります.
4、私が書きたいことは興味があるかもしれません.
nginxのsubrequestは非常に不思議なメカニズムで、私が書いたnginxダイナミックエージェントなど、クールなことをすることができます.これはあなたの興味を引き起こすのではないでしょうか.モジュール、ソースコード、nginxのメッセージなど、興味のあることを教えてください.nginxはjavascritをサポートし、Igor Sysoev大神は自分の軽量級js仮想マシンを実現します.luaのソースコードがどのように実現するかに興味があれば、これを書いてみてください.^-^
本文は終わります!原文を読む:http://nglua.com/reads/5.html