MongoDB基礎請參考:http://blog.51cto.com/kaliarch/2044423
MongoDB(replica set)請參考:http://blog.51cto.com/kaliarch/2044618
一、概述
1.1 背景
為解決mongodb在replica set每個從節點上面的數據庫均是對數據庫的全量拷貝,從節點壓力在高并發大數據量的場景下存在很大挑戰,同時考慮到后期mongodb集群的在數據壓力巨大時的擴展性,應對海量數據引出了分片機制。
1.2 分片概念
分片是將數據庫進行拆分,將其分散在不同的機器上的過程,無需功能強大的服務器就可以存儲更多的數據,處理更大的負載,在總數據中,將集合切成小塊,將這些塊分散到若干片中,每個片只負載總數據的一部分,通過一個知道數據與片對應關系的組件mongos的路由進程進行操作。
1.3 基礎組件
其利用到了四個組件:mongos,config server,shard,replica set
mongos:數據庫集群請求的入口,所有請求需要經過mongos進行協調,無需在應用層面利用程序來進行路由選擇,mongos其自身是一個請求分發中心,負責將外部的請求分發到對應的shard服務器上,mongos作為統一的請求入口,為防止mongos單節點故障,一般需要對其做HA。
config server:配置服務器,存儲所有數據庫元數據(分片,路由)的配置。mongos本身沒有物理存儲分片服務器和數據路由信息,只是存緩存在內存中來讀取數據,mongos在第一次啟動或后期重啟時候,就會從config server中加載配置信息,如果配置服務器信息發生更新會通知所有的mongos來更新自己的狀態,從而保證準確的請求路由,生產環境中通常也需要多個config server,防止配置文件存在單節點丟失問題。
shard:在傳統意義上來講,如果存在海量數據,單臺服務器存儲1T壓力非常大,無論考慮數據庫的硬盤,網絡IO,又有CPU,內存的瓶頸,如果多臺進行分攤1T的數據,到每臺上就是可估量的較小數據,在mongodb集群只要設置好分片規則,通過mongos操作數據庫,就可以自動把對應的操作請求轉發到對應的后端分片服務器上。
replica set:在總體mongodb集群架構中,對應的分片節點,如果單臺機器下線,對應整個集群的數據就會出現部分缺失,這是不能發生的,因此對于shard節點需要replica set來保證數據的可靠性,生產環境通常為2個副本+1個仲裁。
1.4 架構圖
二、安裝部署
2.1 基礎環境
為了節省服務器,采用多實例配置,三個mongos,三個config server,單個服務器上面運行不通角色的shard(為了后期數據分片均勻,將三臺shard在各個服務器上充當不同的角色。),在一個節點內采用replica set保證高可用,對應主機與端口信息如下:
主機名
IP地址
組件mongos
組件config server
shard
mongodb-1
172.20.6.10
端口:20000
端口:21000
主節點:?? 22001
副本節點:22002
仲裁節點:22003
mongodb-2
172.20.6.11
端口:20000
端口:21000
仲裁節點:22001
主節點:?? 22002
副本節點:22003
mongodb-3
172.20.6.12
端口:20000
端口:21000
副本節點:22001
仲裁節點:22002
主節點:?? 22003
2.2、安裝部署
2.2.1 軟件下載目錄創建
wget?-c?https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.4.10.tgz
tar?-zxvf?mongodb-linux-x86_64-rhel62-3.4.10.tgz
ln?-sv?mongodb-linux-x86_64-rhel62-3.4.10?mongodb
echo?"PATH=$PAHT:/usr/local/mongodb/bin">/etc/profile.d/mongodb.sh
source?/etc/profile.d/mongodb.sh
2.2.2 創建目錄
分別在mongodb-1/mongodb-2/mongodb-3創建目錄及日志文件
mkdir?-p?/data/mongodb/mongos/{log,conf}
mkdir?-p?/data/mongodb/mongoconf/{data,log,conf}
mkdir?-p?/data/mongodb/shard1/{data,log,conf}
mkdir?-p?/data/mongodb/shard2/{data,log,conf}
mkdir?-p?/data/mongodb/shard3/{data,log,conf}
touch?/data/mongodb/mongos/log/mongos.log
touch?/data/mongodb/mongoconf/log/mongoconf.log
touch?/data/mongodb/shard1/log/shard1.log
touch?/data/mongodb/shard2/log/shard2.log
touch?/data/mongodb/shard3/log/shard3.log
2.2.3 配置config server副本集
在mongodb3.4版本后要求配置服務器也創建為副本集,在此副本集名稱:replconf
在三臺服務器上配置config server副本集配置文件,并啟動服務
cat>/data/mongodb/mongoconf/conf/mongoconf.conf<
logpath=/data/mongodb/mongoconf/log/mongoconf.log????????#定義config?server日志文件
logappend=true
port?=?21000
maxConns?=?1000????????????#鏈接數
journal?=?true????????????#日志開啟
journalCommitInterval?=?200
fork?=?true????????????#后臺執行
syncdelay?=?60
oplogSize?=?1000
configsvr?=?true????????#配置服務器
replSet=replconf????????#config?server配置集replconf
EOF
mongod?-f?/data/mongodb/mongoconf/conf/mongoconf.conf????????#三臺服務器均啟動config?server
任意登錄一臺服務器進行配置服務器副本集初始化
use?admin
config?=?{_id:"replconf",members:[
{_id:0,host:"172.20.6.10:21000"},
{_id:1,host:"172.20.6.11:21000"},
{_id:2,host:"172.20.6.12:21000"},]
}
rs.initiate(config);
查看集群狀態:
replconf:OTHER>?rs.status()
{
"set"?:?"replconf",
"date"?:?ISODate("2017-12-04T07:42:09.054Z"),
"myState"?:?1,
"term"?:?NumberLong(1),
"configsvr"?:?true,
"heartbeatIntervalMillis"?:?NumberLong(2000),
"optimes"?:?{
"lastCommittedOpTime"?:?{
"ts"?:?Timestamp(1512373328,?1),
"t"?:?NumberLong(1)
},
"readConcernMajorityOpTime"?:?{
"ts"?:?Timestamp(1512373328,?1),
"t"?:?NumberLong(1)
},
"appliedOpTime"?:?{
"ts"?:?Timestamp(1512373328,?1),
"t"?:?NumberLong(1)
},
"durableOpTime"?:?{
"ts"?:?Timestamp(1512373328,?1),
"t"?:?NumberLong(1)
}
},
"members"?:?[
{
"_id"?:?0,
"name"?:?"172.20.6.10:21000",
"health"?:?1,
"state"?:?1,
"stateStr"?:?"PRIMARY",
"uptime"?:?221,
"optime"?:?{
"ts"?:?Timestamp(1512373328,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T07:42:08Z"),
"infoMessage"?:?"could?not?find?member?to?sync?from",
"electionTime"?:?Timestamp(1512373296,?1),
"electionDate"?:?ISODate("2017-12-04T07:41:36Z"),
"configVersion"?:?1,
"self"?:?true
},
{
"_id"?:?1,
"name"?:?"172.20.6.11:21000",
"health"?:?1,
"state"?:?2,
"stateStr"?:?"SECONDARY",
"uptime"?:?42,
"optime"?:?{
"ts"?:?Timestamp(1512373318,?1),
"t"?:?NumberLong(1)
},
"optimeDurable"?:?{
"ts"?:?Timestamp(1512373318,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T07:41:58Z"),
"optimeDurableDate"?:?ISODate("2017-12-04T07:41:58Z"),
"lastHeartbeat"?:?ISODate("2017-12-04T07:42:08.637Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T07:42:07.648Z"),
"pingMs"?:?NumberLong(0),
"syncingTo"?:?"172.20.6.10:21000",
"configVersion"?:?1
},
{
"_id"?:?2,
"name"?:?"172.20.6.12:21000",
"health"?:?1,
"state"?:?2,
"stateStr"?:?"SECONDARY",
"uptime"?:?42,
"optime"?:?{
"ts"?:?Timestamp(1512373318,?1),
"t"?:?NumberLong(1)
},
"optimeDurable"?:?{
"ts"?:?Timestamp(1512373318,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T07:41:58Z"),
"optimeDurableDate"?:?ISODate("2017-12-04T07:41:58Z"),
"lastHeartbeat"?:?ISODate("2017-12-04T07:42:08.637Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T07:42:07.642Z"),
"pingMs"?:?NumberLong(0),
"syncingTo"?:?"172.20.6.10:21000",
"configVersion"?:?1
}
],
"ok"?:?1
}
此時config server集群已經配置完成,mongodb-1為primary,mongdb-2/mongodb-3為secondary
2.2.4 配置shard集群
三臺服務器均進行shard集群配置
shard1配置
cat?>/data/mongodb/shard1/conf/shard.conf?<
dbpath=/data/mongodb/shard1/data
logpath?=?/data/mongodb/shard1/log/shard1.log
port?=?22001
logappend?=?true
nohttpinterface?=?true
fork?=?true
oplogSize?=?4096
journal?=?true
#engine?=?wiredTiger
#cacheSizeGB?=?38G
smallfiles=true
shardsvr=true????????#shard服務器
replSet=shard1????????#副本集名稱shard1
EOF
mongod?-f?/data/mongodb/shard1/conf/shard.conf????????#啟動shard服務
查看此時服務已經正常啟動,shard1的22001端口已經正常監聽,接下來登錄mongodb-1服務器進行shard1副本集初始化
mongo?172.20.6.10:22001
use?admin
config?=?{_id:"shard1",members:[
{_id:0,host:"172.20.6.10:22001"},
{_id:1,host:"172.20.6.11:22001",arbiterOnly:true},
{_id:2,host:"172.20.6.12:22001"},]
}
rs.initiate(config);
查看集群狀態,只列出了部分信息:
{
"_id"?:?0,
"name"?:?"172.20.6.10:22001",
"health"?:?1,
"state"?:?1,
"stateStr"?:?"PRIMARY",????????????#mongodb-1為primary
"uptime"?:?276,
"optime"?:?{
"ts"?:?Timestamp(1512373911,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T07:51:51Z"),
"infoMessage"?:?"could?not?find?member?to?sync?from",
"electionTime"?:?Timestamp(1512373879,?1),
"electionDate"?:?ISODate("2017-12-04T07:51:19Z"),
"configVersion"?:?1,
"self"?:?true
},
{
"_id"?:?1,
"name"?:?"172.20.6.11:22001",
"health"?:?1,
"state"?:?7,
"stateStr"?:?"ARBITER",????????????#mongodb-2為arbiter
"uptime"?:?45,
"lastHeartbeat"?:?ISODate("2017-12-04T07:51:53.597Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T07:51:51.243Z"),
"pingMs"?:?NumberLong(0),
"configVersion"?:?1
},
{
"_id"?:?2,
"name"?:?"172.20.6.12:22001",
"health"?:?1,
"state"?:?2,
"stateStr"?:?"SECONDARY",????????#mongodb-3為secondary
"uptime"?:?45,
"optime"?:?{
"ts"?:?Timestamp(1512373911,?1),
"t"?:?NumberLong(1)
},
此時shard1 副本集已經配置完成,mongodb-1為primary,mongodb-2為arbiter,mongodb-3為secondary。
同樣的操作進行shard2配置和shard3配置
注意:進行shard2的副本集初始化,在mongodb-2, 初始化shard3副本集在mongodb-3上進行操作。
shard2配置文件
cat?>/data/mongodb/shard2/conf/shard.conf?<
dbpath=/data/mongodb/shard2/data
logpath?=?/data/mongodb/shard2/log/shard2.log
port?=?22002
logappend?=?true
nohttpinterface?=?true
fork?=?true
oplogSize?=?4096
journal?=?true
#engine?=?wiredTiger
#cacheSizeGB?=?38G
smallfiles=true
shardsvr=true
replSet=shard2
EOF
mongod?-f?/data/mongodb/shard2/conf/shard.conf
shard3配置文件
cat?>/data/mongodb/shard3/conf/shard.conf?<
dbpath=/data/mongodb/shard3/data
logpath?=?/data/mongodb/shard3/log/shard3.log
port?=?22003
logappend?=?true
nohttpinterface?=?true
fork?=?true
oplogSize?=?4096
journal?=?true
#engine?=?wiredTiger
#cacheSizeGB?=?38G
smallfiles=true
shardsvr=true
replSet=shard3
EOF
mongod?-f?/data/mongodb/shard2/conf/shard.conf
在mongodb-2上進行shard2副本集初始化
mongo?172.20.6.11:22002????#登錄mongodb-2
use?admin
config?=?{_id:"shard2",members:[
{_id:0,host:"172.20.6.10:22002"},
{_id:1,host:"172.20.6.11:22002"},
{_id:2,host:"172.20.6.12:22002",arbiterOnly:true},]
}
rs.initiate(config);
查看shard2副本集狀態
{
"_id"?:?0,
"name"?:?"172.20.6.10:22002",
"health"?:?1,
"state"?:?2,
"stateStr"?:?"SECONDARY",????????#mongodb-2為secondary
"uptime"?:?15,
"optime"?:?{
"ts"?:?Timestamp(1512374668,?1),
"t"?:?NumberLong(1)
},
"optimeDurable"?:?{
"ts"?:?Timestamp(1512374668,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T08:04:28Z"),
"optimeDurableDate"?:?ISODate("2017-12-04T08:04:28Z"),
"lastHeartbeat"?:?ISODate("2017-12-04T08:04:30.527Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T08:04:28.492Z"),
"pingMs"?:?NumberLong(0),
"syncingTo"?:?"172.20.6.11:22002",
"configVersion"?:?1
},
{
"_id"?:?1,
"name"?:?"172.20.6.11:22002",
"health"?:?1,
"state"?:?1,
"stateStr"?:?"PRIMARY",????????#mongodb-2為primary
"uptime"?:?211,
"optime"?:?{
"ts"?:?Timestamp(1512374668,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T08:04:28Z"),
"infoMessage"?:?"could?not?find?member?to?sync?from",
"electionTime"?:?Timestamp(1512374666,?1),
"electionDate"?:?ISODate("2017-12-04T08:04:26Z"),
"configVersion"?:?1,
"self"?:?true
},
{
"_id"?:?2,
"name"?:?"172.20.6.12:22002",????????#mongodb-3為arbiter
"health"?:?1,
"state"?:?7,
"stateStr"?:?"ARBITER",
"uptime"?:?15,
"lastHeartbeat"?:?ISODate("2017-12-04T08:04:30.527Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T08:04:28.384Z"),
"pingMs"?:?NumberLong(0),
"configVersion"?:?1
}
登錄mongodb-3進行shard3副本集初始化
mongo?172.20.6.12:22003????#登錄mongodb-3
use?admin
config?=?{_id:"shard3",members:[
{_id:0,host:"172.20.6.10:22003",arbiterOnly:true},
{_id:1,host:"172.20.6.11:22003"},
{_id:2,host:"172.20.6.12:22003"},]
}
rs.initiate(config);
查看shard3副本集狀態
{
"_id"?:?0,
"name"?:?"172.20.6.10:22003",
"health"?:?1,
"state"?:?7,
"stateStr"?:?"ARBITER",????????#mongodb-1為arbiter
"uptime"?:?18,
"lastHeartbeat"?:?ISODate("2017-12-04T08:07:37.488Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T08:07:36.224Z"),
"pingMs"?:?NumberLong(0),
"configVersion"?:?1
},
{
"_id"?:?1,
"name"?:?"172.20.6.11:22003",
"health"?:?1,
"state"?:?2,
"stateStr"?:?"SECONDARY",????????#mongodb-2為secondary
"uptime"?:?18,
"optime"?:?{
"ts"?:?Timestamp(1512374851,?1),
"t"?:?NumberLong(1)
},
"optimeDurable"?:?{
"ts"?:?Timestamp(1512374851,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T08:07:31Z"),
"optimeDurableDate"?:?ISODate("2017-12-04T08:07:31Z"),
"lastHeartbeat"?:?ISODate("2017-12-04T08:07:37.488Z"),
"lastHeartbeatRecv"?:?ISODate("2017-12-04T08:07:36.297Z"),
"pingMs"?:?NumberLong(0),
"syncingTo"?:?"172.20.6.12:22003",
"configVersion"?:?1
},
{
"_id"?:?2,
"name"?:?"172.20.6.12:22003",
"health"?:?1,
"state"?:?1,
"stateStr"?:?"PRIMARY",????????#mongodb-3為primary
"uptime"?:?380,
"optime"?:?{
"ts"?:?Timestamp(1512374851,?1),
"t"?:?NumberLong(1)
},
"optimeDate"?:?ISODate("2017-12-04T08:07:31Z"),
"infoMessage"?:?"could?not?find?member?to?sync?from",
"electionTime"?:?Timestamp(1512374849,?1),
"electionDate"?:?ISODate("2017-12-04T08:07:29Z"),
"configVersion"?:?1,
"self"?:?true
}
此時shard集群全部已經配置完畢。
2.2.5 配置路由服務器mongos
目前三臺服務器的配置服務器和分片服務器均已啟動,配置三臺mongos服務器
由于mongos服務器的配置是從內存中加載,所以自己沒有存在數據目錄configdb連接為配置服務器集群
cat?>/data/mongodb/mongos/conf/mongos.conf<
--logpath=/data/mongodb/mongos/log/mongos.log
logappend=true
port?=?20000
maxConns?=?1000
configdb=replconf/172.20.6.10:21000,172.20.6.11:21000,172.20.6.12:21000???#制定config?server集群
fork?=?true
EOF
mongos?-f?/data/mongodb/mongos/conf/mongos.conf????????#啟動mongos服務
目前config server集群/shard集群/mongos服務均已啟動,但此時為設置分片,還不能使用分片功能。需要登錄mongos啟用分片
登錄任意一臺mongos
mongo?172.20.6.10:20000
use?admin
db.runCommand({addshard:"shard1/172.20.6.10:22001,172.20.6.11:22001,172.20.6.12:22001"})
db.runCommand({addshard:"shard2/172.20.6.10:22002,172.20.6.11:22002,172.20.6.12:22002"})
db.runCommand({addshard:"shard3/172.20.6.10:22003,172.20.6.11:22003,172.20.6.12:22003"})
查看集群
三、 測試
目前配置服務、路由服務、分片服務、副本集服務都已經串聯起來了,此時進行數據插入,數據能夠自動分片。連接在mongos上讓指定的數據庫、指定的集合分片生效。
注意:設置分片需要在admin數據庫進行
use?admin
db.runCommand(?{?enablesharding?:"kaliarchdb"});????#開啟kaliarch庫分片功能
db.runCommand(?{?shardcollection?:?"kaliarchdb.table1",key?:?{_id:"hashed"}?}?)????#指定數據庫里需要分片的集合tables和片鍵_id
設置kaliarchdb的 table1 表需要分片,根據 _id 自動分片到 shard1 ,shard2,shard3 上面去。
查看分片信息
測試插入數據
use?kaliarchdb;
for?(var?i?=?1;?i?<=?100000;?i++)?db.table1.save({_id:i,"test1":"testval1"});
查看分片情況:(省去部分信息)
db.table1.stats()
{
"sharded"?:?true,
"capped"?:?false,
"ns"?:?"kaliarchdb.table1",
"count"?:?100000,????????#總count
"size"?:?3800000,
"storageSize"?:?1335296,
"totalIndexSize"?:?4329472,
"indexSizes"?:?{
"_id_"?:?1327104,
"_id_hashed"?:?3002368
},
"avgObjSize"?:?38,
"nindexes"?:?2,
"nchunks"?:?6,
"shards"?:?{
"shard1"?:?{
"ns"?:?"kaliarchdb.table1",
"size"?:?1282690,
"count"?:?33755,????????#shard1的count數
"avgObjSize"?:?38,
"storageSize"?:?450560,
"capped"?:?false,
......
"shard2"?:?{
"ns"?:?"kaliarchdb.table1",
"size"?:?1259434,
"count"?:?33143,????????#shard2的count數
"avgObjSize"?:?38,
"storageSize"?:?442368,
"capped"?:?false,
.......
"shard3"?:?{
"ns"?:?"kaliarchdb.table1",
"size"?:?1257876,
"count"?:?33102,????????????#shard3的count數
"avgObjSize"?:?38,
"storageSize"?:?442368,
"capped"?:?false,
此時架構中的mongos,config server,shard集群均已經搭建部署完畢,在實際生成環境話需要對前端的mongos做高可用來提示整體高可用。