数据库连接的分配和回收方法
技术领域
本发明涉及数据库连接的分配和回收方法。
背景技术
随着互联网的不断发展,互联网上的数据量急剧增长,传统单机数据库在处理大规模数据时已经面临明显的瓶颈,各大互联网公司都着手研究分布式数据库的实现方案。
在分布式数据库的实现方案中,包括如下两类:一类是客户端的解决方案,引入一个新的客户端,对数据进行分片处理;另一类是引入数据库中间件,对数据的分片处理由该中间件完成,应用程序只需要访问该数据库中间件即可,整个访问过程和访问原生的数据库几乎一样。
在数据库中间件的解决方案中,针对MySQL的中间件的解决方案相对来说比较多,在实现MySQL中间件的时候需要解决的一个非常重要的一点就是中间件对MySQL连接的管理问题,即连接池的设计与实现。
一般在解决中间件与MySQL实例的连接问题的解决方案主要有两种:
以数据库为单位,每个数据库建立一个连接池;
以MySQL实例为单位,一个MySQL实例上可能有多个数据库,彼此之间共享所有的连接。
以数据库为单位建立连接池的方式存在的不足是:一个MySQL实例本身能承受的连接总数是有限的,且同一个MySQL实例上往往有多个数据库,而各个数据库的访问量一般来说是不一样的,有些数据库可能访问量较大有些数据库可能访问量很小甚至长时间不被访问,在以数据库为单位建立连接池的时候很难预先准确分配各个数据库的连接数。因为不能准确的以数据库分配连接数,导致的问题就是某些数据库对应的连接池经常长期空闲却又消耗MySQL实例上的连接资源,而有些数据库对应的连接池资源紧张却又无法将其他数据库对应的连接池中的空闲连接资源利用起来,同时因为数据库为单位分配连接对MySQL实例上的连接总数的控制也不方便,简单的说就是连接资源利用不充分。
传统的以MySQL实例为单位建立连接池的方式存在的不足:一个MySQL实例上可能存在多个数据库,而通过中间件访问MySQL的时候,可能随机访问其中的一些数据库,所以某些连接可能刚访问了数据库A,返回给连接池以后又从连接池中拿出来去访问数据库B,为了保证访问的正确性,每次访问之前都需要确认某个连接和某个数据库是对应的,也就是说需要在进行SQL操作之前进行一次use db的操作,该操作会保证该连接和对应的数据库关联上,而该操作会增加一次中间件到MySQL实例之间的网络IO,从而导致访问性能下降。
发明内容
本发明的目的是解决中间件方案的连接池实现方法里存在的问题,即MySQL连接资源利用不充分及访问性能降低的问题。
根据本发明的一个方面,提供一种利用数据库连接池分配连接的方法,所述数据库连接池包括全局连接池和逻辑连接池,所述全局连接池包括全局队列,所述逻辑连接池包括各数据库对应的队列,所述方法包括步骤:接收连接请求,该连接请求包含对应数据库的数据库名;当所述逻辑连接池中存在该数据库对应的队列并且该队列非空,则从该队列中取得一个连接,并同时将该连接从该队列中和全局队列中移除,并且返回该连接;当所述逻辑连接池中不存在该数据库对应的队列或者尽管存在但该队列为空,则确定所述全局队列是否为空;当所述全局队列非空,则取出所述全局队列的尾部的连接,建立并保存该连接与所述数据库的对应关系,并且返回该连接,其中当存在该连接与其他数据库的对应关系时,解除该连接与该其他数据库的对应关系;当所述全局队列为空,则判定当前活动连接数是否大于预定的阈值;当活动连接数不大于预定的阈值,则创建新的连接,建立并保存该连接与所述数据库的对应关系,并且返回该连接;当活动连接数大于预定的阈值,则发出连接数报警。
根据本发明上述方面的一个优选的方式,该方法还包括如下步骤:确定是否有弹性连接额度,当有弹性连接额度可使用,则创建新的连接,建立并保存该连接与所述数据库的对应关系,并且返回该连接;当没有弹性连接额度,则返回获取连接失败的异常消息。
根据本发明的又一方面,提供一种利用数据库连接池回收连接的方法,所述数据库连接池包括全局连接池和逻辑连接池,所述全局连接池包括全局队列,所述逻辑连接池包括各数据库对应的队列,所述方法包括步骤:接收释放给所述数据库连接池的连接,并获取该连接对应的数据库的信息;确定连接池连接总数是否已经达到预定连接数阈值;当所述连接池连接数大于等于所述连接数阈值,则关闭该连接;当所述连接池连接数小于所述连接数阈值并且所述逻辑连接池中存在该连接对应的数据库的队列,则把该连接置于该数据库的队列的尾部,并且把该连接置于所述全局队列的头部;当当前连接池连接数小于所述连接数阈值并且所述逻辑连接池中不存在该连接对应的数据库的队列,则为该数据库创建队列,把该队列添加到所述逻辑连接池中,把该连接置于该队列的尾部,并且把该连接置于所述全局队列的头部。
根据本发明的优选实施方式,所述全局队列是链表或数组。
根据本发明的优选实施方式,所述全局队列采用LRU链表的形式。
根据本发明的优选实施方式,所述逻辑连接池包括的队列是数组。
附图说明
下面将参考附图详细地描述本发明的实施例,其中:
图1是本发明的两层连接池结构的示意图;
图2是本发明的连接池初始化的流程图;
图3是本发明的连接池单元分配连接的流程图;
图4是本发明的连接池单元回收连接的流程图。
具体实施方式
当应用要访问分布式数据库系统中的数据库时,需要建立数据库连接(databaseconnection),使得可对数据库进行存取,如通过SQL操作对数据库中的数据进行查询、增加、修改和删除,并且在操作完成后关闭数据库连接。对于一个复杂的数据库应用,频繁的建立、关闭数据库,会极大的降低系统的性能,增大系统的开销,甚至成为系统的瓶颈。数据库连接成为一种有限的昂贵资源。
为了合理利用数据库连接这种资源,产生了数据库连接池技术。连接池技术的基本的思想是在系统初始化的时候,将数据库连接作为对象来建立并存储在内存中,当应用请求访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接分配给该请求。使用完毕后,应用也并非将连接关闭,而是将连接释放回连接池中,以供下一个请求来使用。而连接的建立、关闭都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。通过在应用之间共享连接,而不是在需要连接的时候再建立,就可以改善资源使用,提高应用的响应能力。
根据本发明,采用分层模式来实现一种数据库连接池,使得既可控制连接的总数又能对各个数据库合理的分配连接,同时又尽可能的减少网络IO次数。
根据本发明的数据库连接池包括全局连接池和逻辑连接池两部分。图1是本发明数据库连接池的结构图示。
根据本发明的优选实施例,全局连接池是一个队列,称为全局队列,例如全局队列采用LRU链表的形式,每个连接是LRU链表中的一个元素。利用LRU链表,可以保证刚使用过的连接一定位于该链表的头部,即作为第一个元素,而链表的尾部元素是未被使用或者空闲时间较长的连接。
队列的有序特性保证了从连接池中获取连接的时候,如果出现某个数据库对应的连接池队列中的连接数不够时,可以通过全局连接池快速找到最不活跃的数据库对应的连接池队列中的连接或者是从未被使用连接,从而保证了各个数据库间连接资源的充分利用。
逻辑连接池由各个数据库对应的队列构成。数据库对应的队列以普通的链表或者数组的形式构成。
逻辑连接池中各个数据库对应的队列中的连接与全局连接池的队列中的连接是一样的,即逻辑连接池中各个数据库对应的队列中的连接一定是位于全局连接池的队列中的连接,但全局连接池的队列中的连接不一定都出现在逻辑连接池中。
如图1所示,数据库DB1对应的连接池队列中有两个连接,这两个连接分别是全局连接池的全局队列中的第一个连接和第二个连接,数据库DB2对应的队列中有一个连接,该连接对应全局队列中的第三个连接。全局队列中的第四个连接和第五个连接因为还没有被使用过,所以不属于逻辑连接池中的任何一个数据库对应的队列。
根据本发明的连接池管理单元主要完成三个方面的工作,分别是:
初始化连接池,
分配连接,以及
回收连接。
下面就这三个方面进行详细说明。
(1)初始化连接池
当数据库中间件启动或者重新加载配置时,需要对连接池做初始化工作。
对连接池要设置一些参数,比如:
连接池的总的连接数额度,
连接池最小初始化连接数,以及
弹性连接数额度等。
根据这些参数设置进行相应的初始化工作。
因连接池是分层连接池,在初始化的时候会根据最小初始化连接数来创建连接,新创建的连接在初始化的时候只放在全局连接池中,逻辑连接池中是空的。整个初始化流程如图2所示。
(2)分配连接
通过数据库中间件进行数据库操作的时候,该数据库操作是针对某个具体的数据库。因此,在数据库中间件请求连接的时候都会指定具体的数据库名。
连接池单元接收连接请求,该连接请求包含数据库名。然后,连接池单元开始连接分配的过程。下面结合图3描述分配连接的过程。
在步骤S3001,连接池单元根据该数据库名到逻辑连接池中去寻找相应数据库所对应的队列。
在步骤S3002,确定逻辑连接池中是否存在该数据库对应的队列。如果存在,则在步骤S3011获取该数据库对应的队列并且转到步骤S3013,否则转步骤S3021。
在步骤S3013,确定该数据库对应的队列是否为空。若不空,则转到步骤S3015,否则转到步骤S3021。
在步骤S3015,从该数据库对应的队列中取得一个连接,并同时将该连接从该队列移除,然后转到步骤S3017。
在步骤S3017,在全局队列中移除所取得的连接。并且接着在步骤S3019把该连接返回给请求连接的应用。
根据本发明,在具体实现的时候,可以直接以数组来表示逻辑连接池中数据库对应的队列。分配连接的时候从数组的末尾获取,在回收连接的时候(具体见后面回收连接的步骤),直接将连接置于数组的末尾即可,从而保证优先获取最不活跃的连接。
如果在步骤S3013判定逻辑连接池中存在该数据库对应的队列,但此时该队列为空,则需要转到步骤S3021,使得到全局队列中去获取连接。
在步骤S3021判断全局队列是否为空。当非空时,转到步骤S3023。
在步骤S3023,从全局队列的末尾获取未被使用的连接,或者是其它数据库对应的队列中最不活跃的连接(如果是后者的情况,要解除该连接与该其他数据库的对应关系),并且将该连接从全局队列中移除。
接着在步骤S3025建立并记录该连接与该数据库的对应关系。例如,通过“use db”操作来建立这种对应关系,其中db是具体的数据库名。这样,使得该连接和相应的数据库关联,后续即可通过该连接正常操作该数据库了。然后转步骤S3019把该连接返回给请求连接的应用。
如果在步骤S3021判定全局队列为空,即全局队列中所有的连接都已经被分配了,转步骤S3031判断活跃连接总数有没有达到连接池总的连接数额度。如果还没有达到总的连接数额度,则转步骤S3033,直接创建新的连接,然后依次转步骤S3025、S3019,建立并记录该新连接和该数据库的对应关系,并向调用者返回该连接。
如果在步骤S3031判定活跃连接数已经达到了连接池的连接总数的限制,则在步骤S3041来发出连接数报警。
可选地,在步骤S3043查看是否还有弹性连接额度可以使用。弹性连接是指在连接总数限制之外的用于应对临时增大的突发的访问量而创建的连接。这些连接会在使用完之后就释放,保证对数据库的连接压力尽可能的低。
如果在步骤S3043判定还可以创建弹性连接,则转步骤S3033来创建新的连接,然后转步骤S3025,将新的连接和该数据库对应上并记录该对应关系。然后依次转步骤S3025、S3019,建立并记录该新连接和该数据库的对应关系,并向调用者返回该连接。
如果在步骤S3043判定弹性连接的额度都已经用完了,则在步骤S3045返回获取连接失败的异常消息。
因为对连接池进行了分层处理,所在获取具体某个数据库的连接的时候,如果逻辑连接池中该数据库对应的队列里的连接不够用,可以去全局连接池的全局队列中获取未被使用或者是其它数据库对应的队列中最不活跃的连接,从而保证了连接资源的利用最终会趋于合理的状态,即不活跃的数据库对应的队列中的连接会被转移到活跃的数据库对应的队列中。
(3)回收连接
从连接池中获取到的连接在使用之后需要释放给连接池。在连接池回收连接的时候需要将连接正确置于连接池的合理位置。回收的位置主要包括两处:一个是在全局连接池的全局队列中的位置,另一个是在逻辑连接池中相应队列中的位置。
下面结合图4描述回收连接的过程。
在连接释放给连接池的时候,因为每个使用过的连接都是和具体的数据库有对应关系,所以首先在步骤S4001获取该连接对应的数据库的信息。
连接被实际回收之前,在步骤S4002判断当前连接池中的连接总数是否已经达到阈值。
如果在步骤S4002判定当前连接池中的所有的连接数已经大于等于连接池总的连接数额度,这表明在获取连接的时候已经创建出了临时的弹性连接,在这种情况下,则转步骤S4008直接关闭该连接,从而保证整个连接池的连接总数是可控的。
如果在步骤S4002判定当前连接池的连接数是小于总的连接数额度的,则转步骤S4003用于把该连接返回到逻辑连接池中。
在步骤S4003判断该连接对应的数据库的队列是否存在,如果存在则转步骤S4006,直接把该连接放回到该数据库的队列中。具体实现可直接将该连接置于表示该数据库的队列的末尾即可。
如果在步骤S4003判定逻辑连接池中不存在该数据库对应的队列,则转步骤S4004,为该数据库创建一个队列,然后在步骤S4005将该数据库标示及对应的队列添加到逻辑连接池中,然后转步骤S4006再将该连接返回到对应的数据库的(新创建的)队列中。
将连接返回到逻辑连接池中以后,在步骤S4007把连接返回到全局连接池的全局队列中。例如,当全局队列采用LRU链表表示,则将连接放到LRU链表的头部,即第一个元素位置。
尽管结合附图详细描述了本发明的实施例,但实施例仅用于解释和说明本发明,而不是用于限制本发明。本发明的范围由权利要求书来限定,其中某些要素的改变、替换等是显而易见的。