手把手教你 MongoDB 的安裝與詳細使用(二)

上一篇文章練習了,MongoDB 的以下操作

  • 安裝 MongoDB 服務
  • 連接 MongoDB
  • MongoDB 創建資料庫
  • MongoDB 刪除資料庫
  • MongoDB 插入文檔
  • MongoDB 刪除文檔
  • MongoDB 查詢文檔
  • MongoDB AND 條件
  • MongoDB OR 條件
  • MongoDB AND 和 OR 聯合使用
  • MongoDB 條件操作符
  • MongoDB (>) 大於操作符 - $gt
  • MongoDB(>=)大於等於操作符 - $gte
  • MongoDB (<) 小於操作符 - $lt
  • MongoDB (<=) 小於操作符 - $lte
  • MongoDB 使用 (<) 和 (>) 查詢 - $lt 和 $gt

手把手教你 MongoDB 的安裝與詳細使用(一)

ymq.io/2018/01/29/Mongo

接下來繼續

  1. MongoDB Limit與Skip方法
  2. MongoDB 排序
  3. MongoDB 索引
  4. MongoDB 聚合
  5. MongoDB 主從複製(副本集)
  6. MongoDB 自動故障轉移

1. MongoDB Limit與Skip方法

Limit() 方法

MongoDB Limit() 方法

如果你需要在MongoDB中讀取指定數量的數據記錄,可以使用MongoDB的Limit方法,limit()方法接受一個數字參數,該參數指定從MongoDB中讀取的記錄條數。

插入測試數據

db.col.insert({title: MongoDB-1})ndb.col.insert({title: MongoDB-2})ndb.col.insert({title: MongoDB-3})ndb.col.insert({title: MongoDB-4})nMongoDB Enterprise > db.col.find()n{ "_id" : ObjectId("5a6e8eaef14a3f270ba2dd0c"), "title" : "MongoDB-1" }n{ "_id" : ObjectId("5a6e8ec8f14a3f270ba2dd0d"), "title" : "MongoDB-2" }n{ "_id" : ObjectId("5a6e8ecbf14a3f270ba2dd0e"), "title" : "MongoDB-3" }n{ "_id" : ObjectId("5a6e8ed5f14a3f270ba2dd0f"), "title" : "MongoDB-4" }nMongoDB Enterprise >n

語法

limit()方法基本語法如下所示:

> db.COLLECTION_NAME.find().limit(NUMBER)n

以上實例為顯示查詢文檔中的兩條記錄:

MongoDB Enterprise > db.col.find().limit(2)n{ "_id" : ObjectId("5a6e8eaef14a3f270ba2dd0c"), "title" : "MongoDB-1" }n{ "_id" : ObjectId("5a6e8ec8f14a3f270ba2dd0d"), "title" : "MongoDB-2" }nMongoDB Enterprise > db.col.find({},{"title":1,_id:0}).limit(2)n{ "title" : "MongoDB-1" }n{ "title" : "MongoDB-2" }nMongoDB Enterprise >n

註:如果你們沒有指定limit()方法中的參數則顯示集合中的所有數據。

MongoDB Enterprise > db.col.find({},{"title":1,_id:0}).limit()n{ "title" : "MongoDB-1" }n{ "title" : "MongoDB-2" }n{ "title" : "MongoDB-3" }n{ "title" : "MongoDB-4" }n

Skip() 方法

我們除了可以使用limit()方法來讀取指定數量的數據外,還可以使用skip()方法來跳過指定數量的數據,skip方法同樣接受一個數字參數作為跳過的記錄條數。 語法

skip() 方法腳本語法格式如下:

> db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)n

實例

以上實例只會顯示第二條文檔數據

MongoDB Enterprise > db.col.find({},{"title":1,_id:0}).limit(1).skip(1)n{ "title" : "MongoDB-2" }nMongoDB Enterprise >n

注:skip()方法默認參數為 0

2. MongoDB 排序

MongoDB sort()方法

在MongoDB中使用使用sort()方法對數據進行排序,sort()方法可以通過參數指定排序的欄位

使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而-1是用於降序排列。

語法

sort()方法基本語法如下所示:

> db.COLLECTION_NAME.find().sort({KEY:1})n

col 集合中的數據如下:

