MongoDB 複製相關介紹

上一篇文章介紹了MongoDB的yum安裝方式、配置文件、建立用戶等基礎知識,本篇介紹MongoDB的源碼安裝以及複製集相關!
html

1、使用源碼安裝MongoDBlinux

官網下載地址:http://www.mongodb.org/downloads git

本次實驗使用的mongodb版本是mongodb-linux-x86_64-rhel62-3.4.2.tgz
安裝步驟以下:
一、解壓並設置可執行文件
#tar xf mongodb-linux-x86_64-rhel62-3.4.2.tgz
#mv mongodb-linux-x86_64-rhel62-3.4.2 /usr/local/mongodb #將解壓的包拷貝到指定目錄
MongoDB 的可執行文件位於bin目錄下,因此能夠將其添加到 PATH 路徑中:
#vi /etc/profile
export PATH=$PATH:/usr/local/mongodb/bin
加載/etc/profile使定義生效
#. /etc/profile
查看mongodb的bin文件
#which mongo
/usr/local/mongodb/bin/mongo
查看mongodb的版本號
#mongo --version
MongoDB shell version v3.4.2
git version: 3f76e40c105fc223b3e5aac3e20dcd026b83b38b
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
allocator: tcmalloc
modules: none
build environment:
    distmod: rhel62
    distarch: x86_64
    target_arch: x86_64
    
二、建立數據庫目錄
  MongoDB的數據存儲在data目錄的db目錄下,可是這個目錄在源碼安裝過程不會自動建立,因此須要
手動建立data目錄,並在data目錄中建立db目錄。如下實例中咱們將data目錄建立於根目錄下(/)。
注意:/data/db 是MongoDB默認的啓動的數據庫路徑(--dbpath)。也能夠單獨使用一塊盤掛載到/data/db
目錄,這樣數據就單獨存放了,必定程度提升了安全性!
#mkdir /data/db -p

三、啓動mongodb
注意:若是你的數據庫目錄不是/data/db,能夠經過 --dbpath 來指定
#mongod
2017-02-14T11:28:58.380+0800 I CONTROL  [initandlisten] MongoDB starting : pid=9803 port=27017 dbpath=/data/db 64-bit host=template
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] db version v3.4.2
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] git version: 3f76e40c105fc223b3e5aac3e20dcd026b83b38b
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] allocator: tcmalloc
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] modules: none
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] build environment:
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten]     distmod: rhel62
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten]     distarch: x86_64
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten]     target_arch: x86_64
2017-02-14T11:28:58.381+0800 I CONTROL  [initandlisten] options: {}
2017-02-14T11:28:58.432+0800 I STORAGE  [initandlisten] 
2017-02-14T11:28:58.432+0800 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2017-02-14T11:28:58.432+0800 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2017-02-14T11:28:58.432+0800 I STORAGE  [initandlisten] wiredtiger_open config: create,cache_size=426M,session_max=20000,eviction=(threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] 
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] 
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] 
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2017-02-14T11:28:58.494+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-02-14T11:28:58.495+0800 I CONTROL  [initandlisten] 
2017-02-14T11:28:58.495+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2017-02-14T11:28:58.495+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-02-14T11:28:58.495+0800 I CONTROL  [initandlisten] 
2017-02-14T11:28:58.495+0800 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. rlimits set to 14867 processes, 65536 files. Number of processes should be at least 32768 : 0.5 times number of files.
2017-02-14T11:28:58.495+0800 I CONTROL  [initandlisten] 
2017-02-14T11:28:58.501+0800 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory '/data/db/diagnostic.data'
2017-02-14T11:28:58.511+0800 I INDEX    [initandlisten] build index on: admin.system.version properties: { v: 2, key: { version: 1 }, name: "incompatible_with_version_32", ns: "admin.system.version" }
2017-02-14T11:28:58.511+0800 I INDEX    [initandlisten]          building index using bulk method; build may temporarily use up to 500 megabytes of RAM
2017-02-14T11:28:58.512+0800 I INDEX    [initandlisten] build index done.  scanned 0 total records. 0 secs
2017-02-14T11:28:58.513+0800 I COMMAND  [initandlisten] setting featureCompatibilityVersion to 3.4
2017-02-14T11:28:58.513+0800 I NETWORK  [thread1] waiting for connections on port 27017
根據提示設置ulimit和/sys/kernel參數:
#echo never > /sys/kernel/mm/transparent_hugepage/enabled
#echo never> /sys/kernel/mm/transparent_hugepage/defrag
#vi /etc/security/limits.conf
*  soft nofile 65535
*  hard nofile 65535
*  soft nproc 32768
*  hard nproc 32768
注:設置好以後,不會當即生效,須要exit退出shell,而後從新鏈接生效。從新啓動mongod進程,警告
沒有那麼多了,可是還會提示以下幾個:
** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
** WARNING: Access control is not enabled for the database.
** WARNING: You are running this process as the root user, which is not recommended
其中第一個和第二個比較容易解決,在配置文件添加參數就ok,第三個是提示不容許使用root用戶啓動
mongod進程,上一篇yum安裝的沒有遇到相似問題,是由於yum安裝以後,利用啓動腳本啓動的mongod進
是普通用戶。

四、以普通用戶身份啓動mongod
建立一個普通用戶mongod
#useradd -r -m -s /bin/bash mongod     #建立一個普通系統用戶
修改權限
#chown mongod.mongod /data/ -R
建立mongodb日誌目錄並修改權限
#mkdir /var/log/mongodb/
#chown mongod.mongod /var/log/mongodb
建立配置文件mongod.conf
#vi /etc/mongod.conf
# mongod.conf
# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/
# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
  logRotate: rename
# Where and how to store data.
storage:
  dbPath: /data/db
  journal:
    enabled: true
  engine: wiredTiger
#  mmapv1:
#  wiredTiger:
# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /usr/local/mongodb/mongod.pid  # location of pidfile
# network interfaces
net:
  port: 27017
  bindIp: 10.0.18.149  # Listen to local interface only, comment to listen on all interfaces.
  http:
   enabled: false
   RESTInterfaceEnabled: false
