高並發伺服器需要有一些池的設計,如記憶體池,串連池,資料庫連接池。
池(pool)的設計主要考慮到一些資源的頻繁申請和釋放,尤其是在高並發的伺服器中,幾萬甚至幾十萬並發每秒,設計人員不得不去考慮這些。
比如資料庫連接池(sql pool),是通過TCP來通訊的,屬於IO類,有一定的延時,在高並發系統中頻繁的建立會嚴重影響系統效能。
記憶體( mem )的分配是要涉及鎖( mutex )的,有鎖就會有延時,因此可以在開始申請一大塊記憶體,後面進行分配與釋放,來節省鎖開銷。
伺服器的串連處理不僅僅涉及記憶體,還涉及到一些屬性的賦值,這些是要佔用CPU時間的,如果在一開始就建立大量的串連,就方便以後複用了。
下面我以資料庫連接池為例,先定義串連的結構:
typedef struct tst_sql_s tst_sql_t;struct tst_sql_s{MYSQL *sql;tst_sql_t *next;tst_sql_t *prev;};
現實開發中,我發現有些喜歡用( free-busi ) 模式來設計池。
struct tst_sql_pool_s{tst_sql_t *free_sql;tst_sql_t *busi_sql;…};
將池中的串連分成兩個部分,一部分是閒置(free),一部分是正在用的(busi),相函數函數:
tst_sql_t* tst_sql_pool_get( tst_sql_pool_t* pool ){tst_sql_t *sql;if( !pool ){return 0;}sql = pool->free_sql;if( !sql ){return 0;}pool->free_sql = sql->next;sql->next = pool->busi_sql;sql->prev = 0;if( pool->busi_sql ){pool->busi_sql->prev = sql;}pool->busi_sql = sql;return sql;}int tst_sql_pool_put( tst_sql_pool_t* pool, tst_sql_t* sql ){if( !pool || !sql ){return 0;}if( sql->prev ){sql->prev->next = sql->next;}else{pool->busi_sql = sql->next;}if( sql->next ){sql->next->prev = sql->prev;}sql->next = pool->free_sql;pool->free_sql = sql;return 0;}
基本就完成了池的管理了,但是我們也可以看出來這個判斷其實很麻煩,有沒有不用這麼麻煩的呢。
從上面的函數也可以看出,麻煩主要在 busi 池上,free池的處理其實挺簡單的,於是就有了下面的設計:
串連池只存放空閑串連,不在儲存串連的狀態,而應該把狀態的分別交給管理函數。
下面我們以串連池舉例
我重新設計了串連池的結構:
typedef struct tst_conn_s tst_conn_t;typedef struct tst_conn_pool_s tst_conn_pool_t;struct tst_conn_s{int fd;……..……..tst_conn_t* next;};struct tst_conn_pool_s{……………….tst_conn_t* conns;};
池的管理函數:
tst_conn_t* tst_conn_pool_get( tst_conn_pool_t* pool ){tst_conn_t* conn;if( !pool ){return 0;}conn = pool->conns;if( !conn ){return 0;}pool->conns = conn->next;return conn;}#define TST_CONN_POOL_ERROR -1#define TST_CONN_POOL_OK 0int tst_conn_pool_put( tst_conn_pool_t* pool, tst_conn_t* conn ){if( !pool || !conn ){return TST_CONN_POOL_ERROR;}conn->next = pool->conns;pool->conns = conn;return TST_CONN_POOL_OK;}
這樣,就起到了串連池的分配與回收的功能。
一般在設計上提高模組的透明性和降低耦合,我會把池的管理放在模組內部,對外只提供一致性介面:
#define TST_CONN_POOL_ERROR -1#define TST_CONN_POOL_OK 0tst_conn_t* tst_conn_get();int tst_conn_free( tst_conn_t* conn );
模組內部用一個全域的池,在模組內統一的管理。