MongoDB PHP Driver的串連處理解析

來源:互聯網
上載者:User
1.3版本的PHP MongoDB driver重寫了串連處理庫,和以前版本相比,在持久串連和串連池方面,都有了重大的變化。

1.2版本的串連管理

1.2版本的驅動引入了串連池,在執行任何查詢時,都會從串連池中請求一個串連,完成之後再歸還給串連池。這裡的完成是指持有該串連的變數離開了它的範圍,下面是一個樣本。

最簡單的版本:

demo->test;$c->insert( array( 'test' => 'yes' ) );?>

← $m離開範圍,串連歸還給串連池

在函數中:

demo->test;        $c->insert( array( 'test' => 'yes' ) );} // ← $m離開範圍,串連歸還給串連池?>

在某些情況下,系統可能會產生大量的串連,比如在ORMs/ODMs的某個複雜結構中引用連線物件,如下例子:

 

1.3版本的串連管理

在1.3版本中,串連管理做了很大改動。每個worker進程(線程、PHP-FPM或Apache worker)中,驅動把串連管理和Mongo*對象分離,降低驅動的複雜度。下面以單個節點的MongoDB執行個體來說明驅動如何處理串連。

當一個worker進程啟動,MongoDB驅動會為之初始化連線管理員管理串連,並且預設沒有串連。

在第一個請求調用new MongoClient();時,驅動建立一個新串連,並且以一個雜湊值標識這個串連。這個雜湊值包括以下參數:主機名稱、連接埠,進程ID和可選的 replica set名,如果是密碼驗證的串連,則還包括資料庫名、使用者名稱和密碼的雜湊值(對於密碼驗證的串連,我們後面再詳細討論)。調用 MongoClient::getConnections()方法,可以查看串連對應的雜湊值:

getConnections()[0]['hash'] );?>

輸出:

string(22) “whisky:27017;-;X;22835″

輸出中的”-”表示該串連不屬於某個replica set,”X”是沒有使用者名稱、資料庫和密碼時的預留位置,22835是當前進程的進程ID。

然後該串連會在連線管理員中註冊:

在需要串連的任何時候,包括插入、刪除、更新、尋找或執行命令,驅動都會向管理器請求一個合適的串連來執行。請求串連時會用到new MongoClient()的參數和當前進程的ID。每個worker進程/線程,連線管理員都會有一個串連列表,而每個PHP worker同一時刻,只會運行一個請求,因此和每個MongoDB之間只需要一個串連,不斷重用,直到PHP worker終止或顯式調用MongoClient::close()關閉串連。

Replica sets

在存在複製集的環境中,情形有點不一樣。new MongoClient()的連接字串中,需要指定多個hosts,並標示當前正在實用複製集:

$m = new MongoClient(“mongodb://whisky:13000,whisky:13001/?replicaSet=seta”);

其中的replicaSet參數不能省略,否則驅動會認為你是準備串連三個不同的mongos進程。

在執行個體化時,驅動會檢查複製集的拓撲結構。下面例子的輸出,顯示在調用new MongoClient()之後,複製集中所有可見的資料節點都會在管理器中註冊一個串連:

getConnections() as $c ){    echo $c['hash'], "\n";}?>

輸出:

whisky:13001;seta;X;32315 whisky:13000;seta;X;32315

雖然連接字串中沒有whisky:13000節點,但是管理器中已經註冊了兩個串連:

管理器不僅包含串連的雜湊值和TCP/IP socket,還儲存哪個節點是主節點,以及每個節點的“距離”。下面的指令碼顯示了這些額外的資訊;

getConnections() as $c ){    echo $c['hash'], ":\n",        " - {$c['connection']['connection_type_desc']}, ",        "{$c['connection']['ping_ms']} ms\n";}?>

輸出:

whisky:13001;seta;X;5776: ? SECONDARY, 1 ms whisky:13000;seta;X;5776: ? PRIMARY, 0 ms