#setParameter:
#   enableLocalhostAuthBypass: true
security:
  authorization: enabled
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options
#auditLog:
#snmp:
保存退出,以上配置文件開啓了authorization功能!
啓動命令:
#su mongod -c "/usr/local/mongodb/bin/mongod  -f /etc/mongod.conf"
about to fork child process, waiting until server is ready for connections.
forked process: 11274
child process started successfully, parent exiting
查看端口
#netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1026/sshd           
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1103/master         
tcp        0      0 10.0.18.149:27017           0.0.0.0:*                   LISTEN      11274/mongod        
tcp        0      0 :::22                       :::*                        LISTEN      1026/sshd           
tcp        0      0 ::1:25                      :::*                        LISTEN      1103/master         
查看進程是不是mongod啓動的
#ps aux | grep mongod    
mongod   11274  0.8  1.8 341288 35872 ?        Sl   16:03   0:01 /usr/local/mongodb/bin/mongod -f /etc/mongod.conf
root     11302  0.0  0.0 103244   836 pts/1    S+   16:06   0:00 grep mongod
注:若是想在啓動的時候開啓認證,使用命令:mongod --dbpath /data/db  --port 20000 --auth
若是配置以普通用戶啓動mongod進程,也須要修改/etc/security/limit.d/90-nproc.conf
#vi /etc/security/limits.d/90-nproc.conf  ##添加以下2行
*          soft    nproc     32768
*          hard    nproc     32768
注意:能夠用killall mongod 來中止mongodb服務;可是不能用kill -9 來中止,會損壞服務器;還可
以用ps aux| grep mongod命令來查看PID,再用kill -2 PID中止服務!

2、配置MongoDB的複製(主從複製)web

一、什麼是複製mongodb

  MongoDB複製是將數據同步在多個服務器的過程。複製提供了數據的冗餘備份,並在多個服務器上存儲數據副本,提升了數據的可用性, 並能夠保證數據的安全性。複製還容許您從硬件故障和服務中斷中恢復數據。shell

  Mongodb複製集由一組Mongod實例(進程)組成,包含一個Primary節點和多個Secondary節點,Mongodb Driver(客戶端)的全部數據都寫入Primary,Secondary從Primary同步寫入的數據,以保持複製集內全部成員存儲相同的數據集,提供數據的高可用。數據庫

二、配置複製的優勢centos

保障數據的安全性緩存

數據高可用性 (24*7)安全

災難恢復

無需停機維護(如備份,重建索引,壓縮)

分佈式讀取數據

三、MongoDB複製原理

官方說明:
The minimum recommended configuration for a replica set is a three member replica set with three data-bearing members: one primary and two 
secondary members

mongodb的複製至少須要兩個節點。其中一個是主節點,負責處理客戶端請求,其他的都是從節點,負責複製主節點上的數據。mongodb各個節點常見的搭配方式爲:一主一從、一主多從。

主節點記錄在其上的全部操做oplog,從節點按期輪詢主節點獲取這些操做,而後對本身的數據副本執行這些操做,從而保證從節點的數據與主節點一致,以下圖:

wKiom1ikCmKyPwxfAACOYpr-96I425.png注:以上圖片參考自互聯網。

大體流程是:客戶端從主節點讀取數據,在客戶端寫入數據到主節點時,主節點與從節點進行數據交互保障數據的一致性。

四、配置MongoDB的主從複製(不經常使用)

主IP:10.0.18.144 從IP:10.0.18.145

注:複製集已經在大多數場合下替代了master-slave複製。若是可能的話,儘量使用複製集而不是主-從複製架構。本文旨在於爲以前遺留的主從架構提供支持,或是僅用於學習。

補充:配置主從,暫時將配置文件中的認證功能關閉-->註釋掉security.authorization: enabled
在主服務器關閉mongod進程,從新啓動以下:
#killall mongod   #關閉mongod進程
而後從新啓動:
#su mongod -c "/usr/local/mongodb/bin/mongod  --master -f /etc/mongod.conf"
about to fork child process, waiting until server is ready for connections.
forked process: 10430
child process started successfully, parent exiting
在從服務器關閉mongod進程,從新啓動以下:
#su mongod -c "/usr/local/mongodb/bin/mongod --slave --source 10.0.18.144:27017 -f /etc/mongod.conf"
about to fork child process, waiting until server is ready for connections.
forked process: 14206
child process started successfully, parent exiting
這樣mongodb的主從就配置ok了。
a、在master服務器上操做
首先看下日誌
#tail /var/log/mongodb/mongod.log
………………
2017-02-15T17:02:16.309+0800 I STORAGE  [initandlisten] Scanning the oplog to determine where to place markers for truncation
2017-02-15T17:02:16.322+0800 I REPL     [initandlisten] ******
2017-02-15T17:02:16.325+0800 I NETWORK  [thread1] waiting for connections on port 27017
2017-02-15T17:04:09.031+0800 I NETWORK  [thread1] connection accepted from 10.0.18.145:46767 #1 (1 connection now open)
2017-02-15T17:04:09.032+0800 I NETWORK  [conn1] received client metadata from 10.0.18.145:46767 conn1: { driver: { name: "MongoDB Internal Client", version: "3.4.2" }, os: { type: "Linux", name: "CentOS release 6.6 (Final)", architecture: "x86_64", version: "Kernel 2.6.32-504.el6.x86_64" } }
2017-02-15T17:04:09.045+0800 I -        [conn1] end connection 10.0.18.145:46767 (1 connection now open)
2017-02-15T17:04:12.033+0800 I NETWORK  [thread1] connection accepted from 10.0.18.145:46828 #2 (1 connection now open)
2017-02-15T17:04:12.034+0800 I NETWORK  [conn2] received client metadata from 10.0.18.145:46828 conn2: { driver: { name: "MongoDB Internal Client", version: "3.4.2" }, os: { type: "Linux", name: "CentOS release 6.6 (Final)", architecture: "x86_64", version: "Kernel 2.6.32-504.el6.x86_64" } }
2017-02-15T17:04:12.035+0800 I -        [conn2] end connection 10.0.18.145:46828 (1 connection now open)
2017-02-15T17:04:15.036+0800 I NETWORK  [thread1] connection accepted from 10.0.18.145:46887 #3 (1 connection now open)
2017-02-15T17:04:15.036+0800 I NETWORK  [conn3] received client metadata from 10.0.18.145:46887 conn3: { driver: { name: "MongoDB Internal Client", version: "3.4.2" }, os: { type: "Linux", name: "CentOS release 6.6 (Final)", architecture: "x86_64", version: "Kernel 2.6.32-504.el6.x86_64" } }
能夠看到已經接受了從服務器10.0.18.145的鏈接請求。
進入mongodb進行查看
#mongo --host 10.0.18.144
> db.isMaster()
{
        "ismaster" : true,               #表示是主節點
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2017-02-15T09:08:01.081Z"),
        "maxWireVersion" : 5,
        "minWireVersion" : 0,
        "readOnly" : false,
        "ok" : 1
}
在主服務器建立一個庫,並插入數據,驗證從服務器是否存在
> show dbs;
admin  0.000GB
local  0.000GB
> db.test
test.test
> db
test
> db.test.insert({"name":"ceshizhucong"})
WriteResult({ "nInserted" : 1 })
> show dbs;
admin  0.000GB
local  0.000GB
test   0.000GB
> use test
switched to db test
> db.test.findOne();db.test.findOne();
{ "_id" : ObjectId("58a41cbda6bb67ceb5dd53c6"), "name" : "ceshizhucong" }
b、在從服務器操做
#mongo --host 10.0.18.145
> db.isMaster();
{
        "ismaster" : false,          #表示是從節點
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2017-02-15T09:19:30.163Z"),
        "maxWireVersion" : 5,
        "minWireVersion" : 0,
        "readOnly" : false,
        "ok" : 1
}
> show dbs;
2017-02-15T17:23:35.795+0800 E QUERY    [thread1] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:755:19
shellHelper@src/mongo/shell/utils.js:645:15
@(shellhelp2):1:1
能夠看到執行show dbs命令不成功,由於不是master服務器
> db    #查看當前數據庫,能夠看到test庫已經複製過來了
test
> use web
switched to db web
> db 
web
> db.web.insert({"name":"ceshizhucong3"})db.web.insert({"name":"ceshizhucong3"})
WriteResult({ "writeError" : { "code" : 10107, "errmsg" : "not master" } })
也沒法插入數據,由於從服務器沒法進行寫操做!
查看從服務器日誌
#tail -f mongod.log 
………………
2017-02-15T17:29:13.730+0800 I REPL     [replslave] syncing from host:10.0.18.144:27017
2017-02-15T17:29:14.732+0800 I REPL     [replslave] syncing from host:10.0.18.144:27017
到這裏MongoDB的主從複製就結束了!

