【58沈剑架构系列】一分钟写好连接池

一、如何通过连接访问下游

工程架构中有很多访问下游的需求,下游包括但不限于服务/数据库/缓存,其通讯步骤是为:

(1)与下游建立一个连接

(2)通过这个连接,收发请求

(3)交互结束,关闭连接,释放资源

这个连接是什么呢,通过连接怎么调用下游接口?服务/数据库/缓存,官方会提供不同语言的Driver、Document、DemoCode来教使用方建立连接与调用接口,以MongoDB的C++官方Driver API为例(伪代码):

DBClientConnection* c = new DBClientConnection();

c->connect(“127.0.0.1:8888”);

c->insert(“db.s”, BSON(”shenjian”));

c->close();


这个DBClientConnection就是一个与MongoDB的连接,官方Driver通过它提供了若干API,让用户可以对MongoDB进行连接,增删查改,关闭的操作,从而实现不同的业务逻辑。

二、为什么需要连接池

当并发量很低的时候,上述伪代码没有任何问题,但当服务单机QPS达到几百、几千的时候,建立连接connect和销毁连接close就会成为瓶颈,此时该如何优化?

结论也很简单,服务启动的时候,先建立好若干连接Array[DBClientConnection],当有请求过来的时候,从Array中取出一个,执行下游操作,执行完再放回,从而避免反复的建立和销毁连接,以提升性能。

这个对Array[DBClientConnection]进行维护的数据结构,就是连接池。有了连接池之后,数据库操作的伪代码变为:

DBClientConnection* c = ConnectionPool::GetConnection();

c->insert(“db.s”, BSON(”shenjian”));

ConnectionPool::FreeConnection(c);

三、连接池核心接口与实现

通过上面的讨论,可以看到连接池ConnectionPool主要有三个核心接口:

(1)Init:初始化好Array[DBClientConnection],这个接口只在服务启动时调用一次

(2)GetConnection:请求每次需要访问数据库时,不是connect一个连接,而是通过连接池的这个接口来拿

(3)FreeConnection:请求每次访问完数据库时,不是close一个连接,而是把这个连接放回连接池

连接池核心数据结构:

(1)连接数组Array DBClientConnection [N]

(2)互斥锁数组Array lock[N]

连接池核心接口实现:

Init(){

for i = 1 to N {

Array DBClientConnection [i] = new();

Array DBClientConnection [i]->connect();

Array lock[i] = 0;

}

}

说明:把所有连接和互斥锁初始化

GetConnection()

for i = 1 to N {

if(Array lock[i] == 0){

Array lock[i] = 1;

return Array DBClientConnection[i];

}

}

}

说明:找一个可用的连接,锁住,并返回连接

FreeConnection(c)

for i = 1 to N {

if(Array DBClientConnection [i] == c){

Array lock[i] = 0;

}

}

}

说明:找到连接,把锁释放


可以发现,简单的连接池管理并不是很复杂,基本原理即如上所述。

四、未尽事宜

上述伪代码忽略了一些细节,在实现连接池中是需要考虑的:

(1)如果连接全部被占用,是返回失败,还是让上游等待

(2)需要实施连接可用性检测

(3)为了让调用方更友好,可能还需要包装一层DAO层,让“连接”这个东西对调用方都是黑盒的

(4)通过freeArray,connectionMap可以让取连接和放回连接都达到O(1)时间复杂度

(5)可以通过hash实现id串行化

(6)负载均衡、故障转移、服务自动扩容都可以在这一层实现

希望这一分钟大家有收获。

【文章转载自微信公众号“架构师之路”】

时间: 2024-10-03 17:46:39

【58沈剑架构系列】一分钟写好连接池的相关文章

【58沈剑架构系列】一分钟了解负载均衡的一切

什么是负载均衡 负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据[均匀]分摊到多个操作单元上执行,负载均衡的关键在于[均匀]. 常见的负载均衡方案 常见互联网分布式架构如上,分为客户端层.反向代理nginx层.站点层.服务层.数据层.可以看到,每一个下游都有多个上游调用,只需要做到,每一个上游都均匀访问每一个下游,就能实现“将请求/数据[均匀]分摊到多个操作单元上执行”. [客户端层->反向代理层]的负载均衡 [客户端层]到[反向代理层]的负

【58沈剑架构系列】如何实施异构服务器的负载均衡及过载保护?

零.需求缘起 第一篇文章“一分钟了解负载均衡”和大家share了互联网架构中反向代理层.站点层.服务层.数据层的常用负载均衡方法. 第二篇文章“lvs为何不能完全代替DNS轮询”和大家share了互联网接入层负载均衡需要解决的问题及架构演进. 在这两篇文章中,都强调了“负载均衡是指,将请求/数据[均匀]分摊到多个操作单元上执行,负载均衡的关键在于[均匀]”. 然而,后端的service有可能部署在硬件条件不同的服务器上: 1)如果对标最低配的服务器“均匀”分摊负载,高配的服务器的利用率不足: 2

