pgBouncer如何帮助加速Django

Mri*_*lla 22 python django postgresql connection-pooling pgbouncer

我有一些基于gevent的管理命令.由于我的管理命令使成千上万的请求,我可以使用Gevent将所有套接字调用转换为非阻塞调用.这真的加快了我的应用程序,因为我可以同时提出请求.

目前我应用程序的瓶颈似乎是Postgres.这似乎是因为用于连接Django的Psycopg库是用C语言编写的,不支持异步连接.

我还读到使用pgBouncer可以将Postgres加速2倍.这听起来不错,但如果有人能解释pgBouncer如何工作和帮助会很棒吗?

谢谢

kgr*_*ttn 79

除了节省连接和断开的开销,否则在每个请求上执行此操作,连接池可以将大量客户端连接汇集到少量实际数据库连接.在PostgreSQL中,活动数据库连接的最佳数量通常在某处((2*core_count)+ effective_spindle_count).超过这个数字,吞吐量和延迟都会变得更糟.

有时人们会说"我想支持2000个用户,响应时间快".几乎可以肯定的是,如果你试图用2000个实际的数据库连接做到这一点,性能将是可怕的.如果您的计算机具有四个四核处理器并且活动数据集已完全缓存,那么通过约35个数据库连接汇集请求,您将看到2000个用户获得更好的性能.

要理解为什么这是真的,这个思想实验应该有所帮助.考虑一个假设的数据库服务器机器,只有一个资源可以共享 - 一个核心.该核心将在所有并发请求中平均分时计时,无需开销.假设100个请求都在同一时刻进入,每个请求都需要一秒的CPU时间.核心适用于所有这些核心,在它们之间进行时间切片,直到它们都在100秒后完成.现在考虑如果你在前面放置一个连接池会接受100个客户端连接,但一次只向数据库服务器发出一个请求,将连接繁忙时到达的任何请求放入队列中会发生什么.现在当100个请求同时到达时,一个客户端在1秒内得到响应; 另一个客户端在2秒内获得响应,最后一个客户端在100秒内获得响应.没有人必须等待更长时间才能得到响应,吞吐量是相同的,但平均延迟是50.5秒而不是100秒.

真正的数据库服务器有更多的资源可以并行使用,但同样的原则一旦它们已经饱和,你只会通过添加更多的并发数据库请求来伤害事物.它实际上比示例更糟糕,因为随着更多任务,您有更多的任务切换,锁和缓存的争用增加,L2和L3缓存线争用,以及许多其他问题,这些问题都会导致吞吐量和延迟.最重要的是,虽然高work_mem设置可以通过多种方式帮助查询,但该设置是每个连接的每个计划节点的限制,因此对于大量连接,您需要将此设置为非常小以避免刷新缓存或甚至导致交换,这导致计划速度变慢或哈希表溢出到磁盘等事情.

一些数据库产品有效地在服务器中建立了一个连接池,但是PostgreSQL社区已经采取了这样的立场:由于最好的连接池是在靠近客户端软件的情况下完成的,因此它们会留给用户来管理它.大多数的poolers都会有一些方法来限制数据库与硬编号的连接,同时允许更多的并发客户端请求,并根据需要对它们进行排队.这是你想要的,它应该在事务的基础上完成,而不是每个语句或连接.

  • 很好的答案。我十分同意。 (2认同)
  • @MichaelMior:在PostgreSQL中,每个客户端连接有一个OS*进程*,它依赖于操作系统进行调度.各种进程通过共享内存段,OS信号(如果可用)和自引用UDP套接字进行通信. (2认同)

Mic*_*ior 11

PgBouncer通过充当维护连接池的代理来减少建立连接的延迟.如果您打开与Postgres的许多短暂连接,这可能有助于加快您的应用程序.如果你只有少量的连接,你将看不到多少胜利.

  • 是的,Django将创建一个新连接,但连接将更快建立,因为它将是一个本地PgBouncer实例.Django将为每个Web请求使用新连接,而不是数据库查询. (2认同)
  • 您可以连接到信号`django.db.backends.signals.connection_created`,然后进行一些记录.(请注意,您不希望在生产中执行此操作,因为它会增加不必要的开销.) (2认同)