3、MongoDB副本集的一些特徵介紹

一、副本集特徵:

N個節點的集羣

任何節點可做爲主節點

全部寫入操做都在主節點上

自動故障轉移

自動恢復

二、Primary選舉

複製集經過replSetInitiate命令(或mongo shell的rs.initiate())進行初始化,初始化後各個成員間開始發送心跳消息,

併發起Priamry選舉操做,得到『大多數』成員投票支持的節點,會成爲Primary,其他節點成爲Secondary

三、大多數的定義

假設複製集內投票成員(後續介紹)數量爲N,則大多數爲N/2 + 1,當複製集內存活成員數量不足大多數時,整個複製集將沒法選舉出Primary,複製集將沒法提供寫服務,處於只讀狀態。以下圖:

wKioL1ilR1Shm3ktAAAZyVL7ne0884.png

一般建議將複製集成員數量設置爲奇數,從上表能夠看出3個節點和4個節點的複製集都只能容忍1個節點失效,從『服務可用性』的角度看,其效果是同樣的(但無疑4個節點能提供更可靠的數據存儲)

四、特殊的Secondary

正常狀況下,複製集的Seconary會參與Primary選舉(自身也可能會被選爲Primary),並從Primary同步最新寫入的數據,以保證與Primary存儲相同的數據。Secondary能夠提供讀服務,增長Secondary節點能夠提供複製集的讀服務能力,同時提高複製集的可用性。另外,Mongodb支持對複製集的Secondary節點進行靈活的配置,以適應多種場景的需求

五、Arbiter 仲裁節點

Arbiter節點只參與投票,不能被選爲Primary,而且不從Primary同步數據。好比你部署了一個2個節點的複製集,1個Primary,1個Secondary,任意節點宕機,複製集將不能提供服務了(沒法選出Primary),這時能夠給複製集添加一個Arbiter節點,即便有節點宕機,仍能選出Primary。

Arbiter自己不存儲數據,是很是輕量級的服務,當複製集成員爲偶數時,最好加入一個Arbiter節點,以提高複製集可用性。

六、Priority0

Priority0節點的選舉優先級爲0,不會被選舉爲Primary。好比你跨機房A、B部署了一個複製集,而且想指定Primary必須在A機房,這時能夠將B機房的複製集成員Priority設置爲0,這樣Primary就必定會是A機房的成員。

(注意:若是這樣部署,最好將『大多數』節點部署在A機房,不然網絡分區時可能沒法選出Primary)

七、Vote0

Mongodb 3.0裏,複製集成員最多50個,參與Primary選舉投票的成員最多7個,其餘成員(Vote0)的vote屬性必須設置爲0,即不參與投票。

八、Hidden

Hidden節點不能被選爲主(Priority爲0),而且對Driver不可見。

因Hidden節點不會接受Driver的請求,可以使用Hidden節點作一些數據備份、離線計算的任務,不會影響複製集的服務。

九、Delayed

Delayed節點必須是Hidden節點,而且其數據落後與Primary一段時間(可配置,好比1個小時)。

因Delayed節點的數據比Primary落後一段時間,當錯誤或者無效的數據寫入Primary時,可經過Delayed節點的數據來恢復到以前的時間點。

十、數據同步

Primary與Secondary之間經過oplog來同步數據,Primary上的寫操做完成後,會向特殊的local.oplog.rs特殊集合寫入一條oplog,Secondary不斷的從Primary取新的oplog並應用。因oplog的數據會不斷增長,local.oplog.rs被設置成爲一個capped集合,當容量達到配置上限時,會將最舊的數據刪除掉。另外考慮到oplog在Secondary上可能重複應用,oplog必須具備冪等性,即重複應用也會獲得相同的結果。

Secondary初次同步數據時,會先進行init sync 從Primary(或其餘數據更新的Secondary)同步全量數據,而後不斷經過tailable cursor從Primary的local.oplog.rs集合裏查詢最新的oplog並應用到自身。

