nginx提供了兩種全異步方式來與第三方服務通訊,分別是upstream和subrequest。nginx
upstream:nginx爲代理服務器,做消息透傳。將第三方服務的內容原封不動的返回給用戶。服務器
subrequest:爲客戶請求建立子請求。訪問第三方服務只是爲了獲取某些信息,再根據這些信息構造響應返回給用戶。cookie
ngx_http_request_t中有一個ngx_http_upstream_t類型的成員upstream框架
struct ngx_http_request_s { ... ngx_http_upstream_t *upstream;
... }
nginx模塊啓動upstream機制的示意圖異步
upstream執行的通常流程以下:ui
ngx_http_upstream_t結構體以下,重點關注已經寫好註釋的幾個成員:
struct ngx_http_upstream_s { ngx_http_upstream_handler_pt read_event_handler; ngx_http_upstream_handler_pt write_event_handler; ngx_peer_connection_t peer; ngx_event_pipe_t *pipe; //決定發送什麼樣的請求給上游服務器 ngx_chain_t *request_bufs; ngx_output_chain_ctx_t output; ngx_chain_writer_ctx_t writer; //upstream訪問時的限制性參數 ngx_http_upstream_conf_t *conf; ngx_http_upstream_headers_in_t headers_in; //指定上游服務器地址 ngx_http_upstream_resolved_t *resolved; //存儲上游服務器發來的響應 ngx_buf_t buffer; off_t length; ngx_chain_t *out_bufs; ngx_chain_t *busy_bufs; ngx_chain_t *free_bufs; ngx_int_t (*input_filter_init)(void *data); ngx_int_t (*input_filter)(void *data, ssize_t bytes); void *input_filter_ctx; #if (NGX_HTTP_CACHE) ngx_int_t (*create_key)(ngx_http_request_t *r); #endif //構造發往上游服務器的請求 ngx_int_t (*create_request)(ngx_http_request_t *r); ngx_int_t (*reinit_request)(ngx_http_request_t *r); //收到上游服務器響應後的回調方法 ngx_int_t (*process_header)(ngx_http_request_t *r); void (*abort_request)(ngx_http_request_t *r); //銷燬upstream請求時調用 void (*finalize_request)(ngx_http_request_t *r, ngx_int_t rc); ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix); ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r, ngx_table_elt_t *h); ngx_msec_t timeout; ngx_http_upstream_state_t *state; ngx_str_t method; ngx_str_t schema; ngx_str_t uri; ngx_http_cleanup_pt *cleanup; unsigned store:1; unsigned cacheable:1; unsigned accel:1; unsigned ssl:1; #if (NGX_HTTP_CACHE) unsigned cache_status:3; #endif //向客戶端轉發上游服務器包體時纔有用,buffering=1表示使用多個緩衝區及磁盤文件轉發上游包體,buffering=0表示只使用緩衝區buffer轉發數據 unsigned buffering:1; unsigned keepalive:1; unsigned request_sent:1; unsigned header_sent:1; };
upstream有3種方式處理上游的包體,這由ngx_http_request_t中的subrequest_in_memory決定:
(1)subrequest_in_memory=1,upstream不轉發響應包體,由input_filter方法處理
(2)subrequest_in_memory=0,buffering=1 以多個緩衝區和磁盤文件轉發包體
(3)subrequest_in_memory=0,buffering=0 以固定的大小的緩衝區轉發包體
upstream限制性參數ngx_http_upstream_conf_t,其中3個超時時間是必須設置的,以下:spa
typedef struct { ...//鏈接上游服務器的超時時間 ngx_msec_t connect_timeout; //發送TCP包到上游服務器的超時時間 ngx_msec_t send_timeout; //接收TCP包到上游服務器的超時時間 ngx_msec_t read_timeout;
... }ngx_http_upstream_conf_t
第三方服務器地址設置3d
typedef struct { ngx_str_t host; in_port_t port; ngx_uint_t no_port; /* unsigned no_port:1 */ //地址個數 ngx_uint_t naddrs; in_addr_t *addrs; //地址 struct sockaddr *sockaddr; socklen_t socklen; ngx_resolver_ctx_t *ctx; } ngx_http_upstream_resolved_t;
設置回調方法代理
包括3個必須實現的回調方法code
ngx_int_t (*create_request)(ngx_http_request_t *r); ngx_int_t (*process_header)(ngx_http_request_t *r); void (*finalize_request)(ngx_http_request_t *r, ngx_int_t rc);
5個可選的回調方法
ngx_int_t (*input_filter_init)(void *data); ngx_int_t (*input_filter)(void *data, ssize_t bytes); ngx_int_t (*reinit_request)(ngx_http_request_t *r); void (*abort_request)(ngx_http_request_t *r); ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix);
啓動upstream機制
直接執行ngx_http_upstream_init便可啓動upstream機制,例如:
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) { ... r->main->count++; ngx_http_upstream_init(r); return NGX_DONE; }
經過返回NGX_DONE讓HTTP框架停在執行請求的下一個階段。這裏執行r->main->count++是在告訴HTTP框架將當前請求的引用計數加1,暫時不要銷燬該請求。
回調方法執行場景時序圖以下:
reinit_request回調方法
reinit_request被回調的緣由只有1個:向上遊服務器創建TCP鏈接失敗,根據conf中的參數再次重連上游服務器,而這時就會調用reinit_request方法。
finalize_request回調方法
使用ngx_http_upstream_init啓動upstream機制後,在各類緣由致使該請求被銷燬前,都會調用finalize_request中的方法。此方法必須實現。
process_header回調方法
用於解析上游服務器返回的基於HTTP的響應頭部的,若是process_header返回NGX_AGAIN,意味着還沒收到完整的頭部,下次仍會調用process_header;若是返回NGX_OK,process_header不會再次調用
input_filter_init和input_filter回調方法
都用於處理上游服務器的響應包體,由於處理響應包體前可能須要作一些初始化工做,能夠放在input_filter_init中。input_filter用於實際處理包體。如下場景比較適合從新實現input_filter_init和input_filter回調方法
(1)轉發上游響應到下游時,須要作一些特殊處理
(2)無須在上、下游之間轉發響應時,並不想徹底接受到響應包體後纔開始處理,但願能接受一部分就處理一部分,而後釋放部份內存。