除了保存連接的開銷&在每個請求上以其他方式完成的斷開連接池之後,連接池可以將大量客戶端連接彙集到少量的實際數據庫連接。在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社區認爲,由於最佳連接池接近客戶端軟件,因此他們會將其留給用戶來管理。大多數合作者可以通過某種方式將數據庫連接限制爲硬數字,同時允許更多的併發客戶端請求,並根據需要對其進行排隊。這是你想要的,它應該在交易的基礎上完成,而不是每個語句或連接。
您的數據庫模型也有可能與您正在觸發的查詢不匹配。通常,與從磁盤獲取數據塊所需的工作相比,網絡開銷非常小,這不會降低性能,只會延遲時間。 (除非是頻繁連接/斷開連接的情況除外) – wildplasser