现在你的直觉里浮现这么个情景:upstream是nginx的一个神秘机制,它让nginx可以连接后端的某台服务器。不管后端有多少台服务器,它总能根据你指定的策略挑出其中一台,连接它、发送请求数据、得到后端服务器的响应,最后再响应给客户端。如果这个描述让你清楚upstream替nginx做了什么,我们将深度探索它的实现。不用担心它将比你想象中的简单很多。
nginx中如何使用upstream,配置如下:
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
server backup2.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会绑定到具体的某个upstream,以便nginx处理请求时找到usptream里的某个服务器。这里有个很重要的细节,如果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; };
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; };