nginx upstream模块详解(处理流程篇一 upstream处理)

本文详细介绍了Nginx的upstream模块在代理和缓存中的核心作用,包括创建upstream、初始化、请求处理、响应头处理、包体处理、响应发送等关键步骤。同时,讲解了如何处理Set-Cookie、Redirect、Cache-Control等HTTP头部信息,以及影响缓存策略的各种属性,如max-age、stale-while-revalidate等。
摘要由CSDN通过智能技术生成

upstream 是nginx作为代理及缓存的核心结构 并且请求上游  发送至下游都能由相关联的模块进行干预处理

upstream 模块流程处理如下

创建upstream

ngx_int_t
ngx_http_upstream_create(ngx_http_request_t *r)
{
    ngx_http_upstream_t  *u;

    u = r->upstream;

    if (u && u->cleanup) {    //upstream变量存在 并且配置有cleanup 进行清除
        r->main->count++;
        ngx_http_upstream_cleanup(r);
    }
    ...  //创建upstream 必要初始化
    return NGX_OK;
}

upstream初始化

void
ngx_http_upstream_init(ngx_http_request_t *r)
{
    ngx_connection_t     *c;

    c = r->connection;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http init upstream, client timer: %d", c->read->timer_set);

#if (NGX_HTTP_V2)   //http 2.0初始化处理
    if (r->stream) { 
        ngx_http_upstream_init_request(r);
        return;
    }
#endif

    if (c->read->timer_set) {      //删除超时定时器
        ngx_del_timer(c->read);
    }
    //upstream 初始化
    ngx_http_upstream_init_request(r);
}

ngx_http_upstream_init_request具体实现

