在以下方面设置池的最佳方式是什么:-
- 您何时创建连接
- 你什么时候关闭连接,会关闭所有连接吗
- 你测试连接是否仍然良好。何时以及如何
- 如何计算最大连接数的一个好数字
- 您有什么样的监控来确保池中的用户行为良好?你能阻止一个坏代码把所有东西都取出来吗
- 你是否编写了自己的库,或者使用了第三方库
我认为这是一个不可知论的问题,但对特定数据库/语言的"特性"的评论是受欢迎的。例如,在某些数据库上连接可能比在其他数据库上连接更慢或更昂贵。
为了澄清,我不打算从头开始写一个池,这个问题更多的是关于如何配置一个进行池的现有库。
我用Java为数据库编写了一个连接池,当时它只是一个设计模式,而不是一个公共库。现在我使用Tomcat中内置的一个。
我使用了一个线程来监控池的几个方面,并使用了几个参数来控制它的行为。。。
- minimumInPool="3"。。。前三个是在发布时创建的。游泳池绝对不允许低于三个
- maximumIdleTimeBeforeRemovation="60"。。。如果一个连接空闲了一个小时,请将其删除并创建一个新连接。空闲时间可能意味着池中只有最少三个
- maximumInUseTimeBeforeRemovation="30"。。。如果一个给定的连接已经被检出超过30分钟,那么可能是出了问题。回想一下,然后终止连接
- maximumTimeBeforeRemoval="60"。。。如果超过60分钟,请将其取出
- maximumUsageBeforeRemoval="1000"。。。如果检出次数超过1000次,请将其移除
- monitorInterval="15"。。。每15分钟检查一次上述参数
这几年来对我很有帮助。我见过的最高的游泳池是151个连接。通常情况下,在大量使用期间,游泳池大约有十几个,而在凌晨,游泳池至少有三个闲置。
我使用了Oracle的JDBC精简驱动程序,并连接到了一个Oracle数据库。
以下是我在最近的实现中使用的基本原理。
-
在连接池中有两种类型的连接。第一个是现成的,意思是打开但未被客户端使用。第二种是活动的,意思是被客户使用。
-
让您的连接池维护少量的就绪连接,最小为N,最大为M。N可以根据客户端请求连接的峰值速度进行调整。如果就绪连接的数量降至零,则需要更大的N。如果该数量一直很高(例如高于10),则需要更低的N。
-
当客户端想要一个连接时,给他们一个准备好的连接(使其处于活动状态),然后如果现在准备的连接少于N个,则立即打开一个新的连接(但不要让客户端等待连接完成,否则你将失去池化的优势)。这样可以确保始终至少有N个准备就绪的连接。如果客户想要一个时没有准备好,他们将不得不在您创建新的时等待。
-
当客户端以活动连接结束时,如果就绪连接少于M个,请将其返回到就绪状态。否则,请关闭它。这将阻止您拥有M个以上的就绪连接。
-
定期回收准备好的连接,以防止过时的连接。如果有N个以上的就绪连接,请关闭最旧的连接。否则,关闭它并重新打开另一个。
这样做的优点是在连接池中有足够的就绪和年轻连接,而不会使服务器过载。
Jakarta Commons DBCP已经完成了您列出的所有工作:
- 它根据需要创建连接,并在池中进行管理
- 如果一段时间没有使用,它可以关闭连接
- 它可以在发出连接之前对其执行查询,如果出现错误,则会丢弃该连接并创建一个新的连接。连接也可以在空闲时定期进行测试
- 您可以对将要创建的连接以及要准备的最小连接数设置限制。当然,这个限制在很大程度上取决于你的申请
- 我不知道是怎么回事,但DBCP知道连接何时没有关闭,并为您关闭它,抛出一个异常,以便您在看到日志时知道发生了什么
- DBCP有一个非常有用的超时参数。如果池中的所有连接都在使用,它将等待一段时间,以便将连接返回到池中,如果达到限制时没有可用的连接,则会出现错误
您可以通过播放最小连接数、要创建的最大连接数和超时来微调池。超时时间越长,连接数越低,而超时时间越短,可能需要的连接数越大。这在很大程度上取决于应用程序的功能以及它如何使用连接。
我同意matt b的观点,即我们不应该重新发明轮子。
然而,基于这个和这个问题的答案,使用Commons DBCP是有争议的。这里提到了更好的替代方案,比如c3po或proxyool。
或者您可以使用依赖rdbms的连接池机制。
我不确定您使用连接的上下文是什么,但我可以分享对我有用的内容。
我使用SQL服务器作为后端,并将缓存与之结合使用,以获得更好的性能。我的做法是,只有在我真正需要时才保持连接打开,而不是将连接池化,以便它们立即清理,我可以在SQL活动监视器中准确地看到哪些是活动的,哪些不是。每一个连接都会占用内存,所以在不需要它们的时候,让它发出沉闷的咆哮是很好的。
在回答连接打开和关闭问题之前,让我说缓存非常重要。从缓存中取出一个对象将为您节省大量时间。在我的一些asp.net应用程序中,当开发中启用缓存时,我发现我很难测量延迟,而对于DB调用,完成调用可能需要15到45毫秒,这甚至没有考虑其他延迟因素或负载。我使用的另一种方法是为我的数据提供一个良好的对象结构,这样我只有在发生变化时才会进行数据库更新。我已经在我的对象上实现了一些方法,以确保我做的IO尽可能少。
话虽如此,我们都知道在某个时候我们需要访问和写入数据库,所以我遵循两个原则:
-
保持门窗关闭以节省能源。一个地方的开放连接意味着它在另一个地方不可用(或者内存和其他资源更有限)。我们关闭了池,因为它为我们带来了更好的性能。
-
当连接打开时,我会分批或一次尽可能多地进行操作。这有点复杂,所以让我解释一下。
- 我使用的一种方法是通过管道传递连接对象,这样所有对象都可以使用一个连接对象。这会导致一个连接打开和关闭,而不是10个或更多,具体取决于您的应用程序。这方面的一个很好的例子是我们的一个采购模型,它利用SQL server的强大功能来收集统计信息并散列复杂的订购模式。当你进行200K以上的数据库查找或任何应用程序的用途时,保持打开和关闭连接是没有意义的。另一方面,当我使用对象时,我会尝试捆绑更新,以减少打开连接的时间。因此,在insert调用上执行scope_identity,让我们在缓存对象之前,同时处理插入和查找要添加到对象中的唯一ID。在我第一次开发asp应用程序的时候,我会在页面开始加载时立即打开连接,然后关闭它。我不建议再那样做了。现在有一天,这些抽象和层有很大的好处,我建议任何新手程序员都要仔细注意
我的两分钱:
缓存您的数据!缓存您的数据!缓存您的数据!当你不能缓存数据时,尽可能少地访问数据库!
为什么要重新发明轮子?
可能已经有人解决了这个问题,而且更好。
如果您在Java世界中,您可以使用Commons DBCP。