從一個數據庫連接數計算公式談起
?昨天一個微信群里在討論一個數據庫連接數?的計算公式,截圖看不太清楚。我來描述一下。說是PG提供了一個連接數計算公式:連接數=核心數*2+有效磁盤數量。其中核心數不應該包含超線程數量,而是物理核的數量。

這是一個十分典型的極限測試估算連接數的公式,主要目的是規(guī)避CPU方面存在的瓶頸。這種設置思路往往不會使用在普通的生產系統(tǒng)上,因為不管是OLTP系統(tǒng)還是OLAP系統(tǒng),作為數據庫服務器來說,會話會有大量的工作會產生在IO上,包括網絡IO和磁盤IO,真正使用CPU的比例實際上并不高。對于OLTP系統(tǒng)來說大量的CPU使用都是小于一個時間片(大部分UNIX系統(tǒng)都是一個厘秒)的,很少會把一個時間片用滿,因為數據庫應用中,會話大部分都在等待某些等待事件,比如IO,LWLOCK,LOCK,IPC等,一個會話ONCPU狀態(tài)的比例很低,因此使用CPU數量來作為會話數的設置基礎實際上并沒有任何科學依據。
從另外一個角度來說,CPU之間也是有差異的,哪怕核數相同的CPU,其處理能力也不能同日而語,三五年前的同樣核數的CPU,其處理能力可能不到現在的1/3,花費同樣CPU時間能夠完成的任務也會相差極大。簡單的用CPU作為設置連接數的依據顯然是不合理的。在現在的絕大多數OLTP系統(tǒng)中,數據庫服務器的CPU資源都是十分充足的,大部分系統(tǒng)的主要問題并不出現在CPU資源不足上,這是這二十年來摩爾定律給我們帶來的紅利。

實際上數據庫中的存在排隊效應的地方很多,任何一個地方存在瓶頸都會影響極限測試的性能,也會影響到生產環(huán)境中的并發(fā)訪問效率。兩年前我寫過一篇文章《從疏通下水道聯想到的優(yōu)化問題》,這篇文章中對此做了詳細的分析,有興趣的朋友可以在我的公眾號中查找閱讀。
實際上決定數據庫連接數的最主要因素還是應用,對于絕大多數數據庫系統(tǒng)而言,max_connections參數一定要確保使用這個數據庫的所有模塊不會因為連接池不足而導致應用報錯?,F在的應用系統(tǒng)大多十分復雜,還有大量的模塊使用并發(fā)量十分不穩(wěn)定的微服務。我見過一套數據庫系統(tǒng)對接的應用連接池超過100個,哪怕一個連接池設置幾十個連接,max_connections也必須設置為幾千才能確保大多數情況下不會因為數據庫連接數限制而導致應用故障。
數據庫的最大連接數設置的過大有什么壞處呢?最容易出問題的往往不是CPU,當然如果在云環(huán)境中,我們給數據庫的CPU資源很少,那么較大的連接可能會引發(fā)CPU資源的不足。關于云環(huán)境數據庫服務器的CPU資源問題,那是一個更大的話題-容量管理,今天我們暫不討論。數據庫應用對CPU的使用一般來說是不存在資源不足的問題的,當然如果某個并發(fā)量很大的SQL的執(zhí)行計劃錯了,是很容易把CPU跑爆掉的,這個也不在我們今天探討的范圍內,因為這種情況出現,哪怕連接數設置的很低,也會出問題。
除此之外,實際上最容易出問題的是內存,數據庫會話數多了,因為ATTACH共享內存所占用的TLB就會很大,特別是數據庫沒有使用大頁的情況下。前陣子我們在分析一個數據庫宕機的案例中,就發(fā)現一臺128GB的數據庫服務器上,TLB居然高達30GB。另外會話都會使用WORK_MEM來做排序、JOIN等操作。會話數多了,這些內存自然就會使用的更多。前兩年和一個國外的PGER交流的時候,他提出了一個PG內存估算的方法,悲觀的算法是MAX_CONNECTIONS*WORK_MEM作為會話工作內存,樂觀的算法是MAX_ACTIVE_SESSIONS*WORK_MEM作為會話的工作內存。根據這個,結合物理內存大小,計算SHARED_BUFFERS能夠使用內存的最大值。
實際上悲觀與樂觀算法算出來的值相差甚大,基本上不具備參考意義。當時我和他說與其這么精打細算,莫不如把SWAP設置大一點,哪怕物理內存偶爾用的多一些,系統(tǒng)產生一個小抖動,很快就能挺過去了。他想了一會兒,認同了我的觀點。
實際上我們今天討論的內容很多都屬于容量管理的范疇,這個問題也是困擾了我近20年的問題,這20年里,參與過不少容量管理相關的項目,也幫用戶構建了一些模型,只不過,感覺還是在門外晃悠。等有時間,我也會寫幾篇這方面的文章,把我們這些年的一些成果分享給大家。















 
 
 




 
 
 
 