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

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

池(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 );  

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

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2016-09-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

潜伏长达11年之久的Linux内核漏洞”Phoenix Talon”曝光

上月初,启明星辰ADLab提交了四个存在于Linux内核的远程漏洞,并命名为“Phoenix Talon”;其中一个漏洞为严重(Critical)级别,另外三个...

37280
来自专栏玄魂工作室

​ kali linux 渗透测试 之 DNS信息收集

从本节开始,我们从头开始,系统的学习基于Kali Linux的web应用渗透测试。

30630
来自专栏Vamei实验室

被解放的姜戈07 马不停蹄

前面的文章研究了Django最主要的几个方面:数据库,模板,动态生成页面等。但都是使用python manage.py runserver来运行服务器。这是一个...

201100
来自专栏Debian社区

通过 Hostapd 进行 WIFI 热点共享上网

最近发现自己的Debian之前可以使用GNOME3下的networkmanager进行WIFI共享上网功能因为内核升级导致无法使用。无奈只好再次通过Hostap...

1.1K20
来自专栏along的开发之旅

文加图, 理解Http请求与响应

在讲解OkHttp之前, 我们首先来个高清大图, 看下http请求的整个步骤, 有个整体概念.

11220
来自专栏F-Stack的专栏

全用户态网络开发套件F-Stack架构分析

F-Stack是一个全用户态(kernel bypass)的高性能的网络接入开发包,基于DPDK、FreeBSD协议栈、微线程接口等,适用于各种需要网络接入的业...

71190
来自专栏阮一峰的网络日志

DNS 原理入门

DNS 是互联网核心协议之一。不管是上网浏览,还是编程开发,都需要了解一点它的知识。 本文详细介绍DNS的原理,以及如何运用工具软件观察它的运作。我的目标是,读...

57080
来自专栏SDNLAB

OVN实战二之Overlay实现

前言 上一章介绍了GNS3的使用以及OVN系统的架构,搭建了实验环境,阐述了OVN各个进程的用途、彼此之间的关系,以及产生的日志(OVN实战一之GNS3操作指南...

401120
来自专栏北京马哥教育

原创投稿 | 防火墙及NAT服务

一、简介 1. 关于防火墙 防火墙,其实就是用于实现Linux下访问控制的功能的,它分为硬件和软件防火墙两种。无论是在哪个网络中,防火墙工作的地方一定是在网...

54590
来自专栏Java后端技术

解决Maven项目pom.xml文件报xxx\target\classes\META-INF\MANIFEST.MF (系统找不到指定的路径。)问题

最近自己在公司项目修改一些代码以后,出现如题的错误,后来各种Google等,最终找到了解决办法。

10510

扫码关注云+社区

领取腾讯云代金券