static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, ngx_uint_t state) { ngx_http_upstream_keepalive_peer_data_t *kp = data; ngx_http_upstream_keepalive_cache_t *item; ngx_queue_t *q; ngx_connection_t *c; ngx_http_upstream_t *u; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "free keepalive peer"); /* remember failed state - peer.free() may be called more than once */ if (state & NGX_PEER_FAILED) { kp->failed = 1; } /* cache valid connections */ u = kp->upstream; c = pc->connection; if (kp->failed || c == NULL || c->read->eof || c->read->error || c->read->timedout || c->write->error || c->write->timedout) { goto invalid; } if (!u->keepalive) { goto invalid; } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { goto invalid; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "free keepalive peer: saving connection %p", c); if (ngx_queue_empty(&kp->conf->free)) { q = ngx_queue_last(&kp->conf->cache); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); ngx_http_upstream_keepalive_close(item->connection); } else { q = ngx_queue_head(&kp->conf->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); } item->connection = c; ngx_queue_insert_head(&kp->conf->cache, q); pc->connection = NULL; if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } c->write->handler = ngx_http_upstream_keepalive_dummy_handler; c->read->handler = ngx_http_upstream_keepalive_close_handler; c->data = item; c->idle = 1; c->log = ngx_cycle->log; c->read->log = ngx_cycle->log; c->write->log = ngx_cycle->log; c->pool->log = ngx_cycle->log; item->socklen = pc->socklen; ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); if (c->read->ready) { ngx_http_upstream_keepalive_close_handler(c->read); } invalid: kp->original_free_peer(pc, kp->data, state); }
//ngx_http_upstream_free_keepalive_peer往kp->conf->cache中添加缓存ngx_connection_t,ngx_http_upstream_get_keepalive_peer从缓存中 //取出和后端的连接缓存ngx_connection_t,可以避免重复的建立和关闭TCP连接 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, ngx_uint_t state) { ngx_http_upstream_keepalive_peer_data_t *kp = data; ngx_http_upstream_keepalive_cache_t *item; ngx_queue_t *q; ngx_connection_t *c; ngx_http_upstream_t *u; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "free keepalive peer"); /* cache valid connections */ u = kp->upstream; c = pc->connection; if (state & NGX_PEER_FAILED || c == NULL || c->read->eof || c->read->error || c->read->timedout || c->write->error || c->write->timedout) { goto invalid; } if (!u->keepalive) { //说明本次和后端的连接使用的是缓存cache(keepalive配置)connection的TCP连接,也就是使用的是之前已经和后端建立好的TCP连接ngx_connection_t goto invalid; } //通常设置keepalive后连接都是由后端web服务发起的,因此需要添加读事件 if (ngx_handle_read_event(c->read, 0, NGX_FUNC_LINE) != NGX_OK) { goto invalid; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "free keepalive peer: saving connection %p", c); //如果free队列中可用cache items为空,则从cache队列取一个最近最少使用item, //将该item对应的那个连接关闭,该item用于保存当前需要释放的连接 if (ngx_queue_empty(&kp->conf->free)) { //free中已经没有节点信息了,因此把cache中最少使用的那个取出来,把该连接关闭,重新添加到cache q = ngx_queue_last(&kp->conf->cache); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); ngx_http_upstream_keepalive_close(item->connection); } else { //free队列不空则直接从队列头取一个item用于保存当前连接 q = ngx_queue_head(&kp->conf->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); } ngx_queue_insert_head(&kp->conf->cache, q); //缓存当前连接,将item插入cache队列,然后将pc->connection置空,防止上层调用 //ngx_http_upstream_finalize_request关闭该连接(详见该函数) item->connection = c; pc->connection = NULL; //关闭读写定时器,这样可以避免把后端服务器的tcp连接关闭掉 if (c->read->timer_set) { ngx_del_timer(c->read, NGX_FUNC_LINE); } if (c->write->timer_set) { ngx_del_timer(c->write, NGX_FUNC_LINE); } //设置连接读写钩子。写钩子是一个假钩子(keepalive连接不会由客户端主动关闭) //读钩子处理关闭keepalive连接的操作(接收到来自后端web服务器的FIN分节) c->write->handler = ngx_http_upstream_keepalive_dummy_handler; c->read->handler = ngx_http_upstream_keepalive_close_handler; c->data = item; c->idle = 1; c->log = ngx_cycle->log; c->read->log = ngx_cycle->log; c->write->log = ngx_cycle->log; c->pool->log = ngx_cycle->log; // 保存socket地址相关信息,后续就是通过查找相同的socket地址来复用该连接 item->socklen = pc->socklen; ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); if (c->read->ready) { ngx_http_upstream_keepalive_close_handler(c->read); } invalid: kp->original_free_peer(pc, kp->data, state); //指向原负载均衡算法对应的free }