数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知( 二 )


那么应该多多少呢?这要取决于磁盘 。较新型的SSD不需要寻址,也没有旋转的碟片 。可别想当然地认为“SSD速度更快,所以我们应该增加线程数”,恰恰相反,无需寻址和没有旋回耗时意味着更少的阻塞,所以更少的线程[更接近于CPU核心数]会发挥出更高的性能 。只有当阻塞创造了更多的执行机会时,更多的线程数才能发挥出更好的性能 。
网络和磁盘类似 。通过以太网接口读写数据时也会形成阻塞,10G带宽会比1G带宽的阻塞少一些,1G带宽又会比100M带宽的阻塞少一些 。不过网络通常是放在第三位考虑的,有些人会在性能计算中忽略它们 。

数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知

文章插图
 
上图是PostgreSQL的benchmark数据,可以看到TPS增长率从50个连接数开始变缓 。在上面Oracle的视频中,他们把连接数从2048降到了96,实际上96都太高了,除非服务器有16或32颗核心 。
计算公式下面的公式是由PostgreSQL提供的,不过我们认为可以广泛地应用于大多数数据库产品 。你应该模拟预期的访问量,并从这一公式开始测试你的应用,寻找最合适的连接数值 。
连接数 = ((核心数 * 2) + 有效磁盘数)
核心数不应包含超线程(hyper thread),即使打开了hyperthreading也是 。如果活跃数据全部被缓存了,那么有效磁盘数是0,随着缓存命中率的下降,有效磁盘数逐渐趋近于实际的磁盘数 。这一公式作用于SSD时的效果如何尚未有分析 。
按这个公式,你的4核i7数据库服务器的连接池大小应该为((4 * 2) + 1) = 9 。取个整就算是是10吧 。是不是觉得太小了?跑个性能测试试一下,我们保证它能轻松搞定3000用户以6000TPS的速率并发执行简单查询的场景 。如果连接池大小超过10,你会看到响应时长开始增加,TPS开始下降 。扩展:用了这么久的数据库连接池,你知道原理吗?
笔者注:这一公式其实不仅适用于数据库连接池的计算,大部分涉及计算和I/O的程序,线程数的设置都可以参考这一公式 。我之前在对一个使用Netty编写的消息收发服务进行压力测试时,最终测出的最佳线程数就刚好是CPU核心数的一倍 。
公理:你需要一个小连接池,和一个充满了等待连接的线程的队列如果你有10000个并发用户,设置一个10000的连接池基本等于失了智 。1000仍然很恐怖 。即是100也太多了 。你需要一个10来个连接的小连接池,然后让剩下的业务线程都在队列里等待 。连接池中的连接数量应该等于你的数据库能够有效同时进行的查询任务数(通常不会高于2*CPU核心数) 。
我们经常见到一些小规模的web应用,应付着大约十来个的并发用户,却使用着一个100连接数的连接池 。这会对你的数据库造成极其不必要的负担 。
请注意连接池的大小最终与系统特性相关 。
比如一个混合了长事务和短事务的系统,通常是任何连接池都难以进行调优的 。最好的办法是创建两个连接池,一个服务于长事务,一个服务于短事务 。
再例如一个系统执行一个任务队列,只允许一定数量的任务同时执行,此时并发任务数应该去适应连接池连接数,而不是反过来 。




推荐阅读