3ms 数据库链接池终于搞对了 这次直接从100ms优化到3ms
数据库连接池的配置是开发人员经常打洞的地方。配置数据库连接池时,有几个原则与直觉相悖。
10,000个并发用户访问
假设你有一个网站。虽然压力没有脸书大,但也有1万人次的并发访问——也就是说,TPS约2万。那么这个网站的数据库连接池应该设置多大呢?结果可能会让你大吃一惊,因为问这个问题的正确方式是:
"这个网站的数据库连接池应该设置多小?"
以下视频由甲骨文真实世界性能组发布。请先阅读:
http://www.dailymotion.com/video/x2s8uec
在视频中,对Oracle数据库进行了压力测试,9600个并发线程运行数据库。每两次访问数据库操作之间的休眠550毫秒为550毫秒,开始设置的中间件线程池大小为2048:
从等待和吞吐量可以看出,中间件连接池从2048年减半后,吐槽量没有变化,但是等待事件减少了一半。
接下来,数据库连接池减少到96,并发线程的数量保持不变,为9600。
96个连接的性能数据
队列平均等待1毫秒,执行SQL平均需要2毫秒。
等待事件几乎消失,吞吐量增加。
其他不做调整,只减少中间件层的数据库连接池,请求响应时间从100ms缩短到3ms。
但是为什么呢?
为什么nginx在100个进程只有4个线程的情况下表现优于Apache HTTPD?回想计算机科学的基础知识,答案显而易见。
即使是一台拥有单核中央处理器的计算机也可以“同时”运行数百个线程。但我们都知道,这只是操作系统用时间切片玩的把戏。一个CPU内核一次只能执行一个线程,然后操作系统切换上下文,内核开始执行另一个线程的代码,以此类推。给定一个CPU内核,顺序执行A和B总是比通过时间切片“同时”执行A和B更快,这是计算机科学的一个基本规则。一旦线程数超过CPU内核数,增加线程数只会让系统变慢,而不是变快。
这几乎是事实...
有限的资源
以上说法只能说是接近事实,但也不是那么简单,还有一些其他的因素需要补充。当我们寻找数据库的性能瓶颈时,我们总是可以将其分为三类:中央处理器、磁盘和网络。加内存没有错,但是内存的带宽比磁盘和网络高几个数量级,所以不先加。
如果我们忽略磁盘和网络,结论很简单。在8核服务器上,将连接/线程的数量设置为8可以提供最佳性能,而增加连接的数量会由于上下文切换的丢失而导致性能下降。
数据库通常将数据存储在磁盘上,磁盘通常由旋转的金属盘和安装在步进电机上的读写头组成。读/写磁头一次只能出现在一个地方,然后必须“寻址”到另一个地方才能执行另一个读/写操作。因此,解决需要时间,轮换也需要时间。读/写磁头需要等待磁盘上的目标数据“原地旋转”,然后才能工作。使用缓存当然可以提高性能,但上述原则仍然适用。
在这段时间内,线程正在阻塞等待的磁盘,操作系统可以使用那个空空闲的CPU内核来服务其他线程。因此,因为线程总是在I/O上被阻塞,所以我们可以比CPU内核制造更多的线程/连接,这样我们就可以在相同的时间内完成更多的工作。
那么应该多多少呢?这取决于磁盘。较新的固态硬盘不需要寻址,也没有旋转磁盘。不要想当然地认为“SSD更快,所以要增加线程数”。相反,不寻址、不循环意味着阻塞更少,所以线程越少,性能就越高。只有阻塞创造了更多的执行机会,更多的线程才能在性能上发挥更好的作用。
网络类似于磁盘。通过以太网接口读写数据时,也会形成拥塞,10G带宽小于1G带宽,1G带宽小于100M带宽。但是,网络通常是第三个考虑因素,有些人会在性能计算中忽略它们。
上图是PostgreSQL的基准数据,可以看出TPS的增长速度从50个连接开始放缓。在上面的甲骨文视频中,他们将连接数量从2048个减少到96个。事实上,除非服务器有16或32个内核,否则96就太高了。
计算公式
以下公式是PostgreSQL提供的,但我们认为它可以广泛应用于大多数数据库产品。您应该模拟预期的访问,并根据这个公式测试您的应用程序,以找到最合适的连接值。
连接数=+有效磁盘数)
即使超线程已打开,内核数量也不应包括超线程。如果缓存了所有活动数据,则有效磁盘的数量为0。随着缓存命中率的降低,有效磁盘数逐渐接近实际磁盘数。该公式对固态硬盘的影响尚未分析。
根据这个公式,您的4核i7数据库服务器的连接池大小应该是+1) = 9。让我们把它四舍五入到10。你认为它太小了吗?运行一个性能测试,我们保证它可以轻松处理3000个用户以6000点/秒的速度并发执行简单查询的场景。如果连接池大小超过10,您将看到响应时间开始增加,TPS开始减少。
作者备注:
其实这个公式不仅适用于数据库连接池的计算,还涉及到计算和I/O程序。线程数的设置可以参考这个公式。当我之前对Netty编写的消息服务进行压力测试时,最佳线程数只是CPU内核数的两倍。
公理:您需要一个小的连接池和一个充满等待连接的线程的队列
如果你有10,000个并发用户,设置一个10,000的连接池基本上相当于失去理智。1000还是很可怕。即使100也太多了。您需要一个大约10个连接的小连接池,然后让其余的业务线程在队列中等待。连接池中的连接数应该等于数据库可以同时有效执行的查询任务数。
我们经常看到一些小规模的web应用程序,它们处理大约十几个并发用户,但是使用100个连接的连接池。这将给数据库带来不必要的负担。
专心
连接池的大小最终与系统特性有关。
例如,具有长事务和短事务的系统通常很难由任何连接池进行调整。最好的方法是创建两个连接池,一个用于长事务,一个用于短事务。
例如,当系统执行任务队列时,只允许同时执行一定数量的任务。此时,并发任务的数量应该与连接池连接数相适应,而不是相反。
本文95%的内容翻译自
https://github . com/brettowoldridge/HikariCP/wiki/About-Pool-size
原文来自https://www.jianshu.com/p/a8f653fc0c54
-结束-
“院子院子”
现有技术人员8万+
涵盖JAVA/PHP/IOS/测试等领域
其中80%在P6及以上,包括30名P9技术人员
500多名技术总监和首席技术官