用c++写一个数据库连接池
数据库连接池是为了提高数据库连接的性能,进行连接复用
对于复杂数据库进行大量引用的场景下就会出现访问瓶颈
常见的两种解决方法就是:为了减少磁盘 I/O的次数,在数据库和服务器的应用中间加一层 缓存数据库(例如:Redis、Memcache);
或者就是增加连接池,来减少高并发情况下大量 TCP三次握手、MySQL Server连接认证、MySQL Server关闭连接回收资源和TCP四次挥手 所耗费的性能。
机制解读:
连接池呢就是为数据库连接建立一个缓冲池。
1:从连接池获取或创建可用连接
2:使用完毕之后,把连接返回给连接池
3:在系统关闭前,断开所有连接并释放连接占用的系统资源
4:能够处理无效连接,限制连接池中的连接总数不低于或者不超过某个限定值
池子里四个基本属性:
初始连接量(init_size): 表示连接池事先会和MySQL服务器创建init_size个connection连接,当应用发起MySQL访问时,不用再创建和MySQL服务器新的连接,直接从连接池中获取一个可用的连接就可以,使用完成后,并不去释放connection,而是把当前connection再归还到连接池当中。
最大连接(max_size): 当并发访问MySQL服务器的请求增多时,初始连接量已经不够使用了,此时会根据新的请求数量去创建更多的连接给应用去使用,但是新创建的连接数量上限是max_size,不能无限制的创建连接。因为每个连接都会占用一个socket资源,一般连接池和服务器程序是部署在一台主机上的,如果连接池占用过多的socket资源,那么服务器就不能接收更多的客户端请求了。当这些连接使用完成后,再次归还到连接池当中来维护。
最大空闲时间(max_idle_time): 当访问MySQL的并发请求多了以后,连接池里面的连接数量会动态增加,上限是max_size个,当这些连接用完再次归还到连接池当中。如果在指定的max_idle_time里面,这些新增加的连接都没有被再次使用过,那么新增加的这些连接资源就要被回收,只需要保持初始连接量init_size个连接就可以了。
连接超时时间(connection_timeout): 当MySQL的并发请求量过大,连接池中的连接数量已经到达max_size了,而此时没有空闲的连接可供使用,那么此时应用无法从连接池获取连接,它通过阻塞的方式等待获取连接的时间如果超过connection_timeout时间,那么连接失败,无法访问数据库。
技术点的分析:
通过预先创建一定数量的连接,放到一个池子。当客户端有请求时,服务器端需要与mysql进行交互,那么只需要从池子里取出一个连接,当操作完成再将连接放到连接池中。如此以来避免了频繁的创建和销毁线程。
1.池子只需要一个就够用了,一个池子里有很多连接了。所以对于线程池这个类而言使用单例模式最为合适。用c++11内部静态变量这种线程安全的方法做的
2.池子里面连接存在类似队列这种容器里面,直接用queue了,每次新的连接从队尾进去,队头的连接用完之后,如果空闲太久,占资源就需要把他销毁掉
3.进行数据库连接的话需要mysql相关的api,用c++的话,就把这些api封装一下,具体常用的api之前有写过一篇博客 C/C++链接mysql_
这封装成一个数据库连接类,里面就是伴随着数据库的初始化,查询,更新,事务的一系列操作。连接池里面队列放的就是这一个个数据库连接的类对象
4.需要访问数据库的线程从连接池里面取出连接,和给池子里添加新连接的线程构成了一个典型的生产者消费者,用条件变量加+互斥锁保证同步,cas原子操作 定义一个连接池内的连接数量,用来当做我们生产和消费线程工作都要参考的变量,变量必须保证其原子性
5.对于获取连接池中的连接来说,用户只需要关心使用,去连接池里直接获取连接并且使用即可,并不用关心连接的生成和销毁,并且,对于使用完的连接来说,为了达到复用的目的,我们并不希望把它释放掉,而是使用完之后将其放回到连接池中供其他消费者使用,这个我们就可以使用智能指针来完成用lambda表达式定制连接释放的功能,(把连接重新还给池子);重新放进连接池呢就是重新push到队列池子里,不过要更新一下时间戳,记录每个连接的存活时间
6.连接池实现自动管理连接数(不够时创建连接,销毁空闲时间较长的连接)
需要通过两个子线程,因为主线程不能阻塞在这个地方,所以通过两个子线程取完成,设置线程分离
一个子线程用来不够时自动创建连接:
线程池维护了两个数据,一个最小连接数,一个最大连接数
一个子线程用来销毁空闲时间较长的连接:
大概实现思路:从队头取出连接,并将该连接的空闲时长与设定的最大空闲时长比较,如果大于等于就从队列中弹出并销毁
7.利用Jsoncpp库去解析json文件,配置环境
整个流程原理大概就这样
当时做了四组压力测试:
一个线程去连接数据库每次插一条数据,测试5000下
用连接池省了和数据库建立连接的损耗
多线程的话,测了五个线程(好比五个用户)不断的去同时连接数据库,每次连接插入一条数据,一共插5000条
接上连接池,效率更高
测了5000条数据,能很明显的看到单线程多线程下使用连接池,访问速度有着明显的提高
总结:深入了解了池化的技术,可以和线程池配套,作为一个不错的项目
源码放在这了:Xw-oorik