【58沈剑架构系列】缓存与数据库一致性保证

本文主要讨论这么几个问题: (1)啥时候数据库和缓存中的数据会不一致 (2)不一致优化思路 (3)如何保证数据库与缓存的一致性 一.需求缘起 上一篇<缓存架构设计细节二三事>(点击查看)引起了广泛的讨论,其中有一个结论:当数据发生变化时,“先淘汰缓存,再修改数据库”这个点是大家讨论的最多的. 上篇文章得出这个结论的依据是,由于操作缓存与操作数据库不是原子的,非常有可能出现执行失败. 假设先写数据库,再淘汰缓存:第一步写数据库操作成功,第二步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧

【58沈剑架构系列】秒杀系统架构优化思路

一.秒杀业务为什么难做 1)im系统,例如qq或者微博,每个人都读自己的数据(好友列表.群列表.个人信息): 2)微博系统,每个人读你关注的人的数据,一个人读多个人的数据: 3)秒杀系统,库存只有一份,所有人会在集中的时间读和写这些数据,多个人读一个数据. 例如:小米手机每周二的秒杀,可能手机只有1万部,但瞬时进入的流量可能是几百几千万. 又例如:12306抢票,票是有限的,库存一份,瞬时流量非常多,都读相同的库存.读写冲突,锁非常严重,这是秒杀业务难的地方.那我们怎么优化秒杀业务的架构呢? 二

【58沈剑架构系列】lvs为何不能完全替代DNS轮询

上一篇文章“一分钟了解负载均衡的一切”引起了不少同学的关注,评论中大家争论的比较多的一个技术点是接入层负载均衡技术,部分同学持这样的观点: 1)nginx前端加入lvs和keepalived可以替代“DNS轮询” 2)F5能搞定接入层高可用.扩展性.负载均衡,可以替代“DNS轮询” “DNS轮询”究竟是不是过时的技术,是不是可以被其他方案替代,接入层架构技术演进,是本文将要细致讨论的内容. 一.问题域 nginx.lvs.keepalived.f5.DNS轮询,每每提到这些技术,往往讨论的是接入

【58沈剑架构系列】互联网架构,如何进行容量设计?

一,需求缘起 互联网公司,这样的场景是否似曾相识: 场景一:pm要做一个很大的运营活动,技术老大杀过来,问了两个问题: (1)机器能抗住么? (2)如果扛不住,需要加多少台机器? 场景二:系统设计阶段,技术老大杀过来,又问了两个问题: (1)数据库需要分库么? (2)如果需要分库,需要分几个库? 技术上来说,这些都是系统容量预估的问题,容量设计是架构师必备的技能之一.常见的容量评估包括数据量.并发量.带宽.CPU/MEM/DISK等,今天分享的内容,就以[并发量]为例,看看如何回答好这两个问题.

【58沈剑架构系列】线程数究竟设多少合理

一.需求缘起 Web-Server通常有个配置,最大工作线程数,后端服务一般也有个配置,工作线程池的线程数量,这个线程数的配置不同的业务架构师有不同的经验值,有些业务设置为CPU核数的2倍,有些业务设置为CPU核数的8倍,有些业务设置为CPU核数的32倍. “工作线程数”的设置依据是什么,到底设置为多少能够最大化CPU性能,是本文要讨论的问题. 二.一些共性认知 在进行进一步深入讨论之前,先以提问的方式就一些共性认知达成一致. 提问:工作线程数是不是设置的越大越好? 回答:肯定不是的 1)一来服

【58沈剑架构系列】缓存架构设计细节二三事

本文主要讨论这么几个问题: (1)“缓存与数据库”需求缘起 (2)“淘汰缓存”还是“更新缓存” (3)缓存和数据库的操作时序 (4)缓存和数据库架构简析   一.需求缘起 场景介绍 缓存是一种提高系统读性能的常见技术,对于读多写少的应用场景,我们经常使用缓存来进行优化. 例如对于用户的余额信息表account(uid, money),业务上的需求是: (1)查询用户的余额,SELECT money FROM account WHERE uid=XXX,占99%的请求 (2)更改用户余额,UPDA

【58沈剑架构系列】细聊冗余表数据一致性

本文主要讨论四个问题: (1)为什么会有冗余表的需求 (2)如何实现冗余表 (3)正反冗余表谁先执行 (4)冗余表如何保证数据的一致性   一.需求缘起 互联网很多业务场景的数据量很大,此时数据库架构要进行水平切分,水平切分会有一个patition key,通过patition key的查询能够直接定位到库,但是非patition key上的查询可能就需要扫描多个库了. 例如订单表,业务上对用户和商家都有订单查询需求: Order(oid, info_detail) T(buyer_id, se