nginxダイナミックエージェントスキーム

8569 ワード

0、需要:転送ポリシーの動的調整
データベースには大量のユーザーデータが格納されており、負荷等化サーバがユーザー情報に基づいて要求を動的に転送できるポリシーを制定する必要があります.
例えば、Aユーザ(001)の要求がAサーバ(192.168.1.1.1101)に転送され、Bユーザ(002)の要求がBサーバ(192.168.1.1.1102)に転送され、Cユーザ(003)の要求がAサーバ(192.168.1.1.1103)に転送されるなどである.
1、サーバーコンテキスト
フロントエンドnginxサーバ+N台バックエンドアプリケーションサーバ.単一のサーバでシミュレーションする準備をします.
フロントエンド:192.168.1.101:80
バックエンド:192.168.1.101:81
2、技術頭脳の嵐
プログラマーたちの頭の中にはいくつかの案があり始めました.直感もあれば、経験もあります.以下のようにします.
a、nginxモジュールを書き、モジュールの中でデータベースを読むかnosqlを読むことを実現し、データ値に基づいて転送する.
b、既存のモジュールを探して、直接根拠やスクリプトを変えることができるかどうかを見て解決することができます.ngx_luaは強くて考えられます.
c、サーバはいかなるブロックがないことを保証しなければならない.モジュールの実現時にnginxのsubrequestメカニズムを使用しなければならない.
d、blalala...
3、プログラマーの頭の中には何が入っていますか.単純
タスク1:webプログラマーAは、http apiインタフェースを書き、具体的なサーバ情報(ip+port)を返します.
タスク2:システムエンジニアBは、nginx構成を行い、Aのapiに基づいてnginxに戻り情報に基づいて動的転送を実現させる.
4、実現開始:
タスク1:分ごとに完成して、phpスクリプトを書きましょう.
タスク2:解体を続行
タスク2.1:最も簡単な転送を実現
server {
    listen  80;

    location / {
        proxy_pass  192.168.1.101:81;
    }
}


server {
    listen  81;

    location / {
        root  html;
    }
}

タスク2.2:動的転送の実現
ソースコードproxyを見てpassは変数を使用できますか?
static char *
ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ...

    value = cf->args->elts;

    url = &value[1];

    n = ngx_http_script_variables_count(url);  //      ,      

    if (n) {
        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = url;  
        ...
     }
     ...
}
配置を変更し、okをテストし、下に進みます.
server {
    listen  80;

    location / {
        set  $url 192.168.1.101:81;
        proxy_pass  $url;
    }
}

