连接池应该提高 postgres 的吞吐量,或者至少这是每个人在谷歌搜索什么是池及其好处时所说的,但是每当我在烧瓶中尝试连接池时,结果总是比它慢得多在文件的开头打开一个连接和一个游标,并且从不关闭它们。如果我的 web 应用程序不断收到来自用户的请求,为什么我们甚至关闭连接和游标,创建一个连接和游标一次,然后每当我们收到请求时,GET 或 POST 请求是否只使用现有的请求不是更好吗?游标和连接。我在这里错过了什么吗?! 这是每种方法的时间安排,下面是我运行以对每种方法进行基准测试的代码
使用一个数据库连接完成 100000 次查询需要 16.537524700164795 秒,我们在 Flask 应用程序开始时打开了一次,从未关闭
使用 psqycopg2 池化方法完成 100000 次查询需要 38.07477355003357 秒
使用 pgbouncer 池化方法完成 100000 次查询需要 52.307902574539185 秒
这里还有一个运行测试的视频,如果有帮助的话 https://youtu.be/V2kzKApDs8Y
我用来对每种方法进行基准测试的烧瓶应用程序是
import psycopg2
import time
from psycopg2 import pool
from flask import Flask
app = Flask(__name__)
connection_pool = pool.SimpleConnectionPool(1, 50,host="localhost",database="test",user="postgres",password="test",port="5432")
connection = psycopg2.connect(host="127.0.0.1",database="test",user="postgres",password="test",port="5432")
cursor = connection.cursor()
pgbouncerconnection_pool = pool.SimpleConnectionPool(1, 50, host="127.0.0.1",database="test",user="postgres",password="test",port="6432")
@app.route("/poolingapproach")
def zero():
start = time.time()
for x in range(100000):
with connection_pool.getconn() as connectionp:
with connectionp.cursor() as cursorp:
cursorp.execute("SELECT * from tb1 where id = %s" , [x%100])
result = cursorp.fetchone()
connection_pool.putconn(connectionp)
y = "it took " + str(time.time() - start) + " seconds to finish 100000 queries with the pooling approach"
return str(y) , 200
@app.route("/pgbouncerpooling")
def one():
start = time.time()
for x in range(100000):
with pgbouncerconnection_pool.getconn() as pgbouncer_connection:
with pgbouncer_connection.cursor() as pgbouncer_cursor:
pgbouncer_cursor.execute("SELECT * from tb1 where id = %s" , [x%100])
result = pgbouncer_cursor.fetchone()
pgbouncerconnection_pool.putconn(pgbouncer_connection)
a = "it took " + str(time.time() - start) + " seconds to finish 100000 queries with pgbouncer pooling approach"
return str(a) , 200
@app.route("/oneconnection_at_the_begining")
def two():
start = time.time()
for x in range(100000):
cursor.execute("SELECT * from tb1 where id = %s",[x%100])
result = cursor.fetchone()
end = time.time()
x = 'it took ' + str(end - start)+ ' seconds to finish 100000 queries with one database connection that we don\'t close'
return str(x) , 200
if __name__=="__main__":
app.run()
答案 0 :(得分:0)
我不确定你是如何测试的,但是连接池的想法基本上是解决两件事:
所以我相信你的测试必须专注于这两种情况。
如果您的测试只有 1 个用户请求大量查询,则连接池将只是一种开销,因为它会尝试打开您不需要的额外连接。
如果您的测试总是返回相同的数据,您的 DBMS 可能会缓存结果和查询计划,因此会影响结果。事实上,为了扩展事物,您甚至可以从诸如 elasticsearch 之类的二级缓存中受益。
现在,如果要进行实际测试,必须混合读写操作,在其中添加一些随机变量(强制 DB 不缓存结果或查询计划)并尝试增量加载,这样您就可以看到每次添加更多并发客户端执行请求时系统的行为。
并且由于这些客户端还为测试增加了更多 CPU 负载,您还可以考虑在与为您的数据库提供服务的机器不同的机器上运行客户端,以保持结果公平。