高并发服务器-链接池的设计sql
高并发服务器须要有一些池的设计,如内存池,链接池,数据库链接池。数据库
池(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 0
-
- int 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 0
- tst_conn_t* tst_conn_get();
- int tst_conn_free( tst_conn_t* conn );
模块内部用一个全局的池,在模块内统一的管理。