高并发服务器的设计--连接池的设计
时间:2022-05-05
本文章向大家介绍高并发服务器的设计--连接池的设计,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
高并发服务器需要有一些池的设计,如内存池,连接池,数据库连接池。
池(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 );
模块内部用一个全局的池,在模块内统一的管理。
- Python文学化编程 - Jupyter notebook使用和插件拓展
- PoisonCake(毒蛋糕):内置于手机ROM的恶意代码模块
- Spring+SpringMVC+MyBatis整合
- Python之numpy数组学习(五)——广播
- WordPress再悲剧:WPcache-Blogger感染事件影响五万WordPress网站
- 浅谈神经机器翻译
- 窃取Facebook用户信息:利用Android同源策略漏洞的恶意应用被发现
- 关于React Native 安卓首屏白屏优化
- 浅谈spring security 403机制一、无权限访问二、匿名访问三、有权限访问原因机制指定AccessDeniedHandler指定error-page情景原因结论
- Python之numpy数组学习(二)
- Intent 属性详解(上)
- 复仇行动:Notepad++官网被圣战组织黑了
- 四大组件的纽带——Intent
- 利用HTC One漏洞破解手机PIN密码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- android通过okhttpClient下载网页内容的实例代码
- Android自定义键盘的实现(数字键盘和字母键盘)
- Android iconify 使用详解
- XRecyclerView实现下拉刷新、滚动到底部加载更多等功能
- 浅析Android 快速实现图片压缩与上传功能
- Android处理时间各种方法汇总
- Android TextView Marquee的应用实例详解
- Android毛玻璃背景效果简单实现代码
- ClickHouse和他的朋友们(3)MySQL Protocol和Write调用栈
- ubuntu安装多个版本的CUDA并随时切换
- 如何在Ubuntu 18.04(实体机)上配置OpenWRT的开发环境
- Android 组合控件实现布局的复用的方法
- Android编程实现播放音频的方法示例
- 使用VSCode的Remote-SSH连接Linux进行远程开发
- Android ListView之EfficientAdapte的使用详解