ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

nginx proxy_pass和upstream源码分析

2021-09-13 10:58:54  阅读:455  来源: 互联网

标签:... http pass nginx 源码 proxy conf upstream ngx


poxy_pass

nginx中两个模块有proxy_pass指令,用于反向代理配置项。

分别是:

ngx_http_proxy_module

ngx_stream_proxy_module

ngx_http_proxy_moduleproxy_pass

句法:proxy_pass URL;
上下文:location, if in location, limit_except
说明:设置后端代理服务器的协议(protocol)和地址(address),以及location中可以匹配的一个可选的URI。协议可以是"http"或"https"。地址可以是一个域名或ip地址和端口,或者一个 unix-domain socket 路径。 详见官方文档: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

ngx_stream_proxy_moduleproxy_pass

句法:proxy_pass address;
上下文:server
说明:设置后端代理服务器的地址。这个地址(address)可以是一个域名或ip地址和端口,或者一个 unix-domain socket路径。 详见官方文档: http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_pass

upstream

upstream为nginx负载均衡配置项

句法:upstream name { ... }
上下文:http
说明:定义一组服务器。服务器可以侦听不同的端口。此外,侦听 TCP 和 UNIX 域套接字的服务器可以混合使用。默认情况下,使用加权轮询负载均衡方法在服务器之间分配请求。

upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;

    server backup1.example.com  backup;
}

在上面的示例中,每7个请求将按如下方式分配:5 个请求转到backend1.example.com第二个和第三个服务器中的每一个。

如果在与服务器通信期间发生错误,则请求将传递到下一个服务器,依此类推,直到尝试所有正在运行的服务器。如果无法从任何服务器获得成功响应,则客户端将收到与最后一个服务器通信的结果。

配置基本的格式为在server{},proxy_pass到upstream。

server {

        listen  10.10.55.66:8888 backlog=20480;

        proxy_set_header  Host $http_host;

        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_set_header  X-Forwarded-Proto $scheme;

        proxy_set_header  X-Forwarded-Port $remote_port;

        limit_req  zone=req10k burst=1000;

        location / {

            proxy_pass  http://rp_10_10_55_66_8888;

        }                                                                                                                                                                                                    

    }

    upstream rp_10_10_55_66_8888 {

        check  type=http default_down=false timeout=4000 rise=5 fall=4 interval=5000;

        check_http_send  "HEAD /healthCheck HTTP/1.0\r\nHOST:10.10.55.66\r\n\r\n";

        server  10.10.55.67:8080 weight=20;

    }

源码分析

ngx_http_proxy_pass函数

static char *

ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

...

    // 这里loc对应的conf的handler置为要转发的handler

    clcf->handler = ngx_http_proxy_handler;

    // 这里u保存了对应upstream的信息

    //调用add函数把upstream加入到umcf->implicit_upstreams

    plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);

     

...

}

ngx_http_upstream_add函数

ngx_http_upstream_srv_conf_t *

ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)

{

...

    //find upstream是否在红黑树中

    umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);

    uscfp = umcf->upstreams.elts;

    uscf = ngx_http_upstream_rbtree_lookup(umcf, &u->host);

    // 开始找不到,进行创建和implicit_upstreams

    part = &umcf->implicit_upstreams.part;

    uscfp = part->elts;

    uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));

    // 赋值......

    // 把指针赋值到umcf->upstreams 、umcf->implicit_upstreams

    uscfp = ngx_array_push(&umcf->upstreams);

    *uscfp = uscf;

    uscfp = ngx_list_push(&umcf->implicit_upstreams);

    *uscfp = uscf;

    return uscf

...

}

遇到upstream指令的时候会调用http_upstream,继续调用http_upstream_add。这次带有创建标志。

把放在implicit不确定的upstream加入真正的红黑树里,同时从implicit中删除。

而后返回进行接下来upstream块中指令的填充。

ngx_http_upstream_srv_conf_t *

ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)

{

...

    // 遍历寻找

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {

            part = part->next;

            uscfp = part->elts;

            i = 0;

        }

        // 找到

        uscf = uscfp[i];

        ngx_rbtree_insert(&umcf->rbtree, &uscfp[i]->node);

        ngx_list_delete(&umcf->implicit_upstreams, &uscfp[i]);

        return uscf;

    }

...

}

ngx_http_proxy_handler函数

qproxy_handler设置了create request的方法

在接收请求body逻辑中调用upstream init的方法

static ngx_int_t

ngx_http_proxy_handler(ngx_http_request_t *r)

{

...

    if (ngx_http_upstream_create(r) != NGX_OK) {

        return NGX_HTTP_INTERNAL_SERVER_ERROR;

    }

    u->create_request = ngx_http_proxy_create_request;

    u->reinit_request = ngx_http_proxy_reinit_request;

    u->process_header = ngx_http_proxy_process_status_line;

    u->abort_request = ngx_http_proxy_abort_request;

    u->finalize_request = ngx_http_proxy_finalize_request;

    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

...

}

ngx_http_upstream_init函数

调用了init request

static void

ngx_http_upstream_init_request(ngx_http_request_t *r)

{

...

    // 设置init初始化函数

    if (uscf->peer.init(r, uscf) != NGX_OK) {

        ngx_http_upstream_finalize_request(r, u,

                                           NGX_HTTP_INTERNAL_SERVER_ERROR);

        return;

    }

    u->peer.start_time = ngx_current_msec;

    if (u->conf->next_upstream_tries

        && u->peer.tries > u->conf->next_upstream_tries)

    {

        u->peer.tries = u->conf->next_upstream_tries;

    }

    // 发起连接

    ngx_http_upstream_connect(r, u);

...

}

void

ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)

{

...

    rc = ngx_event_connect_peer(&u->peer);

...

}

ngx_http_upstream函数

static char *

ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)

{

...

    uscf = ngx_http_upstream_add

    ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;

    uscf->srv_conf = ctx->srv_conf;

    pcf = *cf;

    cf->ctx = ctx;

    cf->cmd_type = NGX_HTTP_UPS_CONF;

    //解析upstream内部块的指令

    rv = ngx_conf_parse(cf, NULL);

...

}

upstream块中的server指令

{ ngx_string("server"),

      NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,

      ngx_http_upstream_server,

      NGX_HTTP_SRV_CONF_OFFSET,

      0,

      NULL },

static char *

ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

...

    if (uscf->servers == NULL) {

    uscf->servers = ngx_array_create(cf->pool, 4,sizeof(ngx_http_upstream_server_t));

    us = ngx_array_push(uscf->servers);

    ngx_memzero(us, sizeof(ngx_http_upstream_server_t));

    value = cf->args->elts;

    vni = -1;

    us->hp_addr = NULL;

    // 获得参数

    us->name = u.url;

    us->addrs = u.addrs;

    us->naddrs = u.naddrs;

    us->host = u.host;

    us->weight = weight;

    us->max_fails = max_fails;

    us->fail_timeout = fail_timeout;

    us->id = id;

...

}

结束

一个完整的nginx proxy_pass和upstream配置、源码分析就是这样的。

标签:...,http,pass,nginx,源码,proxy,conf,upstream,ngx
来源: https://blog.csdn.net/realmardrid/article/details/118106375

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有