static void
ngx_http_upstream_init_request(ngx_http_request_t *r)
{
    //处于aio状态 则直接返回
    if (r->aio) {
        return;
    }

    u = r->upstream;

#if (NGX_HTTP_CACHE)

    if (u->conf->cache) {
        ngx_int_t  rc;

        rc = ngx_http_upstream_cache(r, u);

        if (rc == NGX_BUSY) {      //来不及处理 返回等待事件触发 NGX_BUSY用于并发请求miss 在获取数据之前 除第一个请求以外的其他请求均被阻塞
            return;
        }

        r->write_event_handler = ngx_http_request_empty_handler;  //写事件触发不做处理

        if (rc == NGX_ERROR) {  //缓存信息获取出错 直接将错误发送给请求端
            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        if (rc == NGX_OK) {       //缓存命中  直接发送
            rc = ngx_http_upstream_cache_send(r, u);

            if (rc == NGX_DONE) {  //头部处理出错
                return;
            }

            if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {  //无效头部判定 会回源
                rc = NGX_DECLINED;
                r->cached = 0;
                u->buffer.start = NULL;
                u->cache_status = NGX_HTTP_CACHE_MISS;
                u->request_sent = 1;
            }

            if (ngx_http_upstream_cache_background_update(r, u) != NGX_OK) {
                rc = NGX_ERROR;
            }
        }
    }

#endif

    u->store = u->conf->store;

    if (!u->store && !r->post_action && !u->conf->ignore_client_abort) { //开启上下游连接检测  
        r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
    }

    if (r->request_body) {      //存在http请求包体 包体信息存入request_bufs中
        u->request_bufs = r->request_body->bufs;
    }

    if (u->create_request(r) != NGX_OK) {       //创建请求干预过程出错 直接响应服务器内部错误到请求端
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }

    if (ngx_http_upstream_set_local(r, u, u->conf->local) != NGX_OK) {//本地upstream地址配置
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    u->output.alignment = clcf->directio_alignment;
    u->output.pool = r->pool;
    u->output.bufs.num = 1;
    u->output.bufs.size = clcf->client_body_buffer_size;

    if (u->output.output_filter == NULL) {
        u->output.output_filter = ngx_chain_writer;
        u->output.filter_ctx = &u->writer;
    }

    u->writer.pool = r->pool;
    //upstream状态信息初始化
    if (r->upstream_states == NULL) {
          ...
    } else {

       ...
    }

   ... //生命周期结束清理处理设置

    if (u->resolved == NULL) {  //还未开始解析

        uscf = u->conf->upstream;

    } else {

#if (NGX_HTTP_SSL)
        u->ssl_name = u->resolved->host;
#endif

        host = &u->resolved->host;

        umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

        uscfp = umcf->upstreams.elts;

        for (i = 0; i < umcf->upstreams.nelts; i++) {  //从配置的upstream地址信息中搜索(优先处理)

            uscf = uscfp[i];

            if (uscf->host.len == host->len
                && ((uscf->port == 0 && u->resolved->no_port)
                     || uscf->port == u->resolved->port)
                && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
            {
                goto found;
            }
        }

        if (u->resolved->sockaddr) {
                   ...  //已经解析地址信息检查
            if (ngx_http_upstream_create_round_robin_peer(r, u->resolved) //检查通过 创建轮询peer(根据返回的主机数量) 具有负载效果
                != NGX_OK)
            {
                ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
                return;
            }

            ngx_http_upstream_connect(r, u);     //连接至上游服务器

            return;
        }

        if (u->resolved->port == 0) {  //无效port返回服务器错误
            ...
            return;
        }

        temp.name = *host;

        ctx = ngx_resolve_start(clcf->resolver, &temp);  //开始域名解析  域名解析器由core_module配置 未配置对于非IP host处理会失败
        if (ctx == NULL) {
            ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        if (ctx == NGX_NO_RESOLVER) {  //未配置域名解析器  响应错误
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "no resolver defined to resolve %V", host);

            ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
            return;
        }

       ... //upstream域名解析器信息设置  解析完成会在ngx_http_upstream_resolve_handler中触发

        if (ngx_resolve_name(ctx) != NGX_OK) {   //域名解析出错 响应错误请求(注意 域名解析过程是异步的)
            u->resolved->ctx = NULL;
            ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        return;
    }

found:

    if (uscf == NULL) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "no upstream configuration");
        ngx_http_upstream_finalize_request(r, u,
                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }

    u->upstream = uscf;

#if (NGX_HTTP_SSL)
    u->ssl_name = uscf->host;
#endif

    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);     //连接到上游服务器
}

上游服务器连接ngx_http_upstream_connect处理

static void
ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
    ngx_int_t          rc;
    ngx_connection_t  *c;

    r->connection->log->action = "connecting to upstream";

    if (u->state && u->state->response_time) {
        u->state->response_time = ngx_current_msec - u->state->response_time; //更新uptream state响应时间
    }
    ...  //upstream state信息初始化
    rc = ngx_event_connect_peer(&u->peer);         //发起到上游服务器请求

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http upstream connect: %i", rc);

    if (rc == NGX_ERROR) {         //连接错误 将错误响应到请求端
        ngx_http_upstream_finalize_request(r, u,
                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }

    u->state->peer = u->peer.name;

    if (rc == NGX_BUSY) {              //来不及处理 尝试连接到另一个server (如果有)
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
        return;
    }

    if (rc == NGX_DECLINED) {           //连接被拒绝 尝试连接到另一个server (如果有)
        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
        return;
    }

    /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */

    c = u->peer.connection;

    c->data = r;
    //读写事件处理设置
    c->write->handler = ngx_http_upstream_handler;       
    c->read->handler = ngx_http_upstream_handler;

    u->write_event_handler = ngx_http_upstream_send_request_handler;
    u->read_event_handler = ngx_http_upstream_process_header;

    c->sendfile &= r->connection->sendfile;
    u->output.sendfile = c->sendfile;

    if (c->pool == NULL) {

        /* we need separate pool here to be able to cache SSL connections */

        c->pool = ngx_create_pool(128, r->connection->log);
        ...  //创建连接内存池
    }

    c->log = r->connection->log;
    c->pool->log = c->log;
    c->read->log = c->log;
    c->write->log = c->log;

    /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */

    u->writer.out = NULL;
    u->writer.last = &u->writer.out;
    u->writer.connection = c;
    u->writer.limit = 0;

    if (u->request_sent) {
        if (ngx_http_upstream_reinit(r, u) != NGX_OK) {   //重新初始化upstream 
            ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }
    }

    if (r->request_body
        && r->request_body->buf
        && r->request_body->temp_file
        && r == r->main)
    {   
        /*
         * the r->request_body->buf can be reused for one request only,
         * the subrequests should allocate their own temporary bufs
         */
        //请求包体buf循环利用 挂载到upstream 输出空闲buf中(对于将请求包体放入临时文件的请求)
        u->output.free = ngx_
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Nginxupstream配置用于定义后端服务器的地址及相关配置,可以实现负载均衡、缓存等功能。 具体来说,upstream配置需要在Nginx的配置文件中定义一个upstream块,该块中包含多个server指令,每个server指令对应一个后端服务器。可以为每个server指令指定服务器的IP地址、端口号、权重、健康检查等参数。Nginx会根据这些参数对请求进行负载均衡,将请求转发到后端服务器进行处理。 除了server指令,upstream块还可以包含一些其他指令,如zone指令用于定义一个共享内存区域,用于存储后端服务器的状态信息;keepalive指令用于控制与后端服务器的TCP连接复用等。 需要注意的是,upstream配置需要在Nginx的http块中定义,而不能在server块中定义。同时,在配置upstream时,需要考虑后端服务器的负载情况、网络环境等因素,进行合理的调整,以提高系统的性能和稳定性。 ### 回答2: Nginx是一种高性能、开源的HTTP和反向代理服务器。其中,“UPSTREAM”(上游)是Nginx中有机构成的一部分,在进行反向代理负载均衡时,它扮演着至关重要的角色。这文章将详细介绍如何在Nginx中配置UPSTREAMUPSTREAM是什么? UPSTREAM是指Nginx将需要处理的请求转发至一组上游服务器,例如Web服务器、应用服务器等。这些服务器负责为客户端提供所需的服务。UPSTREAM可以帮助用户实现反向代理负载均衡。 UPSTREAM的配置 UPSTREAM的配置具体流程如下: 1.编辑Nginx配置文件 在Nginx配置文件中添加UPSTREAM的相关内容。示例如下: ``` upstream backend{ server 10.0.0.1:8080; server 10.0.0.2:8080; } ``` 此处定义了一个名为backend的UPSTREAM,其中有两个服务器。这两个服务器需要提供相同服务的内容。Nginx会将客户端请求转发至这两个服务器的其中一个。 2.配置反向代理Nginx配置文件中添加反向代理配置。例如: ``` location / { proxy_pass http://backend; } ``` 此处定义了一个location(位置)块,将会匹配所有请求。Nginx会将这些请求反向代理至backend UPSTREAM中的某个服务器。如果有多个UPSTREAMNginx会根据负载均衡算法选择服务器。 3.配置负载均衡算法 Nginx支持多种负载均衡算法,如轮询、IP哈希等。默认情况下,Nginx使用轮询算法。例如: ``` upstream backend { ip_hash; server 10.0.0.1:8080; server 10.0.0.2:8080; } ``` 上面的配置中,Nginx使用IP哈希算法,即根据客户端的IP地址来确定要转发至哪个上游服务器。 4.启动Nginx 配置完成后,启动Nginx以使配置生效。在Linux系统中,使用如下命令: ``` sudo systemctl restart nginx ``` UPSTREAM的优势 使用UPSTREAM有许多优势: 1.实现高可用性 UPSTREAM能够实现多台服务器的负载均衡,避免单点故障,提高系统的可用性。 2.实现更好的性能 使用UPSTREAM能够将请求转发至最近的服务器,从而提高系统响应速度。 3.实现更好的安全性 UPSTREAM能够分发请求至多台服务器,从而减轻单个服务器的负担,降低被攻击的风险。 总结 UPSTREAMNginx的核心模块之一,在反向代理负载均衡中扮演着至关重要的角色。UPSTREAM配置简单、易用,能够提高系统的可用性、性能和安全性。 ### 回答3: Nginxupstream是一个用于反向代理模块,允许我们将客户端请求转发给多个服务器。可以用于负载均衡和容错,确保在某个服务器宕机或出现故障时能够自动切换到另一个服务器。 upstream配置可以定义一组后端服务器,并使用不同的负载均衡算法。以下是nginx upstream配置的详细解释: 1. 定义upstreamupstream块是nginx配置文件中的一个块,用于定义后端服务器的配置。upstream块的语法如下: upstream backend { server 192.168.1.100; server 192.168.1.101; } 在这个块中,我们指定了名为backend的upstream组,同时定义了两个服务器的IP地址。在实际使用中,我们可以在server关键字后跟主机名称或IP地址,然后在每个服务器的下一行添加可选端口号。 2. 配置负载均衡算法 在upstream块中,可以选择不同的负载均衡算法。其中最常使用的算法是轮询算法(默认算法),它将请求轮流分配给不同的后端服务器。还有其他算法可供选择,如随机、权重、IP hash等。以下是一个应用随机算法的例子: upstream backend { server 192.168.1.100; server 192.168.1.101; random; } 3. 配置代理协议 upstream块中,我们也可以指定代理协议。为了提高安全性和性能,我们可以在后端服务中使用HTTPS协议,同时配置Nginx充当HTTPS代理。这需要我们在upstream块中指定两个server,一个是HTTP的服务器,另一个是HTTPS的服务器。以下是一些示例代码: # 用于HTTP协议的upstream upstream backend { server 192.168.1.100; } # 用于HTTPS协议的upstream upstream backend { server 192.168.1.100:80; server 192.168.1.100:443 backup; } 在这个示例中,第一个server是HTTP服务器,第二个server是HTTPS服务器,用于负载均衡。backup关键字用于指定后备服务器。 4. 使用DNS解析 在上面的例子中,我们使用了硬编码的IP地址。但是,当使用DNS解析时,可以使我们更灵活地管理服务器。可以使用resolver指令来指定DNS服务器的IP地址,使用域名而不是IP地址来定义后端服务器。以下是一个dns解析的例子: resolver 8.8.8.8; upstream backend { server api.example.com; } 在这个例子中,我们使用Google DNS(IP地址是8.8.8.8)解析名为api.example.com的域名,而不需要写入硬编码的IP地址。 总结:upstream配置是Nginx反向代理的核心组件,可为后端服务器提供容错和负载均衡。通过nginxupstream配置,我们可以轻松地定义一组后端服务器,并选择不同的负载平衡算法。我们还可以使用代理协议和DNS解析来选择最佳的后端服务器,并提高服务的性能和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值