MongoDB Enterprise > db.col.find()n{ "_id" : ObjectId("5a6e8eaef14a3f270ba2dd0c"), "title" : "MongoDB-1" }n{ "_id" : ObjectId("5a6e8ec8f14a3f270ba2dd0d"), "title" : "MongoDB-2" }n{ "_id" : ObjectId("5a6e8ecbf14a3f270ba2dd0e"), "title" : "MongoDB-3" }n{ "_id" : ObjectId("5a6e8ed5f14a3f270ba2dd0f"), "title" : "MongoDB-4" }nMongoDB Enterprise >n

其中 1 為升序排列,而-1是用於降序排列

以下實例演示了 col 集合中的數據按欄位 title 的降序排列:

MongoDB Enterprise > db.col.find({},{"title":1,_id:0}).sort({"title":-1})n{ "title" : "MongoDB-4" }n{ "title" : "MongoDB-3" }n{ "title" : "MongoDB-2" }n{ "title" : "MongoDB-1" }nMongoDB Enterprise >n

註: 如果沒有指定sort()方法的排序方式,默認按照文檔的升序排列。

3. MongoDB 索引

索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數據時必須掃描集合中的每個文件並選取那些符合查詢條件的記錄。

這種掃描全集合的查詢效率是非常低的,特別在處理大量的數據時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常致命的。

索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對資料庫表中一列或多列的值進行排序的一種結構

ensureIndex() 方法

MongoDB使用 ensureIndex() 方法來創建索引。

語法

ensureIndex()方法基本語法格式如下所示:

> db.COLLECTION_NAME.ensureIndex({KEY:1})n

語法中 Key 值為你要創建的索引欄位,1為指定按升序創建索引,如果你想按降序來創建索引指定為-1即可。

實例

> db.COLLECTION_NAME.ensureIndex({KEY:1})n

語法中 Key 值為你要創建的索引欄位,1為指定按升序創建索引,如果你想按降序來創建索引指定為-1即可。

實例

