MongoDb Replica Set中使用的地址


Unable to connect to a member of the replica set matching the read preference Primary

今天嘗試使用MongoDB Replica Set提供的自動故障恢復功能一直無法成功,總是遇到上面這個錯誤。好一頓整終於找到的原因,由於這里還比較有迷惑性,特此記錄一下供其他人參考。

其實Google一下這個錯誤,在前幾條結果中就有答案,但是該死的GFW屏蔽了Google Group,導致我跳過了那條結果而一直沒有找到正確答案,我可以罵臟話嗎?

進入正題,我們知道使用Replica Set是要在連接字符串中加入所有結點的地址(建議這么做,但並不是強制。關於連接字符串參考這里)。以我為機器為例,我的Windows在虛擬機192.168.122.100上,MongoDB運行在物理機192.168.122.1中的三個實例上,分別是:

192.168.122.1:27017
192.168.122.1:27011
192.168.122.1:27012

因此我的連接字符串大概會是這個樣子(ReplicaSet為rs0):

mongodb://192.168.122.1,192.168.122.1:27011,192.168.122.1:27012/Cart?replicaSet=rs0

然后我到MongoDB的實例上建立了Replica Set:

yaoxing@YX-ARCH ~ $ mongo localhost
MongoDB shell version: 2.4.8
connecting to: test

>rs.initiate()

 

然后嘗試把其他兩個實例添加到Replica Set中:

rs.add("localhost:27011");
rs.add("localhost:27012");

發生了錯誤:

{
    "errmsg" : "exception: can't use localhost in repl set member names except when using it for all members",
    "code" : 13393,
    "ok" : 0
}

最容易想到的就是把localhost更換成機器名了,於是

rs.add("YX-ARCH:27011")
rs.add("YX-ARCH:27012")

成功,一切看起來都很美好,但其實問題就已經在這里發生了。如果嘗試關閉Primary,就會有另外一個實例從Secondary變為Primary,這點沒有問題。但客戶端始終會拋出本文開頭那個異常,無法自動切換到新的Primary上。原因如下:

如果仔細看MongoDB的文檔,你會發現其實在連接字符串中寫進所有的結點並不是必要的,但如果只寫一個結點的話,必須要加上?replicaSet=[set name]參數(原因參考文檔)。為什么可以只寫一個結點?因為當Driver連接上一個結點之后會從該結點獲取其他結點的信息,這樣做是為了以后動態添加新結點的時候Driver可以從結點信息中自動識別,而不必每次都修改連接字符串。當然如果只寫一個結點的話,壞處就是當這個結點掛了的時候Driver就不知道去哪找其他結點的信息了。

由此我們可以發現,有幾台服務器並不是從你的連接字符串中發現的,而是當Driver連接上某一台服務器后,從中獲取的。所以從以上的例子中獲取了什么東西?

rs0:PRIMARY> rs.conf()
{
    "_id" : "rs0",
    "version" : 7,
    "members" : [
        {
            "_id" : 0,
            "host" : "YX-ARCH:27017",
            "priority" : 20
        },
        {
            "_id" : 1,
            "host" : "YX-ARCH:27011",
            "priority" : 30
        },
        {
            "_id" : 2,
            "host" : "YX-ARCH:27012",
            "priority" : 20
        }
    ]
}

一共三個HOST

YX-ARCH
YX-ARCH:27011
YX-ARCH:27012

明眼人應該看出來了,YX-ARCH這個東西在我的虛擬機中不存在,因此C# Driver發現連接字符串最終無法連接到成為新Primary的YX-ARCH:27011,而唯一可以連接的192.168.122.1是Secondary身份,我又沒有指定readPreference,因此不可讀。悲劇就這么發生了。

當然知道了原因,解決方案也很簡單:

在replica set中和連接字符串中使用相同的HOST地址就可以完美解決問題

希望對遇到同樣問題的人有所幫助。


免責聲明!

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



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