nginx連線資源管理

atskyline發表於2019-07-21

本文介紹在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物件的來源。

相關文章