init sync過程包含以下步驟:

T1時間,從Primary同步全部數據庫的數據(local除外),經過listDatabases + listCollections + cloneCollection敏命令組合完成,假設T2時間完成全部操做。

從Primary應用[T1-T2]時間段內的全部oplog,可能部分操做已經包含在步驟1,但因爲oplog的冪等性,可重複應用。

根據Primary各集合的index設置,在Secondary上爲相應集合建立index。(每一個集合_id的index已在步驟1中完成)。

oplog集合的大小應根據DB規模及應用寫入需求合理配置,配置得太大,會形成存儲空間的浪費;配置得過小,可能形成Secondary的init sync一直沒法成功。好比在步驟1裏因爲DB數據太多、而且oplog配置過小,致使oplog不足以存儲[T1, T2]時間內的全部oplog,這就讓Secondary沒法從Primary上同步完整的數據集。

十一、修改複製集配置

當須要修改複製集時,好比增長成員、刪除成員、或者修改爲員配置(如priorty、vote、hidden、delayed等屬性),可經過replSetReconfig命令(rs.reconfig())對複製集進行從新配置。

好比將複製集的第2個成員Priority設置爲2,可執行以下命令

cfg = rs.conf();

cfg.members[1].priority = 2;

rs.reconfig(cfg);

細說Primary選舉

Primary選舉除了在複製集初始化時發生,還有以下場景

複製集被reconfig

Secondary節點檢測到Primary宕機時,會觸發新Primary的選舉

當有Primary節點主動stepDown(主動降級爲Secondary)時,也會觸發新的Primary選舉

Primary的選舉受節點間心跳、優先級、最新的oplog時間等多種因素影響。

十二、節點間心跳

複製集成員間默認每2s會發送一次心跳信息,若是10s未收到某個節點的心跳,則認爲該節點已宕機;若是宕機的節點爲Primary,Secondary(前提是可被選爲Primary)會發起新的Primary選舉。

節點優先級

每一個節點都傾向於投票給優先級最高的節點

優先級爲0的節點不會主動發起Primary選舉

當Primary發現有優先級更高Secondary,而且該Secondary的數據落後在10s內,則Primary會主動降級,讓優先級更高的Secondary有成爲Primary的機會。

1三、Optime

擁有最新optime(最近一條oplog的時間戳)的節點才能被選爲主。

1四、網絡分區

只有更大多數投票節點間保持網絡連通,纔有機會被選Primary;若是Primary與大多數的節點斷開鏈接,Primary會主動降級爲Secondary。

當發生網絡分區時,可能在短期內出現多個Primary,故Driver在寫入時,最好設置『大多數成功』的策略,這樣即便出現多個Primary,也只有一個Primary能成功寫入大多數。

1五、複製集的讀寫設置(Read Preference)

默認狀況下,複製集的全部讀請求都發到Primary,Driver可經過設置Read Preference來將讀請求路由到其餘的節點。

primary: 默認規則,全部讀請求發到Primary

primaryPreferred: Primary優先,若是Primary不可達,請求Secondary

secondary: 全部的讀請求都發到secondary

secondaryPreferred:Secondary優先,當全部Secondary不可達時,請求Primary

nearest:讀請求發送到最近的可達節點上(經過ping探測得出最近的節點)

1六、Write Concern

默認狀況下,Primary完成寫操做即返回,Driver可經過設置[Write Concern(https://docs.mongodb.org/manual/core/write-concern/)來設置寫成功的規則。

以下的write concern規則設置必須在大多數節點上成功,超時時間爲5s。

db.products.insert(

  { item: "envelopes", qty : 100, type: "Clasp" },

  { writeConcern: { w: majority, wtimeout: 5000 } }

)

1七、異常處理(rollback)

當Primary宕機時,若是有數據未同步到Secondary,當Primary從新加入時,若是新的Primary上已經發生了寫操做,則舊Primary須要回滾部分操做,以保證數據集與新的Primary一致。

舊Primary將回滾的數據寫到單獨的rollback目錄下,數據庫管理員可根據須要使用mongorestore進行恢復。


4、開始配置MongoDB副本集:

注:這裏使用3臺服務器作MongoDB的副本集,都是源碼安裝的3.4.2版本,架構信息以下:

主:10.0.18.144  centos6.6  x86_64

從:10.0.18.149  centos6.6  x86_64

從:10.0.18.150  centos6.6  x86_64

具體安裝步驟請參見本篇博客第一部分!

一、修改配置文件
基本配置以下:
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
  logRotate: rename
storage:
  dbPath: /data/db
  journal:
    enabled: true
  engine: wiredTiger
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /usr/local/mongodb/mongod.pid  # location of pidfile
net:
  port: 27017
  bindIp: x.x.x.x     # Listen to local interface only, comment to listen on all interfaces.
  http:
   enabled: false
   RESTInterfaceEnabled: false
#security:
#  authorization: enabled
在基本配置的基礎上對三臺mongodb的配置文件統一添加以下:
replication:
  oplogSizeMB: 20
  replSetName: Myrepl
注:oplogSizeMB指oplog大小,即複製操做日誌的最大大小(以兆字節爲單位
    replSetName 指副本集名稱,注意格式是前面空兩格,冒號後空一格。
而後重啓三臺MongoDB的mongod進程!
#killall mongod
#su mongod -c "/usr/local/mongodb/bin/mongod  -f /etc/mongod.conf"  #以普通用戶啓動

二、在主服務器操做
#mongo --host 10.0.18.144
MongoDB shell version v3.4.2
connecting to: mongodb://10.0.18.144:27017/
MongoDB server version: 3.4.2
> use admin
switched to db admin
> config={_id:"Myrepl",members:[{_id:0,host:"10.0.18.144:27017"},{_id:1,host:"10.0.18.149:27017"},{_id:2,host:"10.0.18.150:27017"}]}config={_id:"Myrepl",members:[{_id:0,host:"10.0.18.144:27017"},{_id:1,host:"10.0.18.149:27017"},{_id:2,host:"10.0.18.150:27017"}]}
{
        "_id" : "Myrepl",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "10.0.18.144:27017"
                },
                {
                        "_id" : 1,
                        "host" : "10.0.18.149:27017"
                },
                {
                        "_id" : 2,
                        "host" : "10.0.18.150:27017"
                }
        ]
}
> rs.initiate(config)    #初始化
{ "ok" : 1 }       #顯示ok表示成功
Myrepl:OTHER> 
補充:要想使用副本集,從的mongodb的數據必須都是空的,要否則執行rs.initiate()命令時會提示因
存在數據而致使初始化不成功,以下:
> rs.initiate(config)
{
        "ok" : 0,
        "errmsg" : "'10.0.18.150:27017' has data already, cannot initiate set.",
        "code" : 110,
        "codeName" : "CannotInitializeNodeWithData"
}
繼續進行:
Myrepl:OTHER> rs.status()    #查看副本集狀態
{
        "set" : "Myrepl",
        "date" : ISODate("2017-02-16T08:57:54.003Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1487235464, 1),
                        "t" : NumberLong(1)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1487235464, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1487235464, 1),
                        "t" : NumberLong(1)
                }
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "10.0.18.144:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",        #主
                        "uptime" : 941, 
                        "optime" : {
                                "ts" : Timestamp(1487235464, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2017-02-16T08:57:44Z"),
                        "electionTime" : Timestamp(1487235294, 1),
                        "electionDate" : ISODate("2017-02-16T08:54:54Z"),
                        "configVersion" : 1,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "10.0.18.149:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",    #從
                        "uptime" : 191,
                        "optime" : {
                                "ts" : Timestamp(1487235464, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1487235464, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2017-02-16T08:57:44Z"),
                        "optimeDurableDate" : ISODate("2017-02-16T08:57:44Z"),
                        "lastHeartbeat" : ISODate("2017-02-16T08:57:52.541Z"),
                        "lastHeartbeatRecv" : ISODate("2017-02-16T08:57:52.182Z"),
                        "pingMs" : NumberLong(0),
                        "syncingTo" : "10.0.18.150:27017",
                        "configVersion" : 1
                },
                {
                        "_id" : 2,
                        "name" : "10.0.18.150:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",    #從
                        "uptime" : 191,
                        "optime" : {
                                "ts" : Timestamp(1487235464, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1487235464, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2017-02-16T08:57:44Z"),
                        "optimeDurableDate" : ISODate("2017-02-16T08:57:44Z"),
                        "lastHeartbeat" : ISODate("2017-02-16T08:57:52.542Z"),
                        "lastHeartbeatRecv" : ISODate("2017-02-16T08:57:52.092Z"),
                        "pingMs" : NumberLong(0),
                        "syncingTo" : "10.0.18.144:27017",
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}
注意:兩個從上的狀態爲 "stateStr" : "SECONDARY",若爲 "STARTUP",則須要進行以下操做:
> var config={_id:"tpp",members:[{_id:0,host:"192.168.0.103:27017"},{_id:1,host:"192.168.0.109:27017"},{_id:2,host:"192.168.0.120:27017"}]}
> rs.initiate(config)
查看到以上信息就說明配置成功了,咱們也會發現主上前綴變爲Myrepl:PRIMARY>  而從服務器的前綴
變成了Myrepl:SECONDARY> 

三、副本集測試
在主服務器上建庫、建集合、插入數據
Myrepl:PRIMARY> use testdb
switched to db testdb
Myrepl:PRIMARY> db.createCollection('test1')
{ "ok" : 1 }
Myrepl:PRIMARY> show dbs
admin   0.000GB
local   0.000GB
testdb  0.000GB
Myrepl:PRIMARY> db.testdb.insert({"name":"repl","time":"170216"}) #插入一條數據
WriteResult({ "nInserted" : 1 })
Myrepl:PRIMARY> db.testdb.findOne()   #查看數據
{
        "_id" : ObjectId("58a56b7404b33bc093a90321"),
        "name" : "repl",
        "time" : "170216"
}
而後再從服務器上查看
#mongo --host 10.0.18.149
MongoDB shell version v3.4.2
connecting to: mongodb://10.0.18.149:27017/
MongoDB server version: 3.4.2
Myrepl:SECONDARY> show dbs
2017-02-16T17:08:09.524+0800 E QUERY    [thread1] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:755:19
shellHelper@src/mongo/shell/utils.js:645:15
@(shellhelp2):1:1
Myrepl:SECONDARY> rs.slaveOk()    #執行此命令,以後查詢就不報錯了!
Myrepl:SECONDARY> show dbs
admin   0.000GB
local   0.000GB
testdb  0.000GB
Myrepl:SECONDARY> use testd   
switched to db testdb
Myrepl:SECONDARY> db.testdb.findOne()   #查詢數據,能夠看到在從服務器上已經有數據了
{
        "_id" : ObjectId("58a56b7404b33bc093a90321"),
        "name" : "repl",
        "time" : "170216"
}
注意:經過上面的命令只能臨時查詢,下次再經過mongo命令進入後查詢仍會報錯,因此能夠修改文件
#vi ~/.mongorc.js                  //寫入下面這行
rs.slaveOk();
而後重啓mongod進程!
我這裏是root用戶,因此在/root/.mongorc.js中添加便可!

四、模擬主服務器宕機,查看從服務器轉變爲主
首先在主服務器查看三臺服務器的權重,以下:
Myrepl:PRIMARY> rs.config()
{
        "_id" : "Myrepl",
        "version" : 1,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 0,
                        "host" : "10.0.18.144:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,         #優先級爲1
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 1,
                        "host" : "10.0.18.149:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,        #優先級爲1
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "10.0.18.150:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,       #優先級爲1
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : 2000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("58a568d2b205e55e0e0682d1")
        }
}
注意:默認全部的機器權重(優先級)都爲1,若是任何一個權重設置爲比其餘的高,則該臺機器立馬會切換爲primary角色,因此要咱們預設三臺機器的權重
設置權重
預設主(18.144)權重爲三、從(18.149)權重爲二、從(18.150)權重爲1(默認值可不用從新賦值)。
在主18.144上執行下面命令:
Myrepl:PRIMARY> cfg=rs.config()      #從新賦值
{
        "_id" : "Myrepl",
        "version" : 1,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 0,
                        "host" : "10.0.18.144:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 1,
                        "host" : "10.0.18.149:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "10.0.18.150:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : 2000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("58a568d2b205e55e0e0682d1")
        }
}
Myrepl:PRIMARY> cfg.members[0].priority = 3     
3
Myrepl:PRIMARY> cfg.members[1].priority = 2
2
Myrepl:PRIMARY> rs.reconfig(cfg)      #從新加載配置
{ "ok" : 1 }
Myrepl:PRIMARY> rs.config()                #從新查看權重是否已經更改
{
        "_id" : "Myrepl",
        "version" : 2,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 0,
                        "host" : "10.0.18.144:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 3,       #變爲了3
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 1,
                        "host" : "10.0.18.149:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 2,      #變爲了2
                        "tags" : {  

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "10.0.18.150:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,          #保持原來的1
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : 2000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("58a568d2b205e55e0e0682d1")
        }
}

五、停掉主(10.0.18.144)服務器的mongod進程
#killall mongod
而後在從服務器10.0.18.149上敲幾下回車,從的角色立馬由SECONDARY變爲PRIMARY,以下: 
Myrepl:SECONDARY> 
Myrepl:SECONDARY> 
Myrepl:SECONDARY> 
Myrepl:PRIMARY> 
Myrepl:PRIMARY> 
Myrepl:PRIMARY> rs.status()            #查看狀態
{
        "set" : "Myrepl",
        "date" : ISODate("2017-02-16T10:12:40.419Z"),
        "myState" : 1,
        "term" : NumberLong(2),
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1487239953, 1),
                        "t" : NumberLong(2)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1487239953, 1),
                        "t" : NumberLong(2)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1487239953, 1),
                        "t" : NumberLong(2)
                }
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "10.0.18.144:27017",
                        "health" : 0,                        #原來的主服務器health爲0
                        "state" : 8,
                        "stateStr" : "(not reachable/healthy)",   #並且是不可達的狀態
                        "uptime" : 0,
                        "optime" : {
                                "ts" : Timestamp(0, 0),
                                "t" : NumberLong(-1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(0, 0),
                                "t" : NumberLong(-1)
                        },
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2017-02-16T10:12:39.422Z"),
                        "lastHeartbeatRecv" : ISODate("2017-02-16T10:10:43.056Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "Connection refused",
                        "configVersion" : -1
                },
                {
                        "_id" : 1,
                        "name" : "10.0.18.149:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",     #原來的從服務器由於優先級高,變成了主
                        "uptime" : 3446,
                        "optime" : {
                                "ts" : Timestamp(1487239953, 1),
                                "t" : NumberLong(2)
                        },
                        "optimeDate" : ISODate("2017-02-16T10:12:33Z"),
                        "infoMessage" : "could not find member to sync from",
                        "electionTime" : Timestamp(1487239853, 1),
                        "electionDate" : ISODate("2017-02-16T10:10:53Z"),
                        "configVersion" : 2,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "10.0.18.150:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 3445,
                        "optime" : {
                                "ts" : Timestamp(1487239953, 1),
                                "t" : NumberLong(2)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1487239953, 1),
                                "t" : NumberLong(2)
                        },
                        "optimeDate" : ISODate("2017-02-16T10:12:33Z"),
                        "optimeDurableDate" : ISODate("2017-02-16T10:12:33Z"),
                        "lastHeartbeat" : ISODate("2017-02-16T10:12:39.357Z"),
                        "lastHeartbeatRecv" : ISODate("2017-02-16T10:12:39.583Z"),
                        "pingMs" : NumberLong(0),
                        "syncingTo" : "10.0.18.149:27017",
                        "configVersion" : 2
                }
        ],
        "ok" : 1
}
注意:由上面可發現原來的主(18.144)已處於不健康狀態(失連),而原來權重高的從(18.149)的角色變爲PRIMARY,
權重低的從角色不變。不過要想讓用戶識別新主,還需手動指定讀庫的目標server!

六、原主恢復,新主寫入的數據是否同步
在10.0.18.149這臺新主服務器操做:
#mongo --host 10.0.18.149
MongoDB shell version v3.4.2
connecting to: mongodb://10.0.18.149:27017/
MongoDB server version: 3.4.2
在此服務器建庫、建集合、插入數據
Myrepl:PRIMARY> show dbs;
admin   0.000GB
local   0.000GB
testdb  0.000GB
Myrepl:PRIMARY> use testdb2
switched to db testdb2
Myrepl:PRIMARY> db
testdb2
Myrepl:PRIMARY> db.createCollection('test2')
{ "ok" : 1 }
Myrepl:PRIMARY> show dbs
admin    0.000GB
local    0.000GB
testdb   0.000GB
testdb2  0.000GB
Myrepl:PRIMARY> db.testdb2.insert({"name":"repl2","time":"17021618"})db.testdb2.insert({"name":"repl2","time":"17021618"})
WriteResult({ "nInserted" : 1 })
Myrepl:PRIMARY> db.testdb2.findOne()
{
        "_id" : ObjectId("58a57cd471c4e5a43bfa11fa"),
        "name" : "repl2",
        "time" : "17021618"
}
在第二臺從服務器10.0.18.150查看數據
#mongo --host 10.0.18.150
MongoDB shell version v3.4.2
connecting to: mongodb://10.0.18.150:27017/
MongoDB server version: 3.4.2
Myrepl:SECONDARY> show dbs;
2017-02-16T18:21:23.860+0800 E QUERY    [thread1] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:755:19
shellHelper@src/mongo/shell/utils.js:645:15
@(shellhelp2):1:1
Myrepl:SECONDARY> rs.slaveOk()
Myrepl:SECONDARY> show dbs
admin    0.000GB
local    0.000GB
testdb   0.000GB
testdb2  0.000GB
也能夠看到第二臺從服務器已經重新主服務器複製了數據!

而後將原來的主服務器10.0.18.144的mongod進程啓動,在新主服務器10.0.18.149回車查看以下:
Myrepl:PRIMARY> 
2017-02-16T18:24:06.037+0800 I NETWORK  [thread1] trying reconnect to 10.0.18.149:27017 (10.0.18.149) failed
2017-02-16T18:24:06.039+0800 I NETWORK  [thread1] reconnect 10.0.18.149:27017 (10.0.18.149) ok
Myrepl:SECONDARY> 
Myrepl:SECONDARY> 
能夠看到狀態由原來的Myrepl:PRIMARY變爲了Myrepl:SECONDARY

最後登陸原主服務器查看數據是否存在
#mongo --host 10.0.18.144
MongoDB shell version v3.4.2
connecting to: mongodb://10.0.18.144:27017/
MongoDB server version: 3.4.2
Myrepl:PRIMARY> show dbs     #能夠看到testdb2庫已經存在了
admin    0.000GB
local    0.000GB
testdb   0.000GB
testdb2  0.000GB
Myrepl:PRIMARY> use testdb2
switched to db testdb2
Myrepl:PRIMARY> db.testdb2.findOne()        #數據也能夠查看到
{
        "_id" : ObjectId("58a57cd471c4e5a43bfa11fa"),
        "name" : "repl2",
        "time" : "17021618"
}

說明:由上面可知,當權重更高的原主恢復運行了,在新主期間寫入的新數據一樣同步到了原主上,即副本集成功實現了負載均衡的目的。

七、爲副本集開啓認證功能

說明:在配置副本集的時候,沒有開啓認證功能,爲了安全起見,配置好副本集以後,須要開啓。

注:單服務器,啓動時添加--auth參或者在配置文件中配置authorization: enabled開啓開啓驗證。

副本集服務器,開啓--auth參數或者在配置文件中配置authorization: enabled的同時,必須指定keyfile參數,節點之間的通信基於該keyfile,key長度必須在6到1024個字符之間,最好爲3的倍數,不能含有非法字符!

a、首先在主服務器建立數據庫管理員用戶
Myrepl:PRIMARY> use admin
switched to db admin
Myrepl:PRIMARY> db.createUser({user:"root",pwd:"test123",roles:["userAdminAnyDatabase"]})
Successfully added user: { "user" : "root", "roles" : [ "userAdminAnyDatabase" ] }
Myrepl:PRIMARY> show collections;    #查看集合
system.users
system.version
Myrepl:PRIMARY> show users;         #查看用戶
{
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}
Myrepl:PRIMARY> db.system.users.find()    #查看用戶的詳細信息
{ "_id" : "admin.root", "user" : "root", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "YUtAugkOXigZNs0Y8sO+aA==", "storedKey" : "SGcT/CXln2oV0yCg0AP6GUgNhLQ=", "serverKey" : "ntBaZ36ulyNa7QuiLiXpclXb1TU=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
而後爲testdb庫建立一個具備讀寫權限的普通用戶
Myrepl:PRIMARY> use testdb
switched to db testdb
Myrepl:PRIMARY> db.createUser({user:"testuser1",pwd:"123456,",roles:["readWrite"]})
Successfully added user: { "user" : "testuser1", "roles" : [ "readWrite" ] }
Myrepl:PRIMARY> show users;
{
        "_id" : "testdb.testuser1",
        "user" : "testuser1",
        "db" : "testdb",
        "roles" : [
                {
                        "role" : "readWrite",
                        "db" : "testdb"
                }
        ]
}
而後建立系統管理員用戶
Myrepl:PRIMARY> use admin
switched to db admin
Myrepl:PRIMARY> db.createUser({user:"system",pwd:"123456",roles:[{role:"root",db:"admin"}]})
Successfully added user: {
        "user" : "system",
        "roles" : [
                {
                        "role" : "root",
                        "db" : "admin"
                }
        ]
}
Myrepl:PRIMARY> show users;
{
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}
{
        "_id" : "admin.system",
        "user" : "system",
        "db" : "admin",
        "roles" : [
                {
                        "role" : "root",
                        "db" : "admin"
                }
        ]
}
b、在主服務器生成keyfile文件
#cd /usr/local/mongodb   #進入mongodb安裝目錄
#openssl rand -base64 21 > keyfile  #建立一個keyfile(使用openssl生成21位base64加密的字符串)
#chown mongod.mongod keyfile   #修改屬主屬組
#chmod 600 keyfile             #修改權限爲600
注意:上面的數字21,最好是3的倍數,不然生成的字符串可能含有非法字符,認證失敗!
c、將keyfile的內容寫入到其餘2臺從服務器對應目錄,並修改屬性和權限
d、在三臺服務器的mongod.conf配置文件中添加認證參數
security:
  keyFile: "/usr/local/mongodb/keyfile"      #keyfile路徑
  clusterAuthMode: "keyFile"                 #認證模式
  authorization: enabled                     #開啓認證

而後重啓mongod進程,而後查看
#mongo --host 10.0.18.144
MongoDB shell version v3.4.2
connecting to: mongodb://10.0.18.144:27017/
MongoDB server version: 3.4.2
Myrepl:PRIMARY> show dbs
2017-02-17T17:35:42.675+0800 E QUERY    [thread1] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
        "code" : 13,
        "codeName" : "Unauthorized"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:755:19
shellHelper@src/mongo/shell/utils.js:645:15
@(shellhelp2):1:1
能夠看到沒法執行show dbs,提示沒有認證
Myrepl:PRIMARY> use admin
switched to db admin
Myrepl:PRIMARY> db.auth("root","test123")    #認證經過
1
Myrepl:PRIMARY> show dbs;          #認證以後,查看就ok了
admin    0.000GB
local    0.001GB
testdb   0.000GB
testdb2  0.000GB
Myrepl:PRIMARY> show users;
{
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}
{
        "_id" : "admin.system",
        "user" : "system",
        "db" : "admin",
        "roles" : [
                {
                        "role" : "root",
                        "db" : "admin"
                }
        ]
}
一樣,在從服務器上想要查看數據,也須要認證經過後才能夠!

八、其餘
從新設置副本集命令:
rs.stepDown()
cfg = rs.conf()
cfg.members[n].host= 'new_host_name:prot'
rs.reconfig(cfg)
副本集全部節點服務器總數必須爲奇數,服務器數量爲偶數的時候,須要添加一個仲裁節點,仲裁節點不參與數副本集,只有選舉權。
#添加仲裁節點
rs.addArb("10.0.18.111:27017")
複製(副本集)相關請查閱中文網站
####################################
MongoDB查看複製集狀態
/opt/app/mongodb3/bin/mongostat --host x.x.x.114:27017 -umongodbuser -pxxx --authenticationDatabase=admin --discover -n 3 1

                    insert query update delete getmore command % dirty % used flushes vsize   res qr|qw ar|aw netIn netOut conn   set repl     time
x.x.x.113:27017    *16    95    *27     *0       0    74|0     0.1   80.0       0 15.5G 14.2G   0|3   1|0   17k   964k  556 km_tv  SEC 11:27:50
x.x.x.114:27017    *16    81    *27     *0       0    75|0     0.1   80.0       0 15.4G 14.1G   0|0   1|0   16k   745k  558 km_tv  SEC 11:27:50
x.x.x.115:27017     17    *0     57     *0      79   212|0     0.4   49.8       0  9.7G  8.4G   0|0   1|0  360k   694k  518 km_tv  PRI 11:27:50

x.x.x.113:27017    *12    85    *29     *0       0    81|0     0.2   80.0       0 15.5G 14.2G   0|0   2|0   17k   618k  556 km_tv  SEC 11:27:52
x.x.x.114:27017    *12    80    *29     *0       0    80|0     0.1   80.0       0 15.4G 14.1G   0|0   1|0   16k   697k  558 km_tv  SEC 11:27:51
x.x.x.115:27017     11    *0     52     *0      68   181|0     0.5   49.8       0  9.7G  8.4G   0|0   1|0  292k   980k  515 km_tv  PRI 11:27:52

x.x.x.113:27017    *12    81    *35     *0       0    86|0     0.2   80.0       0 15.5G 14.2G   0|0   1|0   16k   906k  556 km_tv  SEC 11:27:53
x.x.x.114:27017    *12    90    *35     *0       0    83|0     0.1   80.0       0 15.4G 14.1G   0|0   1|0   17k    16m  558 km_tv  SEC 11:27:52
x.x.x.115:27017     12    *0     64     *0      76   199|0     0.5   49.8       0  9.7G  8.4G   0|0   1|0  271k   548k  515 km_tv  PRI 11:27:53
各字段解釋說明:
insert/s :   官方解釋是每秒插入數據庫的對象數量,若是是slave,則數值前有*,則表示複製集操做
query/s :  每秒的查詢操做次數
update/s : 每秒的更新操做次數
delete/s : 每秒的刪除操做次數
getmore/s: 每秒查詢cursor(遊標)時的getmore操做數
command:   每秒執行的命令數,在主從系統中會顯示兩個值(例如 3|0),分表表明 本地|複製 命令
注: 一秒內執行的命令數好比批量插入,只認爲是一條命令(因此意義應該不大)
dirty: 僅僅針對WiredTiger引擎,官網解釋是髒數據字節的緩存百分比
used:  僅僅針對WiredTiger引擎,官網解釋是正在使用中的緩存百分比
flushes:
For WiredTiger引擎:指checkpoint的觸發次數在一個輪詢間隔期間
For MMAPv1 引擎:每秒執行fsync將數據寫入硬盤的次數
注:通常都是0,間斷性會是1, 經過計算兩個1之間的間隔時間,能夠大體瞭解多長時間flush一次。
flush開銷是很大的,若是頻繁的flush,可能就要找找緣由了
vsize: 虛擬內存使用量,單位MB (這是 在mongostat 最後一次調用的總數據)
res:    物理內存使用量,單位MB (這是 在mongostat 最後一次調用的總數據)
注:這個和你用top看到的同樣, vsize通常不會有大的變更, res會慢慢的上升,若是res常常忽然降低,去查查是否有別的程序狂吃內存。

qr: 客戶端等待從MongoDB實例讀數據的隊列長度
qw:客戶端等待從MongoDB實例寫入數據的隊列長度
ar: 執行讀操做的活躍客戶端數量
aw: 執行寫操做的活客戶端數量
注:若是這兩個數值很大,那麼就是DB被堵住了,DB的處理速度不及請求速度。看看是否有開銷很大的慢查詢。若是查詢一切正常,確實是負載很大,就須要加機器了
netIn:MongoDB實例的網絡進流量
netOut:MongoDB實例的網絡出流量
注:此兩項字段表名網絡帶寬壓力,通常狀況下,不會成爲瓶頸
conn: 打開鏈接的總數,是qr,qw,ar,aw的總和
注:MongoDB爲每個鏈接建立一個線程,線程的建立與釋放也會有開銷,因此儘可能要適當配置鏈接數的啓動參數,maxIncomingConnections,阿里工程師建議在5000如下,基本知足多數場景
set:  副本集的名稱
repl: 節點的複製狀態
     M       ---master
     SEC     ---secondary
     REC     ---recovering
     UNK     ---unknown
     SLV     ---slave
     RTR     ---mongs process("router')
     ARB     ---arbiter
time: 當前時間

九、不停機狀態下複製集主節點切換
注意:這裏是在三臺複製集的mongdob  priority 全是1 的狀況下!!!
a、凍結其中的一個從節點,使其不參與到與primary的內部選舉工做
進入到mongodb執行如下命令: (單位:秒)
rs.freeze(120)
b、重啓主節點的mongodb進程 (在2分鐘以內完成)
c、第三個slave 節點 就被選舉成爲了主節點
rs.status()  查看狀態

5、複製集其餘一些用法

一、查看副本集成員數據同步(延遲)狀況
mongo>db.printReplicationInfo()
mongo>db.printSlaveReplicationInfo()  #最好在secondary上執行
mongo>rs.printReplicationInfo()
mongo>rs.printSlaveReplicationInfo()  #最好在secondary上執行

mongo>use local>db.slaves.find()  在主節點上跟蹤延遲:
local.slaves該集合保存着全部正從當前成員進行數據同步的成員,以及每一個成員的數據新舊程度。
登陸主節點
>use local
>db.slaves.find()、
查看其中每一個成員對應的"syncedTo":{"t":9999999,"i":32} 部分便可知道數據的同步程度。

二、主節點降爲secondary
mongo>use admin
mongo>rs.stepDown(60) #單位爲 秒
 
三、鎖定指定節點在指定時間內不能成爲主節點(阻止選舉)
mongo>rs.freeze(120)#單位爲 秒
釋放阻止
mongo>rs.freeze(0)

本文參考連接:

http://msiyuetian.blog.51cto.com/8637744/1722406

http://www.osyunwei.com/archives/9313.html

http://blog.csdn.net/zhaowenzhong/article/details/51899093

不足之處,請多多指出!

相關文章
相關標籤/搜索