タスク2.3:apiに基づいて変数$urlの値を設定する
既成のモジュールがないようで、頭の中で一度フィルタリングして、あるとsubrequestに関係するモジュールでなければならなくて、auth_を思い出しましたrequestモジュールは、httpリクエストを構成し、httpリクエストの戻り結果に基づいてクライアントに正常にアクセスするかどうかを決定し、ソースコードを見てから実行できます.
static ngx_int_t
ngx_http_auth_request_handler(ngx_http_request_t *r)
{ 
    ...
    if (ctx != NULL) {
        ...
        if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {  //            
            return NGX_ERROR;
        }

        /* return appropriate status */

        if (ctx->status == NGX_HTTP_FORBIDDEN) { // 403
            return ctx->status;
        }
        
        // 200 and ...
        if (ctx->status >= NGX_HTTP_OK
            && ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
        {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "auth request unexpected status: %d", ctx->status);

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }  ...

    return NGX_AGAIN;
}

ソースコードから私達は2つの情報を掌握します:1、apiは状態コードを返して200 2、ngx_になりますhttp_auth_request_set_variablesには、次の情報が必要な場合があります.
static ngx_int_t
ngx_http_auth_request_set_variables(ngx_http_request_t *r,
    ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx)
{
    ...
    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
    v = cmcf->variables.elts;

    av = arcf->vars->elts;
    last = av + arcf->vars->nelts;

    //    arcf->vars     
    while (av < last) {  
        /*
         * explicitly set new value to make sure it will be available after
         * internal redirects
         */

        vv = &r->variables[av->index];

        if (ngx_http_complex_value(ctx->subrequest, &av->value, &val)
            != NGX_OK)
        {
            return NGX_ERROR;
        }

        vv->valid = 1;
        vv->not_found = 0;
        vv->data = val.data;
        vv->len = val.len;

        if (av->set_handler) {
            /*
             * set_handler only available in cmcf->variables_keys, so we store
             * it explicitly
             */

            av->set_handler(r, vv, v[av->index].data);  //     
        }

        av++;
    }

    return NGX_OK;
}
コードロジックはとても简単で、このモジュールの配置のあるメンバーを遍歴して、きっと変数と関系があるので、配置情报を探しました
static ngx_command_t  ngx_http_auth_request_commands[] = {

    { ngx_string("auth_request"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_http_auth_request,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("auth_request_set"), //         ,    
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
      ngx_http_auth_request_set, //         ,         
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};
整理すると、apiの返信情報を受信すると、モジュールは設定変数を処理する.soは以下のように構成され、okをテストし、続行する.
server {
    listen  80;

    location / {
        auth_request  /api.php; # php  
        auth_request_set  $url 192.168.1.101:81; #    ,       
        proxy_pass  $url;
    }

    location ~ \.php$ { #         /api.php 
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        include        fastcgi_params;
    }
}
タスク2.4:$urlの値をapiから返す情報から取得する
(2.3でシミュレーション全体を一歩ずつ終わらせないで、各ステップが正確で簡単で、コード再構築の原則に似ているかどうかを維持してください)
私たちはこれを解決します:auth_request_set   $url  192.168.1.101:81;
nginxにはどのような変数が要求された戻り情報を取得できるのか、ヘッダ情報も可能です(実はここではヘッダ情報からしか取得できないと心の中で判断しており、nginxのコードを熟知している程度).変数値を取得する関数を見てみましょう.
ngx_http_variable_value_t *
ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
{
    ...
    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);

    if (v) {
        if (v->flags & NGX_HTTP_VAR_INDEXED) {
            return ngx_http_get_flushed_variable(r, v->index);

        } else {

            vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));

            if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
                return vv;
            }

            return NULL;
        }
    }

    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
    if (vv == NULL) {
        return NULL;
    }

    //    nginx     http_xxx           xxx: ...
    if (ngx_strncmp(name->data, "http_", 5) == 0) {

        if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
            == NGX_OK)
        {
            return vv;
        }

        return NULL;
    }

    //      ,          ,     ,           
    if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
        //          ,        ,      header_in   ,
                header_out,          
        if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
            == NGX_OK) 
        {
            return vv;
        }

        return NULL;
    }

    ...

    vv->not_found = 1;

    return vv;
}
ここまで心の中はすでに数があって、phpコードを書いて、しかも直接テストにアクセスします正常です
api.php
<?php

$url = "192.168.1.101:81";
header("url: $url");
nginx構成を変更します.
server {
    listen  80;

    location / {
        auth_request  /api.php; # php  
        auth_request_set  $url $sent_http_url; #    ,       
        proxy_pass  $url;
    }

    location ~ \.php$ { #         /api.php 
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        include        fastcgi_params;
    }
} 

できました.気持ちがいいです.30分前に案を検証し、5分前に完成する予定です.
5、全体方案の整理:
a、> ./configure --with-http_auth_request_module && make && ./objs/nginx
b、nginx.conf
server {
    listen  80;

    location / {
        auth_request  /api.php; # php  
        auth_request_set  $url $sent_http_url; #    ,       
        proxy_pass  $url;
    }

    location ~ \.php$ { #         /api.php 
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        include        fastcgi_params;
    }
} 


server {
    listen  81;

    location / {
        root  html;
    }
}
   c、api.php
<?php

$url = "192.168.1.101:81";
header("url: $url");

もっと分かち合う:nglua.com