博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高并发服务器-连接池的设计
阅读量:6298 次
发布时间:2019-06-22

本文共 2256 字,大约阅读时间需要 7 分钟。

hot3.png

高并发服务器-连接池的设计

高并发服务器需要有一些池的设计,如内存池,连接池,数据库连接池。

池(pool)的设计主要考虑到一些资源的频繁申请和释放,尤其是在高并发的服务器中,几万甚至几十万并发每秒,设计人员不得不去考虑这些。

比如数据库连接池(sql pool),是通过TCP来通信的,属于IO类,有一定的延时,在高并发系统中频繁的创建会严重影响系统性能。

内存( mem )的分配是要涉及锁( mutex )的,有锁就会有延时,因此可以在开始申请一大块内存,后面进行分配与释放,来节省锁开销。

服务器的连接处理不仅仅涉及内存,还涉及到一些属性的赋值,这些是要占用CPU时间的,如果在一开始就创建大量的连接,就方便以后复用了。

下面我以数据库连接池为例,先定义连接的结构:

  1. typedef struct tst_sql_s tst_sql_t;  
  2. struct tst_sql_s{  
  3.     MYSQL     *sql;  
  4.     tst_sql_t   *next;  
  5.     tst_sql_t   *prev;  
  6. };  

现实开发中,我发现有些喜欢用( free-busi ) 模式来设计池。

  1. struct  tst_sql_pool_s  
  2. {  
  3.     tst_sql_t *free_sql;  
  4.     tst_sql_t *busi_sql;  
  5.     …  
  6. };  

将池中的连接分成两个部分,一部分是空闲的(free),一部分是正在用的(busi),相函数函数:

  1. tst_sql_t* tst_sql_pool_get( tst_sql_pool_t* pool )  
  2. {  
  3.     tst_sql_t *sql;  
  4.     if( !pool ){  
  5.         return 0;  
  6.     }  
  7.       
  8.     sql = pool->free_sql;  
  9.       
  10.     if( !sql ){  
  11.         return 0;  
  12.     }  
  13.   
  14.     pool->free_sql = sql->next;  
  15.     sql->next = pool->busi_sql;  
  16.     sql->prev = 0;  
  17.     if( pool->busi_sql ){  
  18.         pool->busi_sql->prev = sql;  
  19.     }  
  20.     pool->busi_sql = sql;  
  21.       
  22.     return sql;  
  23. }  
  24.   
  25. int tst_sql_pool_put( tst_sql_pool_t* pool, tst_sql_t* sql )  
  26. {  
  27.     if( !pool || !sql ){  
  28.         return 0;  
  29.     }  
  30.   
  31.     if( sql->prev ){  
  32.         sql->prev->next = sql->next;  
  33.     }  
  34.     else{  
  35.         pool->busi_sql = sql->next;  
  36.     }  
  37.   
  38.     if( sql->next ){  
  39.         sql->next->prev = sql->prev;  
  40.     }  
  41.   
  42.     sql->next = pool->free_sql;  
  43.     pool->free_sql = sql;  
  44.       
  45.     return 0;  
  46. }  

 

 

基本就完成了池的管理了,但是我们也可以看出来这个判断其实很麻烦,有没有不用这么麻烦的呢。

从上面的函数也可以看出,麻烦主要在 busi 池上,free池的处理其实挺简单的,于是就有了下面的设计:

连接池只存放空闲连接,不在保存连接的状态,而应该把状态的分别交给管理函数。

下面我们以连接池举例

我重新设计了连接池的结构:

  1. typedef struct tst_conn_s tst_conn_t;  
  2. typedef struct tst_conn_pool_s tst_conn_pool_t;  
  3. struct tst_conn_s  
  4. {  
  5.     int  fd;  
  6.     ……..  
  7.     ……..  
  8.     tst_conn_t* next;  
  9. };  
  10.   
  11. struct tst_conn_pool_s  
  12. {  
  13.     ………  
  14.     ……….  
  15.     tst_conn_t*  conns;  
  16. };  

 

池的管理函数:

  1. tst_conn_t* tst_conn_pool_get( tst_conn_pool_t* pool )  
  2. {  
  3.     tst_conn_t* conn;  
  4.   
  5.     if( !pool ){  
  6.         return 0;  
  7.     }  
  8.   
  9.     conn = pool->conns;  
  10.     if( !conn ){  
  11.         return 0;  
  12.     }  
  13.   
  14.     pool->conns = conn->next;  
  15.       
  16.     return conn;  
  17.   
  18. }  
  19. #define TST_CONN_POOL_ERROR -1  
  20. #define TST_CONN_POOL_OK 0  
  21.   
  22. int tst_conn_pool_put( tst_conn_pool_t* pool, tst_conn_t* conn )  
  23. {  
  24.     if( !pool || !conn ){  
  25.         return TST_CONN_POOL_ERROR;  
  26.     }  
  27.   
  28.     conn->next = pool->conns;  
  29.     pool->conns = conn;  
  30.       
  31.     return TST_CONN_POOL_OK;  
  32. }     

 

 

 

这样,就起到了连接池的分配与回收的功能。

一般在设计上提高模块的透明性和降低耦合,我会把池的管理放在模块内部,对外只提供一致性接口:

  1. #define TST_CONN_POOL_ERROR -1  
  2. #define TST_CONN_POOL_OK 0  
  3. tst_conn_t* tst_conn_get();  
  4. int tst_conn_free( tst_conn_t* conn );  

模块内部用一个全局的池,在模块内统一的管理。 

转载于:https://my.oschina.net/u/3346994/blog/868981

你可能感兴趣的文章
使sqoop能够启用压缩的一些配置
查看>>
PostgreSQL可视化客户端工具
查看>>
PythonOCC 3D图形库学习—导入STEP模型
查看>>
【机器学习】逻辑回归(Logistic Regression)
查看>>
C# Dictionary.Add(key,"123") 与 Dictionary[key]="123"的区别
查看>>
cocos2dx 学习代码记录
查看>>
从句分析
查看>>
《Cisco路由器配置与管理完全手册》(第二版)前言和目录
查看>>
解答网友shell问题一例20140702
查看>>
use telnet auto reboot TP-Link route
查看>>
xcode 各版本下载地址及其它工具下载地址
查看>>
MVC 自定义AuthorizeAttribute实现权限管理
查看>>
内存溢出导致jenkins自动部署到tomcat失败
查看>>
Python之zip
查看>>
try catch finally
查看>>
UOJ #148. 【NOIP2015】跳石头 二分
查看>>
lintcode 中等题:和大于S的最小子数组
查看>>
用于重新编译的工具和命令
查看>>
pthread_create()之前的属性设置
查看>>
composer使用
查看>>