日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MongoDB 分布式部署教程

發布時間:2024/4/17 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MongoDB 分布式部署教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文將介紹如何使用 MongoDB 提供的 Replica Set 和 Shards 功能構建一個分布式 MongoDB 集群。

Replica Set 部署

我們先從部署一個三節點的 Replica Set 開始。

首先,我們要為每個?mongod?實例創建它自己的?dbpath:

1
2
3
mkdir 1
mkdir 2
mkdir 3

然后,我們便可以開始啟動這三個?mongod?實例了:

1
2
3
mongod --dbpath 1 --port 27001 --replSet myRS
mongod --dbpath 2 --port 27002 --replSet myRS
mongod --dbpath 3 --port 27003 --replSet myRS

注意,這里我是為了在同一臺機器上運行三個?mongod?實例,所以需要為它們分別指定不同的端口。如果是真實的分布式 Replica Set,在每臺機器上使用默認的?27017?端口是完全可行的。

除此之外,我使用?--replSet?參數指定了?mongod?實例所屬 Replica Set 的名字。這個名字是可以隨意起的,但必須確保屬于同一個 Replica Set 的?mongod?實例設置了相同的?--replSet,否則可能會產生一些不可預期的后果。

在順利打開這些?mongod?實例后以后,不出意外的話我們應該能在輸出的日志信息中看到如下記錄:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2015-11-14T16:25:46.060+0800 I JOURNAL [initandlisten] journal dir=3\journal
2015-11-14T16:25:46.061+0800 I JOURNAL [initandlisten] recover : no journal files present, no recovery needed
2015-11-14T16:25:46.078+0800 I JOURNAL [durability] Durability thread started
2015-11-14T16:25:46.078+0800 I JOURNAL [journal writer] Journal writer thread started
2015-11-14T16:25:46.613+0800 I CONTROL [initandlisten] MongoDB starting : pid=9812 port=27003 dbpath=3 64-bit host=mrdai-Laptop
2015-11-14T16:25:46.613+0800 I CONTROL [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2
2015-11-14T16:25:46.613+0800 I CONTROL [initandlisten] db version v3.0.7
2015-11-14T16:25:46.614+0800 I CONTROL [initandlisten] git version: 6ce7cbe8c6b899552dadd907604559806aa2e9bd
2015-11-14T16:25:46.614+0800 I CONTROL [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
2015-11-14T16:25:46.614+0800 I CONTROL [initandlisten] allocator: tcmalloc
2015-11-14T16:25:46.614+0800 I CONTROL [initandlisten] options: { net: { port: 27003 }, replication: { replSet: "myRS" }, storage: { dbPath: "3" } }
2015-11-14T16:25:46.615+0800 I INDEX [initandlisten] allocating new ns file 3\local.ns, filling with zeroes...
2015-11-14T16:25:47.542+0800 I STORAGE [FileAllocator] allocating new datafile 3\local.0, filling with zeroes...
2015-11-14T16:25:47.543+0800 I STORAGE [FileAllocator] creating directory 3\_tmp
2015-11-14T16:25:47.544+0800 I STORAGE [FileAllocator] done allocating datafile 3\local.0, size: 64MB, took 0 secs
2015-11-14T16:25:47.551+0800 I REPL [initandlisten] Did not find local replica set configuration document at startup; NoMatchingDocument Did not find replica set configuration document in local.system.replset
2015-11-14T16:25:47.552+0800 I NETWORK [initandlisten] waiting for connections on port 27003

可以注意到,倒數第二條記錄顯示?mongod?未能在本地數據中找到 Replica Set 的設置信息。這是正常的,因為這是第一次創建的 Replica Set。最后一條信息顯示?mongod?啟動完畢,等待外界連接它的端口。

那么,我們開始啟動 Replica Set。使用?mongo?連入隨便一個?mongod?實例,并進行設置:

1
2
3
4
5
6
7
8
9
10
var conf = {
_id : "myRS",
members : [
{ _id : 1, host : "localhost:27001" },
{ _id : 2, host : "localhost:27002" },
{ _id : 3, host : "localhost:27003" }
]
}

rs.initiate(conf)

在?conf?中,我們將?_id?設置為 Replica Set 的名稱,并在?members?中設置了 Replica Set 所有成員的信息,其中包括成員的名稱?_id?以及成員的主機名?host。

注意,盡管這里可以直接使用了?IP:端口?的形式來指定?mongod?實例,但在真實環境中,不要這么做,這種做法十分糟糕。不過現在搭建分布式,大家的做法似乎更傾向于為每臺機器修改?hosts?文件。同樣,不要這么做,這兩種做法都屬于 bad practice。最好的做法,是在你的集群環境中配置一臺 DNS 服務器。這樣,當你的某一個結點的 IP 發生變化時,你就只需要修改 DNS 服務器中的那條解析條目,而不需要修改每個結點的?hosts?文件了。

直接以數字作為每個結點的名稱也是不好的做法,因為這個名稱在?mongod?的日志信息中會經常出現。使用更加可讀的名稱是更好的做法。

一切正常的話,你應該會在其中一個結點上看到如下日志信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2015-11-14T16:41:54.946+0800 I NETWORK [initandlisten] connection accepted from 127.0.0.1:61875 #1 (1 connection now open)
2015-11-14T16:41:54.951+0800 I NETWORK [conn1] end connection 127.0.0.1:61875 (0 connections now open)
2015-11-14T16:41:54.953+0800 I NETWORK [initandlisten] connection accepted from 127.0.0.1:61877 #2 (1 connection now open)
2015-11-14T16:41:55.013+0800 I NETWORK [initandlisten] connection accepted from 127.0.0.1:61882 #3 (2 connections now open)
2015-11-14T16:41:55.018+0800 I NETWORK [conn3] end connection 127.0.0.1:61882 (1 connection now open)
2015-11-14T16:41:55.078+0800 I REPL [WriteReplSetConfig] Starting replication applier threads
2015-11-14T16:41:55.082+0800 I REPL [ReplicationExecutor] New replica set config in use: { _id: "myRS", version: 1, members: [ { _id: 1, host: "localhost:27001", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 }, { _id: 2, host: "localhost:27002", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 }, { _id:3, host: "localhost:27003", arbiterOnly: false, buildIndexes: true, hidden: false, priority...(line truncated)...
2015-11-14T16:41:55.086+0800 I NETWORK [initandlisten] connection accepted from 127.0.0.1:61884 #4 (2 connections now open)
2015-11-14T16:41:55.115+0800 I REPL [ReplicationExecutor] This node is localhost:27003 in the config
2015-11-14T16:41:55.128+0800 I REPL [ReplicationExecutor] transition to STARTUP2
2015-11-14T16:41:55.134+0800 I REPL [rsSync] ******
2015-11-14T16:41:55.136+0800 I REPL [rsSync] creating replication oplog of size: 6172MB...
2015-11-14T16:41:55.137+0800 I STORAGE [FileAllocator] allocating new datafile 3\local.1, filling with zeroes...
2015-11-14T16:41:55.139+0800 I REPL [ReplicationExecutor] Member localhost:27001 is now in state STARTUP2
2015-11-14T16:41:55.151+0800 I STORAGE [FileAllocator] done allocating datafile 3\local.1, size: 2047MB, took 0.001 secs
2015-11-14T16:41:55.153+0800 I STORAGE [FileAllocator] allocating new datafile 3\local.2, filling with zeroes...
2015-11-14T16:41:55.161+0800 I STORAGE [FileAllocator] done allocating datafile 3\local.2, size: 2047MB, took 0.001 secs
2015-11-14T16:41:55.170+0800 I STORAGE [FileAllocator] allocating new datafile 3\local.3, filling with zeroes...
2015-11-14T16:41:55.171+0800 I REPL [ReplicationExecutor] Member localhost:27002 is now in state STARTUP2
2015-11-14T16:41:55.186+0800 I STORAGE [FileAllocator] done allocating datafile 3\local.3, size: 2047MB, took 0.001 secs
2015-11-14T16:41:56.198+0800 I REPL [rsSync] ******
2015-11-14T16:41:56.198+0800 I REPL [rsSync] initial sync pending
2015-11-14T16:41:56.200+0800 I REPL [rsSync] no valid sync sources found in current replset to do an initial sync
2015-11-14T16:41:57.139+0800 I REPL [ReplicationExecutor] Member localhost:27001 is now in state SECONDARY
2015-11-14T16:41:57.206+0800 I REPL [rsSync] initial sync pending
2015-11-14T16:41:57.206+0800 I REPL [ReplicationExecutor] syncing from: localhost:27001
2015-11-14T16:41:57.221+0800 I REPL [rsSync] initial sync drop all databases
2015-11-14T16:41:57.222+0800 I STORAGE [rsSync] dropAllDatabasesExceptLocal 1
2015-11-14T16:41:57.222+0800 I REPL [rsSync] initial sync clone all databases
2015-11-14T16:41:57.229+0800 I REPL [rsSync] initial sync data copy, starting syncup
2015-11-14T16:41:57.234+0800 I REPL [rsSync] oplog sync 1 of 3
2015-11-14T16:41:57.239+0800 I REPL [rsSync] oplog sync 2 of 3
2015-11-14T16:41:57.254+0800 I REPL [rsSync] initial sync building indexes
2015-11-14T16:41:57.258+0800 I REPL [rsSync] oplog sync 3 of 3
2015-11-14T16:41:57.265+0800 I REPL [rsSync] initial sync finishing up
2015-11-14T16:41:57.268+0800 I REPL [rsSync] replSet set minValid=5646f3d4:1
2015-11-14T16:41:57.274+0800 I REPL [rsSync] initial sync done
2015-11-14T16:41:57.290+0800 I REPL [ReplicationExecutor] transition to RECOVERING
2015-11-14T16:41:57.292+0800 I REPL [ReplicationExecutor] transition to SECONDARY
2015-11-14T16:41:58.136+0800 I REPL [ReplicationExecutor] could not find member to sync from
2015-11-14T16:41:58.971+0800 I REPL [ReplicationExecutor] replSetElect voting yea for localhost:27001 (1)
2015-11-14T16:41:59.140+0800 I REPL [ReplicationExecutor] Member localhost:27001 is now in state PRIMARY
2015-11-14T16:41:59.171+0800 I REPL [ReplicationExecutor] Member localhost:27002 is now in state SECONDARY

從日志中,我們可以很清晰地看到,發起?rs.initiate?的?mongod?向其他?mongod?開啟了連接,其他?mongod?獲取到了我們配置的?conf?信息。而后,Replica Set 開始啟動。首先是各結點進行初始化同步,從發起?rs.initiate?的?mongod?處同步了 oplog,并進入?Secondary?狀態。然后,3 個?Secondary?發現 Replica Set 中沒有?Primary,于是發起選舉。日志里,我們甚至可以看到這個?mongod?把票投給了誰。最后,選舉結束,localhost:27001?成為了?Primary。

使用 Java 驅動連接至 Replica Set

我們通過如下語句連接至單一的 MongoDB 實例:

1
MongoClient client = new MongoClient("localhost", 27001);

我們為?MongoClient?對象指定了一個 MongoDB 實例的主機名和端口號。以這種方式初始化的?MongoClient?會假設目標 MongoDB 實例只是一個 standalone 的實例,如果該實例不是?Primary?時,客戶端執行寫操作則可能被該 MongoDB 實例拒絕。

通過如下語句可使?MongoClient?進入 Replica Set 模式:

1
2
3
MongoClient client = new MongoClient(asList(
new ServerAddress("localhost", 27001)
));

我們通過?Arrays#asList?方法為?MongoClient?傳入了一個?List,MongoClient?便會進入 Replica Set 模式。在這種模式下,客戶端會利用給定的主機(seedlist)來發現 Replica Set 的其他所有結點,其中就包括了?Primary。因此,即使?localhost:27001?不是?Primary?也沒關系,客戶端會通過它獲知?Primary?的地址并自動連接至?Primary。

但以上做法仍不全面:如果?localhost:27001?進程已經掛了,或者它并不是 Replica Set 的成員,我們便無法通過上述語句連接至 Replica Set。 我們可以為構造函數傳入更多的 MongoDB 實例的地址來降低這種情況發生的幾率:

1
2
3
4
5
MongoClient client = new MongoClient(asList(
new ServerAddress("localhost", 27001),
new ServerAddress("localhost", 27002),
new ServerAddress("localhost", 27003)
));

當然,也有可能正好你指定的這多個結點都同時掛掉,那樣自然是防不勝防了。不過,提高 Replica Set 拓撲可用性就是網絡架構的問題了。當我們在執行寫操作時,我們還需要考慮?Primary?會突然掛掉。比如說,我們正在執行這樣的寫操作:

1
2
3
4
5
6
MongoCollection collection = client.getDatabase("foo").getCollection("bar");

for (int i = 0; i < Integer.MAX_VALUE; i++) {
collection.insertOne(new Document("_id", new ObjectId()).append("i", i));
Thread.sleep(500);
}

在執行插入時,如果?Primary?突然失效(如調用了?rs.stepDown()),那么上述代碼中的?insertOne?方法會拋出一個錯誤。因此,更為健壯的做法,是為該?insertOne?語句加上?try/catch?塊:

1
2
3
4
5
6
7
8
for (int i = 0; i < Integer.MAX_VALUE; i++) {
try {
collection.insertOne(new Document("_id", new ObjectId()).append("i", i));
} catch (MongoException e) {
// Handle the exception
}
Thread.sleep(500);
}

遺憾的是,拋出錯誤的?insertOne?操作恐怕無法由 MongoDB 驅動自動重試。實際上,不只是觸發錯誤的那一次操作,在 Replica Set 自動選舉出新的?Primary?前,所有寫操作都會拋出錯誤。但幸運的是,由于加上了?try/catch?塊,應用程序不會因為單次寫入失敗便直接退出。在觸發錯誤后,下一次插入前驅動都會重新嘗試利用 seedlist 來獲取新的?Primary?的地址。當 Replica Set 重新選舉出新的?Primary?后,驅動便可以再次進行寫操作了。

通過觀察 MongoDB Java 驅動輸出的日志信息,你可以更細致地觀察驅動的行為。這里就不直接給出了,有興趣可自己嘗試。

Shard 集群部署

在本節中,我們將會在本機上部署一個完整的生產級別的 MongoDB Shard 集群。集群由 4 個 Shard 負責存儲數據,其中每個 Shard 都是包含三個結點的 Replica Set。除此之外,集群還包括 4 個?mongos?和 3 個 Config Server。

注意,用于生產環境的 Shard 集群必須遵循如下幾個原則:必須使用 Replica Set 來作為 Shard,任何一個 Shard 的不可用都會導致集群出現異常;必須使用正好 3 個 Config Server,Config Server 不可用將導致整個集群不可用。除此之外,使用兩個以上的?mongos?實例可以更好地分散壓力。

4 個 Replica Set 的信息分別如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
_id : "a",
members : [
{ _id : "a1", host : "localhost:27001" },
{ _id : "a2", host : "localhost:27002" },
{ _id : "a3", host : "localhost:27003" }
]
}

{
_id : "b",
members : [
{ _id : "b1", host : "localhost:27101" },
{ _id : "b2", host : "localhost:27102" },
{ _id : "b3", host : "localhost:27103" }
]
}

{
_id : "c",
members : [
{ _id : "c1", host : "localhost:27201" },
{ _id : "c2", host : "localhost:27202" },
{ _id : "c3", host : "localhost:27203" }
]
}


{
_id : "d",
members : [
{ _id : "d1", host : "localhost:27301" },
{ _id : "d2", host : "localhost:27302" },
{ _id : "d3", host : "localhost:27303" }
]
}

集群各成員啟動

首先我們分別啟動集群的各個成員,分別是 Shard、Config Server 和 Query Router。其中前兩種成員均為?mongod,而 Query Router 則是?mongos。

單個 Replica Set 的配置方式大致上無太大變化,只是作為 Shard Server 在啟動?mongod?時需要加上–shardsvr選項。 以 Replica Set?a?為例:

1
2
3
4
5
mkdir a{1,2,3}

mongod --shardsvr --replSet a --dbpath a1 --logpath log.a1 --port 27001 --fork
mongod --shardsvr --replSet a --dbpath a2 --logpath log.a2 --port 27002 --fork
mongod --shardsvr --replSet a --dbpath a3 --logpath log.a3 --port 27003 --fork

注意:當?--shardsvr?選項被打開時,mongod?的默認端口號變為?27018

再使用?mongo?連接至任意一個?mongod?實例,啟動 Replica Set:

1
2
3
4
5
6
7
8
9
10
var conf = {
_id : "a",
members : [
{ _id : "a1", host : "localhost:27001" },
{ _id : "a2", host : "localhost:27002" },
{ _id : "a3", host : "localhost:27003" }
]
}

rs.initiate(conf)

重復上述操作即可啟動其余三個 Replica Set。

接下來開始啟動 Config Server:

1
2
3
4
5
mkdir cfg{1,2,3}

mongod --configsvr --dbpath cfg1 --logpath log.cfg1 --port 26050 --fork
mongod --configsvr --dbpath cfg2 --logpath log.cfg2 --port 26051 --fork
mongod --configsvr --dbpath cfg3 --logpath log.cfg3 --port 26052 --fork

注意:當?--configvr?選項被打開時,mongod?的默認端口號變為27019

最后,啟動 Query Router:

1
2
3
4
mongos --configdb localhost:26050,localhost:26051,localhost:26052 --logpath log.mongos1 --fork
mongos --configdb localhost:26050,localhost:26051,localhost:26052 --logpath log.mongos2 --port 26061 --fork
mongos --configdb localhost:26050,localhost:26051,localhost:26052 --logpath log.mongos3 --port 26062 --fork
mongos --configdb localhost:26050,localhost:26051,localhost:26052 --logpath log.mongos4 --port 26063 --fork

注意:mongos?的默認端口號為27017,與?mongod?、?mongo?的默認端口號相同。

如此一來,集群的各個成員都啟動完畢了,可以開始配置集群了。

添加 Shard

實際上,在啟動?mongos?時,我們已經指定了集群所使用的 Config Server 的地址。接下來就是為集群指定每個 Shard 的地址了。

打開?mongo?連接至任意一個?mongos,并執行如下指令:

1
2
3
4
sh.addShard("a/localhost:27001")
sh.addShard("b/localhost:27101")
sh.addShard("c/localhost:27201")
sh.addShard("d/localhost:27301")

注意到,我們添加 Shard 時,輸入了 Replica Set 的名稱以及其中一個成員的地址。該成員并不一定得是?Primary,只要它是該 Replica Set 的成員,mongos?就能自動發現 Replica Set 的其他所有成員。

在添加了 4 個 Shard 以后,整個 Shard 集群便配置完畢,可以開始使用了。

?

from:?https://mr-dai.github.io/mongodb_distribution_tutorial/

總結

以上是生活随笔為你收集整理的MongoDB 分布式部署教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。