驅動把操作分為兩種類型:寫操作,包括插入、更新、刪除和命令;讀操作,包括find和findOne。預設情況下,如果沒有設定讀偏好參數,管理器會一直返回主節點的串連。讀偏好參數可以通過setSlaveOkay()設定,也可以在連接字串中設定:

$m = new MongoClient("mongodb://whisky:13000,whisky:13001/?replicaSet=seta&readPreference=secondaryPreferred");

加上這些參數後,連接字串變得特別長,因此PHP驅動允許將選項放在數組中,作為第二個參數傳入:

$options = array(        'replicaSet' => 'seta',        'readPreference' => 'secondaryPreferred',);$m = new MongoClient("mongodb://whisky:13000,whisky:13001/", $options);

對於每個操作,驅動向管理器請求擷取一個合適的串連。對於寫操作,會一直返回主節點的串連;對於讀操作,如果輔助節點可用且“距離”不遠的話,則會返回該輔助節點的串連。

驗證的串連

如果MongoDB啟用驗證功能,那麼串連的雜湊值會包含驗證相關的雜湊值。這樣不同指令碼,使用不同的使用者名稱、密碼串連同一個MongoDB上的不 同的資料庫時,能夠相互區分,而不會誤用串連。下面樣本使用admin使用者名稱串連admin資料庫,然後觀察hash值的變化:

getConnections()[0]['hash'] );?>

輸出:

string(64) “whisky:27017;-;admin/admin/bda5cc70cd5c23f7ffa1fda978ecbD30;8697″

以前樣本中的”X”部分已經替換為一個包含資料庫名admin、使用者名稱admin和雜湊值bda5cc70cd5c23f7ffa1fda978ecbd30,該雜湊值是根據使用者名稱、資料庫名和密碼雜湊值計算得來。

為了驗證能夠正確工作,需要在連接字串中包含資料庫名,否則會預設為admin。

在建立串連後要使用資料庫,需要先選擇該資料庫,如:

$collection = $m->demoDb->collection; $collection->findOne();

如果選擇的資料庫是連接字串中指定的資料庫,或者連接字串中的資料庫是admin,那麼一切都會正常運行。否則,驅動會建立一個新的串連,從而防止驗證被繞過,如下所示:

test2;$collection = $db->collection;var_dump( $collection->findOne() );?>

輸出:

Fatal error: Uncaught exception ‘MongoCursorException’ with message ‘whisky:27017: unauthorized db:test2 ns:test2.collection lock type:0 client:127.0.0.1′ in …/mongo-connect-5.php.txt:6

因為我們的串連並沒有執行test2資料庫的授權驗證,因而失敗。如果我們執行驗證,就會正常運行:

test2;$db->authenticate('user2', 'user2' );$collection = $db->collection;$collection->findOne();foreach ( $m->getConnections() as $c ){    echo $c['hash'], "\n";}?>

輸出:

whisky:27017;-;test/user/602b672e2fdcda7b58a042aeeb034376;26983 whisky:27017;-;test2/user2/984b6b4fd6c33f49b73f026f8b47c0de;26983

現在管理器中有兩個已驗證的串連:

順便提一句,如果你開啟了E_DEPRECATED層級的錯誤提示,則會看到:

Deprecated: Function MongoDB::authenticate() is deprecated in …/mongo-connect-6.php.txt on line 5

驅動建議通過建立兩個MongoClient對象完成該類任務:

 false ) );$mTest2 = new MongoClient( 'mongodb://user2:user2@whisky:27017/test2', array( 'connect' => false ) );$mTest1->test->test->findOne();$mTest2->test2->test->findOne();foreach ( $mTest2->getConnections() as $c ){    echo $c['hash'], "\n";}?>

單個MongoDB伺服器能支援的並發串連相當有限,如果使用PHP-FPM的話,每個worker進程有自己獨立的串連池,那麼很容易達到串連數 的上限。因此,在生產環境中,不管有沒有使用複製集,都要部署mongos,然後PHP-FPM串連mongos,這樣可以減少mongod的串連數,並 且PHP-FPM和mongos之間可以使用短串連(即每個請求結束時都顯式調用close函數關閉MongoDB串連)。

來源:風之緣的部落格

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.