2012-05-02 21 views
15

我有一些基於gevent的管理命令。由於我的管理命令使得成千上萬的請求,我可以使用Gevent將所有套接字調用轉換爲非阻塞調用。這確實可以加快我的應用程序,因爲我可以同時發出請求。pgBouncer如何幫助加快Django

目前我的應用程序的瓶頸似乎是Postgres。看起來這是因爲用於連接到Django的Psycopg庫是用C編寫的,並且不支持異步連接。

我也讀過使用pgBouncer可以使Postgres速度提高2倍。這聽起來不錯,但如果有人能夠解釋pgBouncer如何工作和幫助,那將會很棒。

感謝

+0

您的數據庫模型也有可能與您正在觸發的查詢不匹配。通常,與從磁盤獲取數據塊所需的工作相比,網絡開銷非常小,這不會降低性能,只會延遲時間。 (除非是頻繁連接/斷開連接的情況除外) – wildplasser

回答

65

除了保存連接的開銷&在每個請求上以其他方式完成的斷開連接池之後,連接池可以將大量客戶端連接彙集到少量的實際數據庫連接。在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社區認爲,由於最佳連接池接近客戶端軟件,因此他們會將其留給用戶來管理。大多數合作者可以通過某種方式將數據庫連接限制爲硬數字,同時允許更多的併發客戶端請求,並根據需要對其進行排隊。這是你想要的,它應該在交易的基礎上完成,而不是每個語句或連接。

+1

優秀的答案。我十分同意。 – wildplasser

+0

這些前端嬉皮士都希望儘可能快地建立和斷開連接,並且如果他們無法達到自然高位狀態,則會將連接杆置於前面。我喜歡2 * ncore + nspindle公式。每個進程都被認爲在磁盤讀取中被阻塞。 – wildplasser

+0

@kgrittn我在上面的思想實驗中假設,每個查詢在沒有其他請求的情況下需要一秒鐘運行? –

9

PgBouncer減少由作爲其保持連接池的代理建立連接的延遲。如果您打開許多短期連接到Postgres,這可能有助於加速您的應用程序。如果你只有少量的連接,你就不會看到太多的勝利。

+0

如果我已經理解了這個問題,Django仍然一次又一次地創建連接,但是pgBouncer減少了創建這個連接所需的時間。我聽說Django爲每個請求創建一個新的連接。通過請求,人們是否意味着獲取頁面的Web請求(這意味着在視圖的週期中執行的每個命令都通過一個單一的數據庫連接),或請求意味着每個單獨的數據庫命中(SELECT,INSERT,UPDATE和DELETE )在這種情況下,即使每個命令都處於同一視圖中,每個命令都將在新連接中執行 –

+2

是的,Django將創建一個新連接,但連接將建立得更快,因爲它將連接到本地PgBouncer實例。 Django將爲每個Web請求使用一個新連接,而不是數據庫查詢。 –

+1

你可能會發現[這個問題](http://stackoverflow.com/questions/1125504/django-persistent-database-connection)有一些更有趣的信息。但請注意,每個請求都會打開新的連接。如果請求遇到錯誤,則可能會導致意外結果,導致事務可能無法正確關閉(等等)。 –