MongoDB Enterprise > db.col.ensureIndex({"title":1})n{nt"createdCollectionAutomatically" : false,nt"numIndexesBefore" : 1,nt"numIndexesAfter" : 2,nt"ok" : 1n}nMongoDB Enterprise >ndb.col.insert({title: MongoDB 教程, n description: MongoDB 是一個 Nosql 資料庫,n by: 搜雲庫教程-專註於開發技術的研究與知識分享,n url: http://www.souyunku.com,n tags: [mongodb, database, NoSQL],n likes: 100n})n

ensureIndex() 方法中你也可以設置使用多個欄位創建索引(關係型資料庫中稱作複合索引)。

MongoDB Enterprise > db.col.ensureIndex({"title":1,"description":1})n{nt"createdCollectionAutomatically" : false,nt"numIndexesBefore" : 3,nt"numIndexesAfter" : 4,nt"ok" : 1n}n

ensureIndex() 接收可選參數,可選參數列表如下:

實例

在後台創建索引:

建索引過程會阻塞其它資料庫操作,background可指定以後台方式創建索引,即增加 "background" 可選參數。 "background" 默認值為false。

MongoDB Enterprise > db.col.ensureIndex({"url":1}, {background: true})n{nt"createdCollectionAutomatically" : false,nt"numIndexesBefore" : 5,nt"numIndexesAfter" : 6,nt"ok" : 1n}nMongoDB Enterprise >n

4. MongoDB 聚合

MongoDB 聚合

MongoDB中聚合(aggregate)主要用於處理數據(諸如統計平均值,求和等),並返回計算後的數據結果。有點類似sql語句中的 count(*)。

aggregate() 方法

刪除之前的測試數據

MongoDB Enterprise > db.col.remove({})nWriteResult({ "nRemoved" : 5 })nMongoDB Enterprise >n

插入新的測試數據

db.col.insert({nttitle: MongoDB 教程,ntdescription: MongoDB 是一個 Nosql 資料庫,ntby_user: penglei,nturl: http://www.souyunku.com,nttags: [mongodb, database, NoSQL],ntlikes: 100n})ndb.col.insert({nttitle: MongoDB 教程,ntdescription: MongoDB 是一個 Nosql 資料庫,ntby_user: penglei,nturl: http://www.souyunku.com,nttags: [mongodb, database, NoSQL],ntlikes: 200n})ndb.col.insert({nttitle: MongoDB 教程,ntdescription: MongoDB 是一個 Nosql 資料庫,ntby_user: penglei,nturl: http://www.souyunku.com,nttags: [mongodb, database, NoSQL],ntlikes: 300n})nMongoDB Enterprise > db.col.find()n{ "_id" : ObjectId("5a6ebfab5326a260464a4072"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 資料庫", "by_user" : "penglei", "url" : "http://www.souyunku.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }n{ "_id" : ObjectId("5a6ebfab5326a260464a4073"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 資料庫", "by_user" : "penglei", "url" : "http://www.souyunku.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 200 }n{ "_id" : ObjectId("5a6ebfab5326a260464a4074"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 資料庫", "by_user" : "penglei", "url" : "http://www.souyunku.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 300 }nMongoDB Enterprise >n

MongoDB中聚合的方法使用aggregate()。

語法

aggregate() 方法的基本語法格式如下所示:

> db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)n

MongoDB Enterprise > db.col.aggregate([{$group : {_id : "$by_user", num_tutorials : {$sum : 1}}}])n{nt"_id": "penglei",nt"num_tutorials": 3n}nMongoDB Enterprise > db.col.aggregate([{$group : {_id : "$by_user", totle : {$sum : 1}}}])n{nt"_id": "penglei",nt"totle": 3n}nMongoDB Enterprise >n

以上實例類似sql語句:select by_user, count(*) from col group by by_user

在上面的例子中,我們通過欄位by_user欄位對數據進行分組,並計算by_user欄位相同值的總和。

下表展示了一些聚合的表達式:

管道的概念

管道在Unix和Linux中一般用於將當前命令的輸出結果作為下一個命令的參數。

MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理。管道操作是可以重複的。

表達式:處理輸入文檔並輸出。表達式是無狀態的,只能用於計算當前聚合管道的文檔,不能處理其它的文檔。

這裡我們介紹一下聚合框架中常用的幾個操作:

  • $project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用於創建計算結果以及嵌套文檔。
  • $match:用於過濾數據,只輸出符合條件的文檔。$match使用MongoDB的標準查詢操作。
  • $limit:用來限制MongoDB聚合管道返回的文檔數。
  • $skip:在聚合管道中跳過指定數量的文檔,並返回餘下的文檔。
  • $unwind:將文檔中的某一個數組類型欄位拆分成多條,每條包含數組中的一個值。
  • $group:將集合中的文檔分組,可用於統計結果。
  • $sort:將輸入文檔排序後輸出。
  • $geoNear:輸出接近某一地理位置的有序文檔。

管道操作符實例

1、$project實例

MongoDB Enterprise > db.col.aggregate(n { $project : {n title : 1 ,n by_user : 1 ,n }}n );n n{ "_id" : ObjectId("5a6ebfab5326a260464a4072"), "title" : "MongoDB 教程", "by_user" : "penglei" }n{ "_id" : ObjectId("5a6ebfab5326a260464a4073"), "title" : "MongoDB 教程", "by_user" : "penglei" }n{ "_id" : ObjectId("5a6ebfab5326a260464a4074"), "title" : "MongoDB 教程", "by_user" : "penglei" }nMongoDB Enterprise >n

這樣的話結果中就只還有_id,tilte和by_user三個欄位了,默認情況下_id欄位是被包含的,如果要想不包含_id話可以這樣:

MongoDB Enterprise > db.col.aggregate(n { $project : {n _id : 0 ,n title : 1 ,n by_user : 1n }});n{ "title" : "MongoDB 教程", "by_user" : "penglei" }n{ "title" : "MongoDB 教程", "by_user" : "penglei" }n{ "title" : "MongoDB 教程", "by_user" : "penglei" }n

2.$match實例

db.col.aggregate( [ntttt{ $match : { likes : { $gt : 90, $lte : 200 } } },ntttt{ $group: { _id: null, count: { $sum: 1 } } }nttt ] );n

$match用於獲取 likes 大於70小於或等於90記錄,然後將符合條件的記錄送到下一階段$group管道操作符進行處理。

MongoDB Enterprise > db.col.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])n{ "_id" : "penglei", "num_tutorial" : 3 }nMongoDB Enterprise >n

以上實例類似sql語句:

select by_user as _id, count(*) as num_tutorial from mycol group by by_usern

按日、按月、按年、按周、按小時、按分鐘聚合操作如下:

db.getCollection(m_msg_tb).aggregate(n[n {$match:{m_id:10001,mark_time:{$gt:new Date(2017,8,0)}}},n {$group: {n _id: {$dayOfMonth:$mark_time},n pv: {$sum: 1}n }n },n {$sort: {"_id": 1}}n])n

時間關鍵字如下:

  • $dayOfYear: 返回該日期是這一年的第幾天(全年 366 天)。
  • $dayOfMonth: 返回該日期是這一個月的第幾天(1到31)。
  • $dayOfWeek: 返回的是這個周的星期幾(1:星期日,7:星期六)。
  • $year: 返回該日期的年份部分。
  • $month: 返回該日期的月份部分( 1 到 12)。
  • $week: 返回該日期是所在年的第幾個星期( 0 到 53)。
  • $hour: 返回該日期的小時部分。
  • $minute: 返回該日期的分鐘部分。
  • $second: 返回該日期的秒部分(以0到59之間的數字形式返回日期的第二部分,但可以是60來計算閏秒)。
  • $millisecond:返回該日期的毫秒部分( 0 到 999)。
  • $dateToString: { $dateToString: { format: , date: } }。

5. MongoDB 主從複製(副本集)

MongoDB複製是將數據同步在多個伺服器的過程。

複製提供了數據的冗餘備份,並在多個伺服器上存儲數據副本,提高了數據的可用性, 並可以保證數據的安全性。

複製還允許您從硬體故障和服務中斷中恢複數據。

官方文檔 docs.mongodb.com/manual

5.1 什麼是複製?

  • 保障數據的安全性
  • 數據高可用性 (24*7)
  • 災難恢復
  • 無需停機維護(如備份,重建索引,壓縮)
  • 分散式讀取數據

5.2 MongoDB複製原理

mongodb的複製至少需要兩個節點。其中一個是主節點,負責處理客戶端請求,其餘的都是從節點,負責複製主節點上的數據。

mongodb各個節點常見的搭配方式為:一主一從、一主多從。

主節點記錄在其上的所有操作oplog,從節點定期輪詢主節點獲取這些操作,然後對自己的數據副本執行這些操作,從而保證從節點的數據與主節點一致。

MongoDB複製結構圖如下所示:

以上結構圖中,客戶端從主節點讀取數據,在客戶端寫入數據到主節點時, 主節點與從節點進行數據交互保障數據的一致性。

5.3 副本集特徵

  • N 個節點的集群
  • 任何節點可作為主節點
  • 所有寫入操作都在主節點上
  • 自動故障轉移
  • 自動恢復

5.4 MongoDB副本集設置

1、關閉正在運行的MongoDB伺服器。

service mongod stopn

2.節點建點

首先需要去你選擇的mongodb數據文件存放的文件夾新建三個資料庫,用來模擬三台不通的機器,博主的路徑如下

mkdir -p /data/db/node1nmkdir -p /data/db/node2nmkdir -p /data/db/node3n

3.啟動三個資料庫(dbpath),並且埠(--port 1000x),集群名稱(--replSet gabriel),關閉日誌選項(--nojournal),守護進程方式啟動,會自動拉起(--fork),日誌目錄(--logpath)

mongod --dbpath /data/db/node1 --port 10001 --replSet gabriel --nojournal --fork --logpath /data/db/node1.lognmongod --dbpath /data/db/node2 --port 10002 --replSet gabriel --nojournal --fork --logpath /data/db/node2.lognmongod --dbpath /data/db/node3 --port 10003 --replSet gabriel --nojournal --fork --logpath /data/db/node3.logn

4.順便連接一個伺服器,做初始化操作,這裡博主連入10001埠

終端下進入

mongo localhost:10001n

進入後輸入初始化方法

MongoDB Enterprise gabriel:OTHER> rs.initiate({_id:"gabriel",members:[n{_id:1,host:"localhost:10001"},n{_id:2,host:"localhost:10002"},n{_id:3,host:"localhost:10003"},n]})n

收到如下信息就成功了。

{nt"ok" : 1,nt"operationTime" : Timestamp(1517221411, 1),nt"$clusterTime" : {ntt"clusterTime" : Timestamp(1517221411, 1),ntt"signature" : {nttt"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),nttt"keyId" : NumberLong(0)ntt}nt}n}nMongoDB Enterprise gabriel:OTHER>n

此時會發現終端上的輸出已經有了變化。

//從單個一個n>n//變成了ngabriel:OTHER>n

5.查詢狀態

MongoDB Enterprise gabriel:OTHER> rs.status()n{nt"set" : "gabriel",nt"date" : ISODate("2018-01-29T10:33:21.227Z"),nt"myState" : 1,nt"term" : NumberLong(1),nt"heartbeatIntervalMillis" : NumberLong(2000),nt"optimes" : {ntt"lastCommittedOpTime" : {nttt"ts" : Timestamp(1517221984, 1),nttt"t" : NumberLong(1)ntt},ntt"readConcernMajorityOpTime" : {nttt"ts" : Timestamp(1517221984, 1),nttt"t" : NumberLong(1)ntt},ntt"appliedOpTime" : {nttt"ts" : Timestamp(1517221994, 1),nttt"t" : NumberLong(1)ntt},ntt"durableOpTime" : {nttt"ts" : Timestamp(1517221994, 1),nttt"t" : NumberLong(1)ntt}nt},nt"members" : [ntt{nttt"_id" : 1,nttt"name" : "localhost:10001",nttt"health" : 1,nttt"state" : 1,nttt"stateStr" : "PRIMARY",nttt"uptime" : 659,nttt"optime" : {ntttt"ts" : Timestamp(1517221994, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDate" : ISODate("2018-01-29T10:33:14Z"),nttt"electionTime" : Timestamp(1517221422, 1),nttt"electionDate" : ISODate("2018-01-29T10:23:42Z"),nttt"configVersion" : 1,nttt"self" : truentt},ntt{nttt"_id" : 2,nttt"name" : "localhost:10002",nttt"health" : 1,nttt"state" : 2,nttt"stateStr" : "SECONDARY",nttt"uptime" : 589,nttt"optime" : {ntttt"ts" : Timestamp(1517221994, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDurable" : {ntttt"ts" : Timestamp(1517221984, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDate" : ISODate("2018-01-29T10:33:14Z"),nttt"optimeDurableDate" : ISODate("2018-01-29T10:33:04Z"),nttt"lastHeartbeat" : ISODate("2018-01-29T10:33:20.972Z"),nttt"lastHeartbeatRecv" : ISODate("2018-01-29T10:33:19.923Z"),nttt"pingMs" : NumberLong(0),nttt"syncingTo" : "localhost:10001",nttt"configVersion" : 1ntt},ntt{nttt"_id" : 3,nttt"name" : "localhost:10003",nttt"health" : 1,nttt"state" : 2,nttt"stateStr" : "SECONDARY",nttt"uptime" : 589,nttt"optime" : {ntttt"ts" : Timestamp(1517221994, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDurable" : {ntttt"ts" : Timestamp(1517221984, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDate" : ISODate("2018-01-29T10:33:14Z"),nttt"optimeDurableDate" : ISODate("2018-01-29T10:33:04Z"),nttt"lastHeartbeat" : ISODate("2018-01-29T10:33:20.972Z"),nttt"lastHeartbeatRecv" : ISODate("2018-01-29T10:33:19.921Z"),nttt"pingMs" : NumberLong(0),nttt"syncingTo" : "localhost:10001",nttt"configVersion" : 1ntt}nt],nt"ok" : 1,nt"operationTime" : Timestamp(1517221994, 1),nt"$clusterTime" : {ntt"clusterTime" : Timestamp(1517221994, 1),ntt"signature" : {nttt"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),nttt"keyId" : NumberLong(0)ntt}nt}n}n

在返回中,參數set後面為集群名稱,每個members下面可以看到他們各自的情況,其中stateStr是角色,主節點為(PRIMARY)。

6.進入主節點插入數據,進入從節點查看數據

博主主節點在10001介面

mongo localhost:10001n

插入數據

MongoDB Enterprise gabriel:PRIMARY> use testnswitched to db testndb.col.insert({title: MongoDB 教程, n description: MongoDB 是一個 Nosql 資料庫,n by: 搜雲庫教程-專註於開發技術的研究與知識分享,n url: http://www.souyunku.com,n tags: [mongodb, database, NoSQL],n likes: 100n})nMongoDB Enterprise gabriel:PRIMARY> db.col.find()n{ "_id" : ObjectId("5a6ef998525d903d07a00cdf"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 資料庫", "by" : "搜雲庫教程-專註於開發技術的研究與知識分享", "url" : "http://www.souyunku.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }nMongoDB Enterprise gabriel:PRIMARY>n

博主切換從節點10002

mongo localhost:10002n

切換到從節點,你會發現使用show dbs 會報錯,是因為還沒有開啟許可權,輸入rs.slaveOk();就可以順利訪問了。

MongoDB Enterprise gabriel:SECONDARY> show dbsn2018-01-29T10:40:37.362+0000 E QUERY [thread1] Error: listDatabases failed:{nt"operationTime" : Timestamp(1517222434, 1),nt"ok" : 0,nt"errmsg" : "not master and slaveOk=false",nt"code" : 13435,nt"codeName" : "NotMasterNoSlaveOk",nt"$clusterTime" : {ntt"clusterTime" : Timestamp(1517222434, 1),ntt"signature" : {nttt"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),nttt"keyId" : NumberLong(0)ntt}nt}n} :n_getErrorWithCode@src/mongo/shell/utils.js:25:13nMongo.prototype.getDBs@src/mongo/shell/mongo.js:65:1nshellHelper.show@src/mongo/shell/utils.js:813:19nshellHelper@src/mongo/shell/utils.js:703:15n@(shellhelp2):1:1nMongoDB Enterprise gabriel:SECONDARY>nMongoDB Enterprise gabriel:SECONDARY> rs.slaveOk()n

再次查看

MongoDB Enterprise gabriel:SECONDARY> show dbsnadmin 0.000GBnconfig 0.000GBnlocal 0.000GBntest 0.000GBnMongoDB Enterprise gabriel:SECONDARY>n

切到test 庫,查看數據已經同步過來了

MongoDB Enterprise gabriel:SECONDARY> use testnswitched to db testnMongoDB Enterprise gabriel:SECONDARY> db.col.find()n{ "_id" : ObjectId("5a6ef998525d903d07a00cdf"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 資料庫", "by" : "搜雲庫教程-專註於開發技術的研究與知識分享", "url" : "http://www.souyunku.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }nMongoDB Enterprise gabriel:SECONDARY>n

以上就是簡單的主從複製建立過程,現在已經可以在從伺服器看到主伺服器插入的數據了。

切換從節點10003 一樣的問題

刪除從節點

rs.remove(ip:port)n

關閉主伺服器後,再重新啟動,會發現原來的從伺服器變為了從伺服器,新啟動的伺服器(原來的從伺服器)變為了從伺服器

6. MongoDB 自動故障轉移

首先通過 rs.status() 查看,可以看到主節點是10001,主節點"name" : "localhost:10001", "stateStr" : "PRIMARY" 接下來停止 10001 主節點,測試故障切換

MongoDB Enterprise gabriel:PRIMARY> rs.status()n{nt"set" : "gabriel",nt"date" : ISODate("2018-01-30T02:39:58.468Z"),nt"myState" : 1,nt"term" : NumberLong(1),nt"heartbeatIntervalMillis" : NumberLong(2000),nt"optimes" : {ntt"lastCommittedOpTime" : {nttt"ts" : Timestamp(1517279986, 1),nttt"t" : NumberLong(1)ntt},ntt"readConcernMajorityOpTime" : {nttt"ts" : Timestamp(1517279986, 1),nttt"t" : NumberLong(1)ntt},ntt"appliedOpTime" : {nttt"ts" : Timestamp(1517279996, 1),nttt"t" : NumberLong(1)ntt},ntt"durableOpTime" : {nttt"ts" : Timestamp(1517279996, 1),nttt"t" : NumberLong(1)ntt}nt},nt"members" : [ntt{nttt"_id" : 1,nttt"name" : "localhost:10001",nttt"health" : 1,nttt"state" : 1,nttt"stateStr" : "PRIMARY",nttt"uptime" : 58656,nttt"optime" : {ntttt"ts" : Timestamp(1517279996, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDate" : ISODate("2018-01-30T02:39:56Z"),nttt"electionTime" : Timestamp(1517221422, 1),nttt"electionDate" : ISODate("2018-01-29T10:23:42Z"),nttt"configVersion" : 1,nttt"self" : truentt},ntt{nttt"_id" : 2,nttt"name" : "localhost:10002",nttt"health" : 1,nttt"state" : 2,nttt"stateStr" : "SECONDARY",nttt"uptime" : 58586,nttt"optime" : {ntttt"ts" : Timestamp(1517279996, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDurable" : {ntttt"ts" : Timestamp(1517279986, 1),ntttt"t" : NumberLong(1)nttt},nttt"optimeDate" : ISODate("2018-01-30T02:39:56Z"),nttt"optimeDurableDate" : ISODate("2018-01-30T02:39:46Z"),nttt"lastHeartbeat" : ISODate("2018-01-30T02:39:58.289Z"),nttt"lastHeartbeatRecv" : ISODate("2018-01-30T02:39:57.220Z"),nttt"pingMs" : NumberLong(0),nttt"syncingTo" : "localhost:10001",nttt"configVersion" : 1ntt},ntt{nttt"_id" : 3,nttt"name" : "localhost:10003",nttt"health" : 0,nttt"state" : 8,nttt"stateStr" : "(not reachable/healthy)",nttt"uptime" : 0,nttt"optime" : {ntttt"ts" : Timestamp(0, 0),ntttt"t" : NumberLong(-1)nttt},nttt"optimeDurable" : {ntttt"ts" : Timestamp(0, 0),ntttt"t" : NumberLong(-1)nttt},nttt"optimeDate" : ISODate("1970-01-01T00:00:00Z"),nttt"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),nttt"lastHeartbeat" : ISODate("2018-01-30T02:39:58.304Z"),nttt"lastHeartbeatRecv" : ISODate("2018-01-30T02:39:21.208Z"),nttt"pingMs" : NumberLong(0),nttt"lastHeartbeatMessage" : "Connection refused",nttt"configVersion" : -1ntt}nt],nt"ok" : 1,nt"operationTime" : Timestamp(1517279996, 1),nt"$clusterTime" : {ntt"clusterTime" : Timestamp(1517279996, 1),ntt"signature" : {nttt"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),nttt"keyId" : NumberLong(0)ntt}nt}n}nMongoDB Enterprise gabriel:PRIMARY>n

連接到主節點

mongo localhost:10001n

關閉主節點

mongo localhost:10001n

顯示所有資料庫

MongoDB Enterprise gabriel:PRIMARY> show dbsnadmin 0.000GBnconfig 0.000GBnlocal 0.000GBntest 0.000GBn

切換到admin

MongoDB Enterprise gabriel:PRIMARY> use adminnswitched to db adminn

停止資料庫,必須進入 admin 庫

MongoDB Enterprise gabriel:PRIMARY> db.shutdownServer()n

響應

2018-01-30T02:51:34.503+0000 I NETWORK [thread1] trying reconnect to localhost:10001 (127.0.0.1) failedn2018-01-30T02:51:35.398+0000 I NETWORK [thread1] Socket recv() Connection reset by peer 127.0.0.1:10001n2018-01-30T02:51:35.398+0000 I NETWORK [thread1] SocketException: remote: (NONE):0 error: SocketException socket exception [RECV_ERROR] server [127.0.0.1:10001] n2018-01-30T02:51:35.399+0000 I NETWORK [thread1] reconnect localhost:10001 (127.0.0.1) failed failed n2018-01-30T02:51:35.404+0000 I NETWORK [thread1] trying reconnect to localhost:10001 (127.0.0.1) failedn2018-01-30T02:51:35.404+0000 W NETWORK [thread1] Failed to connect to 127.0.0.1:10001, in(checking socket for error after poll), reason: Connection refusedn2018-01-30T02:51:35.404+0000 I NETWORK [thread1] reconnect localhost:10001 (127.0.0.1) failed failed nMongoDB Enterprise >n

查看是否真的停止了,發現已經沒有10001 節點進程了

root@souyunku-2:# ps -ef | grep mongonroot 5554 1 0 Jan29 ? 00:03:34 mongod --dbpath /data/db/node2 --port 10002 --replSet gabriel --nojournal --fork --logpath /data/db/node2.lognroot 12284 1 0 02:43 ? 00:00:02 mongod --dbpath /data/db/node3 --port 10003 --replSet gabriel --nojournal --fork --logpath /data/db/node3.lognroot 12436 5132 0 02:53 pts/1 00:00:00 grep --color=auto mongonroot@souyunku-2:# netstat -nltpnActive Internet connections (only servers)nProto Recv-Q Send-Q Local Address Foreign Address State PID/Program namentcp 0 0 127.0.0.1:10002 0.0.0.0:* LISTEN 5554/mongod ntcp 0 0 127.0.0.1:10003 0.0.0.0:* LISTEN 12284/mongod nroot@souyunku-2:/data/db#n

查看是否故障專業

root@souyunku-2:# mongo localhost:10001n

查看主從狀態

MongoDB Enterprise gabriel:SECONDARY> rs.status()n{nt"set" : "gabriel",nt"date" : ISODate("2018-01-30T02:56:48.074Z"),nt"myState" : 2,nt"term" : NumberLong(2),nt"syncingTo" : "localhost:10003",nt"heartbeatIntervalMillis" : NumberLong(2000),nt"optimes" : {ntt"lastCommittedOpTime" : {nttt"ts" : Timestamp(1517280995, 1),nttt"t" : NumberLong(2)ntt},ntt"readConcernMajorityOpTime" : {nttt"ts" : Timestamp(1517280995, 1),nttt"t" : NumberLong(2)ntt},ntt"appliedOpTime" : {nttt"ts" : Timestamp(1517281005, 1),nttt"t" : NumberLong(2)ntt},ntt"durableOpTime" : {nttt"ts" : Timestamp(1517280995, 1),nttt"t" : NumberLong(2)ntt}nt},nt"members" : [ntt{nttt"_id" : 1,nttt"name" : "localhost:10001",nttt"health" : 0,nttt"state" : 8,nttt"stateStr" : "(not reachable/healthy)",nttt"uptime" : 0,nttt"optime" : {ntttt"ts" : Timestamp(0, 0),ntttt"t" : NumberLong(-1)nttt},nttt"optimeDurable" : {ntttt"ts" : Timestamp(0, 0),ntttt"t" : NumberLong(-1)nttt},nttt"optimeDate" : ISODate("1970-01-01T00:00:00Z"),nttt"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),nttt"lastHeartbeat" : ISODate("2018-01-30T02:56:47.605Z"),nttt"lastHeartbeatRecv" : ISODate("2018-01-30T02:51:34.519Z"),nttt"pingMs" : NumberLong(0),nttt"lastHeartbeatMessage" : "Connection refused",nttt"configVersion" : -1ntt},ntt{nttt"_id" : 2,nttt"name" : "localhost:10002",nttt"health" : 1,nttt"state" : 2,nttt"stateStr" : "SECONDARY",nttt"uptime" : 59660,nttt"optime" : {ntttt"ts" : Timestamp(1517281005, 1),ntttt"t" : NumberLong(2)nttt},nttt"optimeDate" : ISODate("2018-01-30T02:56:45Z"),nttt"syncingTo" : "localhost:10003",nttt"configVersion" : 1,nttt"self" : truentt},ntt{nttt"_id" : 3,nttt"name" : "localhost:10003",nttt"health" : 1,nttt"state" : 1,nttt"stateStr" : "PRIMARY",nttt"uptime" : 784,nttt"optime" : {ntttt"ts" : Timestamp(1517281005, 1),ntttt"t" : NumberLong(2)nttt},nttt"optimeDurable" : {ntttt"ts" : Timestamp(1517281005, 1),ntttt"t" : NumberLong(2)nttt},nttt"optimeDate" : ISODate("2018-01-30T02:56:45Z"),nttt"optimeDurableDate" : ISODate("2018-01-30T02:56:45Z"),nttt"lastHeartbeat" : ISODate("2018-01-30T02:56:46.486Z"),nttt"lastHeartbeatRecv" : ISODate("2018-01-30T02:56:47.147Z"),nttt"pingMs" : NumberLong(0),nttt"electionTime" : Timestamp(1517280703, 1),nttt"electionDate" : ISODate("2018-01-30T02:51:43Z"),nttt"configVersion" : 1ntt}nt],nt"ok" : 1,nt"operationTime" : Timestamp(1517281005, 1),nt"$clusterTime" : {ntt"clusterTime" : Timestamp(1517281005, 1),ntt"signature" : {nttt"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),nttt"keyId" : NumberLong(0)ntt}nt}n}nMongoDB Enterprise gabriel:SECONDARY>n

發現 "name" : "localhost:10001","stateStr" : "(not reachable/healthy)", 健康狀態已經是「無法訪問狀態了」

主節點已經切換成 10003 節點了

"_id" : 3,n"name" : "localhost:10003",n"health" : 1,n"state" : 1,n"stateStr" : "PRIMARY",n

重啟節點10001

mongod --dbpath /data/db/node1 --port 10001 --replSet gabriel --nojournal --fork --logpath /data/db/node1.logn

參考:

Runoob 教程:runoob.com/mongodb/mong

Tutorials 教程:Pointtutorialspoint.com/mong

MongoDB 官網地址:https://www.mongodb.com

MongoDB 官方英文文檔:docs.mongodb.com/manual

MongoDB 各平台下載地址:mongodb.com/download-ce

MongoDB 安裝 docs.mongodb.com/manual

Contact

  • 作者:鵬磊
  • 出處:http://www.ymq.io/2018/01/29/MongoDB-2
  • Email:admin@souyunku.com
  • 版權歸作者所有,轉載請註明出處
  • Wechat:關注公眾號,搜雲庫,專註於開發技術的研究與知識分享

weixin.qq.com/r/0UwmPsn (二維碼自動識別)


推薦閱讀:

一個大型的SNS網站,是否適合資料庫全部用mongodb來做,為什麼?
MongoDB在商業使用時會有丟失數據的問題么?
MongoDB 存儲引擎 mongorocks 原理解析
MongoDB——漸進式開發光伏雲系統實踐(二)

TAG:MongoDB | 分布式存储 |