本文介紹在nginx中連線資源(即ngx_connection_t)的管理與使用。
連線池的初始化
在ngx_cycle_t結構體中維護了幾個和連線相關的資料,具體如下
struct ngx_cycle_s {
....
ngx_connection_t *free_connections;
ngx_uint_t free_connection_n;
ngx_uint_t connection_n;
ngx_connection_t *connections;
ngx_event_t *read_events;
ngx_event_t *write_events;
}
逐一說明一下
- connection_n表示最大的連線數量,通過配置項worker_connections設定
- connections、read_events、write_events都是陣列,陣列大小為connection_n,且下標都是一一對應,例如connections[i]、read_events[i]、write_events[i]一定是配套使用的一組。connections[i].read = read_events[i],connections[i].write=write_events[i]也始終是成立的。
- free_connections是一個連結串列的頭部,表示空閒的連結,free_connection_n表示空閒連線的數量。
- 空閒的連結串列通過c[i].data當作next指標逐一串聯
- 利用一個free鏈管理一個資源池的方式與filter中的ngx_output_chain_ctx_t.free類似
- 上述相關資源的初始化都發生在ngx_event_process_init()函式中,即在worker程式初始化時完成。
關於free鏈結構可以參考ngx_event_process_init()中的程式碼
c = cycle->connections;
i = cycle->connection_n;
next = NULL;
do {
i--;
c[i].data = next;
c[i].read = &cycle->read_events[i];
c[i].write = &cycle->write_events[i];
c[i].fd = (ngx_socket_t) -1;
next = &c[i];
} while (i);
cycle->free_connections = next;
cycle->free_connection_n = cycle->connection_n;
連線的申請與釋放
連線的申請與釋放就是對cycle->free_connections的操作,相關的函式有2個ngx_get_connection()與ngx_free_connection().核心的邏輯可以參考程式碼
ngx_connection_t *
ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
{
...
c = ngx_cycle->free_connections;
ngx_cycle->free_connections = c->data;
ngx_cycle->free_connection_n--;
...
}
void
ngx_free_connection(ngx_connection_t *c)
{
c->data = ngx_cycle->free_connections;
ngx_cycle->free_connections = c;
ngx_cycle->free_connection_n++;
...
}
連線的典型場景
通過檢視ngx_get_connection()與的引用,可以看到連線的主要使用場景
- 場景一:作為監聽fd的管理,在ngx_event_process_init()函式中會為cycle->listening中的每個監聽繫結一個connection物件,並把connection物件的read事件處理函式設定為ngx_event_accept。
- 場景二:accept連線後的管理,在ngx_event_accept()中,在accept獲得新連線後會通過connection進行管理,也是業務開發中reqeust->connection物件的來源。
- 場景三:當nginx需要作為客戶端發起請求時,呼叫ngx_event_connect_peer()函式,也會從連線池中申請資源,這個也是upstream->peer.connection物件的來源。