PHP-FPM模式下可怕的 MongoDB-PHP-Driver 連接池無節制連接問題


@鄭昀匯總 創建日期:2013/1
 
問題發生環境:
  • Nginx
  • PHP 5.3.10 as php-fpm extension to nginx
  • mongodb-php-driver 1.2.12
  • MongoDB 2.2
此問題是 MongoDB PHP Driver 1.2.x 的官方特性導致的,描述請看  PHP-202 和   PHP-347 。簡單地說,PHP-FPM模式下,每一個 PHP Worker 進程都有自己獨立的 mongodb 連接池,從而導致連接數極易超標,內存數也隨之倍增。
 
一,PHP服務背景:
某個 Web 應用是通過   Nginx+factcgi  運行的 PHP 程序提供服務的。
PHP-FPM的最大子進程數,是通過 php-fpm.conf 的  max_children  參數設置的(或pm=dynamic時由 spare_servers+start_servers 參數綜合決定)。這個值曾被設置為 512
 
二,MongoDB服務背景:
mongodb 實例的最大連接數限制可以通過啟動參數中的   maxConns  設置:
  • maxConns:默認值取決於系統的限制(如 ulimit 和 file descriptor)。如果沒設置這個參數, mongodb 自己不會限制連接數。但,你不能設置超過 20,000 。
一般不刻意設置 maxConns 參數。
 
三,MongoDB PHP Driver 的可怕連接池特性(BUG?)
MongoDB 官方提供的   mongodb-php-driver  在 1.3.0 以下版本(1.2.0~1.2.1x),擁有一個可怕的連接池實現方案,在執行任何查詢時,都會從連接池中請求一個連接,完成之后再歸還給連接池。這里的完成是指持有該連接的變量離開了它的作用域。
 
PHP-FPM模式下,一個 PHP Web 應用能對 MongoDB instance 建立的並發連接數計算方式如下:
  • 進程數:max-children = 512 ,那么是 512 個進程
  • 一個MongoDB實例對應一個連接池:主站配置了165和166兩個副本集實例;
  • 連接池中的連接數:mongodb-php-driver 對此不做任何限制,可以無限增加直到句柄耗盡為止。
—————— 鄭昀:此計算方式出自  mongo.connecting.pools ——————
根據 mongodb 官方文檔說明, 雖然連接數無限增長理論上是有可能的,但實際觀測發現,一個 Web Server 與一個 mongodb 實例的連接數通常會穩定在一個值上,不會有太大的起伏
那么,假設 一個 PHP Web 應用向 mongodb-165 發起的連接數為
750 個,
該 MongoDB 實例為此需要維護的內存數至少為:
750 × 默認10MB =   7.5 GB
 
五,解決辦法
迅速升級到 mongodb-php driver 1.3.2。
 
參考文檔:
1)2012-12-9,Connection Handling with the MongoDB PHP driver,英文稿中文翻譯稿
2)李丹的測試結果:
“再測試一下驅動升級到1.3.2穩定版后的ab結果,發現close效果很明顯,很快的連接數就下降到測試之前的數量了。雖然在峰值上大於老的驅動,但是應該可以解決現有線上的高連接持續的問題。”
4)mongodb-java-driver 定義了一個應用與 mongodb 實例能建立的最大連接數,即 (connectionsPerHost × threadsAllowedToBlockForConnectionMultiplier)個連接:
  • mongo.options.connectionsPerHost:每個Application與 MongoDB 實例能建立的最大物理連接數,默認是10;
  • mongo.options.threadsAllowedToBlockForConnectionMultiplier:可以等待池中有連接可用的最大線程數,默認是5。
5)crazyshell,2012,MongoDB maxConns參數

贈圖幾枚:
http://ww4.sinaimg.cn/large/61b889f5jw1e0noudfng5j.jpg
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM