MongoDBマスターコピーとコピーセット
29998 ワード
MongoDBレプリケーション
コンセプト
レプリケーションは、複数のサーバ間でデータを同期するプロセスです.
レプリケーションの特徴
マスターコピー
プライマリ・スレーブ・レプリケーションは、バックアップ、障害復旧、読み取り拡張などに使用できます.基本的には、プライマリ・ノードと1つ以上のセカンダリ・ノードを構築し、データベース・クラスタでプライマリ・サーバが誰であるかを明確に知る必要があります.プライマリ・サーバは1台しかありません.サーバからは、自分のデータ・ソース、すなわち対応するプライマリ・サービスが誰であるかを知る必要があります.
mongod --master
を実行してプライマリ・サーバを起動します.mongod --slave --source master_address
を実行してサーバから起動します.構成の調整
主にdbPathとlog pathを指定し、masterは以下のように構成されています.
$ cat master.conf
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: /home/work/mongo/master
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /home/work/mongo/master/mongod.log
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1
mongoインスタンスの起動
mongod -f master.conf --logappend --master --fork
mongod -f slave-1.conf --logappend --slave --fork --source localhost:27017
mongod -f slave-2.conf --logappend --slave --fork --source localhost:27017
すべてのスレーブノードはプライマリノードから情報をコピーし、ノードからスレーブノードへのメカニズムをコピーすることはできません.これは、ノードに独自のoplogがないためです.1つのクラスタではノードから明確な制限はないが,複数のノードが単一のホストに対して開始したクエリも耐えられず,12ノードを超えないクラスタは良好に動作する.
機能テスト
プライマリ・ライブラリにuserセットにデータを挿入します.
> use test
switched to db test
> db.user.insert({'u':'test', 'p':'pwd'})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("59c8d10c836ac6ec4e425fc5"), "u" : "test", "p" : "pwd" }
ライブラリからログインすると、userセットが挿入したレコードが同期していることがわかります.
> rs.slaveOk()
> show dbs
admin 0.000GB
local 0.000GB
test 0.000GB
> use test
switched to db test
> show collections;
user
> db.user.find()
{ "_id" : ObjectId("59c8d10c836ac6ec4e425fc5"), "u" : "test", "p" : "pwd" }
その他の構成アイテム
レプリカセット(Replica Set)
レプリカセットは、1つのprimaryノードと1つ以上のsecondaryノードからなる自動フェイルオーバ機能を持つプライマリ・スレーブ・クラスタです.プライマリ・スレーブ・クラスタとレプリカ・セットの最も明らかな違いは、レプリカ・セットに固定されたプライマリ・ノードがないことです.クラスタ全体がプライマリ・ノードを選択し、動作しない場合は他のノードに変更します.レプリカセットには、アクティブなノードと1つ以上のバックアップノードがあります.
さぎょうげんり
インスタンスの起動
rep 1,2,3はそれぞれ270127070701827019ポートで起動した.
work@jdu4e00u53f7:~/mongo$ mongod -f rep1.conf --replSet rs0 --fork
work@jdu4e00u53f7:~/mongo$ mongod -f rep2.conf --replSet rs0 --fork
work@jdu4e00u53f7:~/mongo$ mongod -f rep3.conf --replSet rs0 --fork
work@jdu4e00u53f7:~/mongo$ mongo --port 27017
レプリカセットの初期化
> rsconf = {'_id':'rs0', 'members':[{'_id': 0, 'host':'127.0.0.1:27017'}, {'_id': 1, 'host': '127.0.0.1:27018'}, {'_id':2, 'host': '127.0.0.1:27019'}]}
{
"_id" : "rs0",
"members" : [
{
"_id" : 0,
"host" : "127.0.0.1:27017"
},
{
"_id" : 1,
"host" : "127.0.0.1:27018"
},
{
"_id" : 2,
"host" : "127.0.0.1:27019"
}
]
}
> rs.initiate(rsconf)
{ "ok" : 1 }
現在の構成の表示
rs0:OTHER> rs.conf()
{
"_id" : "rs0",
"version" : 1,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "127.0.0.1:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "127.0.0.1:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "127.0.0.1:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : 60000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("59c8e527002aa17b30c3408c")
}
}
mongodbでは、構成内のノードがレプリカセットrs 0に自動的に追加されます.
プライマリノードの表示
rs0:SECONDARY> rs.isMaster()
{
"hosts" : [
"127.0.0.1:27017",
"127.0.0.1:27018",
"127.0.0.1:27019"
],
"setName" : "rs0",
"setVersion" : 1,
"ismaster" : false,
"secondary" : true,
"primary" : "127.0.0.1:27017",
"me" : "127.0.0.1:27018",
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1506338789, 1),
"t" : NumberLong(1)
},
"lastWriteDate" : ISODate("2017-09-25T11:26:29Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2017-09-25T11:26:37.835Z"),
"maxWireVersion" : 5,
"minWireVersion" : 0,
"readOnly" : false,
"ok" : 1
}
oplogステータスの表示
rs0:SECONDARY> db.printReplicationInfo()
configured oplog size: 1214.6957025527954MB
log length start to end: 862secs (0.24hrs)
oplog first event time: Mon Sep 25 2017 19:14:47 GMT+0800 (CST)
oplog last event time: Mon Sep 25 2017 19:29:09 GMT+0800 (CST)
now: Mon Sep 25 2017 19:29:15 GMT+0800 (CST)
機能テスト
レプリケーション機能
メインライブラリにデータを挿入します.
rs0:PRIMARY> use testdb
switched to db testdb
rs0:PRIMARY> db.user.insert({'u':'test', 'p':'123'})
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.user.find()
{ "_id" : ObjectId("59c8e698c28239e0dfd6f578"), "u" : "test", "p" : "123" }
ライブラリからログインすると、データが同期していることがわかります.
$ mongo --port 27018
rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> show dbs;
admin 0.000GB
local 0.000GB
testdb 0.000GB
rs0:SECONDARY> use testdb
switched to db testdb
rs0:SECONDARY> db.user.find()
{ "_id" : ObjectId("59c8e698c28239e0dfd6f578"), "u" : "test", "p" : "123" }
じどうフェイルオーバ
プライマリノードを閉じる
# primary
$ mongo --port 27017
# admin ( admin )
rs0:PRIMARY> use admin
switched to db admin
rs0:PRIMARY> db.shutdownServer()
server should be down...
ノードのステータスの表示
rs0:PRIMARY> rs.status()
{
"set" : "rs0",
"date" : ISODate("2017-09-25T11:31:22.492Z"),
"myState" : 1,
"term" : NumberLong(2),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1506339074, 1),
"t" : NumberLong(2)
},
"appliedOpTime" : {
"ts" : Timestamp(1506339074, 1),
"t" : NumberLong(2)
},
"durableOpTime" : {
"ts" : Timestamp(1506339074, 1),
"t" : NumberLong(2)
}
},
"members" : [
{
"_id" : 0,
"name" : "127.0.0.1:27017",
"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-09-25T11:31:21.532Z"),
"lastHeartbeatRecv" : ISODate("2017-09-25T11:30:42.934Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Connection refused",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "127.0.0.1:27018",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1057,
"optime" : {
"ts" : Timestamp(1506339074, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2017-09-25T11:31:14Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1506339053, 1),
"electionDate" : ISODate("2017-09-25T11:30:53Z"),
"configVersion" : 1,
"self" : true
},
{
"_id" : 2,
"name" : "127.0.0.1:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 992,
"optime" : {
"ts" : Timestamp(1506339074, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1506339074, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2017-09-25T11:31:14Z"),
"optimeDurableDate" : ISODate("2017-09-25T11:31:14Z"),
"lastHeartbeat" : ISODate("2017-09-25T11:31:21.530Z"),
"lastHeartbeatRecv" : ISODate("2017-09-25T11:31:21.725Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "127.0.0.1:27018",
"configVersion" : 1
}
],
"ok" : 1
}
127.0.0.1:27017
はすでに到達不可能な状態であることがわかる.127.0.0.1:27018
は新しいプライマリノードとして選択される.自動フェイルオーバテストに成功しました.27017のインスタンスを再起動すると、127.0.0.1:27017
がスレーブノードになることがわかります.その他の構成
運用環境
京東入門級クラウドサーバー、Ubuntu 16.04,Mongo3.4