mongodb集羣搭建

mongodb集羣有三種方式

    1,主從模式,類似mysql master slave方式。

    2,副本集模式,其實是一主多從,如果主節點掛掉,會重新在從節點選取一臺爲主節點。

    3,分片模式,針對大數據量,高負載情況。

wKioL1UsvwCgUF0jAAG8apv8TOY057.jpg

從圖中可以看到有四個組件:mongos、config server、shard、replica set。

mongos,數據庫集羣請求的入口,所有的請求都通過mongos進行協調,不需要在應用程序添加一個路由選擇器,mongos自己就是一個請求分發中心,它負責把對應的數據請求請求轉發到對應的shard服務器上。在生產環境通常有多mongos作爲請求的入口,防止其中一個掛掉所有的mongodb請求都沒有辦法操作。

config server,顧名思義爲配置服務器,存儲所有數據庫元信息(路由、分片)的配置。mongos本身沒有物理存儲分片服務器和數據路由信息,只是緩存在內存裏,配置服務器則實際存儲這些數據。mongos第一次啓動或者關掉重啓就會從 config server 加載配置信息,以後如果配置服務器信息變化會通知到所有的 mongos 更新自己的狀態,這樣 mongos 就能繼續準確路由。在生產環境通常有多個 config server 配置服務器,因爲它存儲了分片路由的元數據,這個可不能丟失!就算掛掉其中一臺,只要還有存貨, mongodb集羣就不會掛掉。

shard,這就是傳說中的分片了。上面提到一個機器就算能力再大也有天花板,就像軍隊打仗一樣,一個人再厲害喝血瓶也拼不過對方的一個師。俗話說三個臭皮匠頂個諸葛亮,這個時候團隊的力量就凸顯出來了。在互聯網也是這樣,一臺普通的機器做不了的多臺機器來做,如下圖:

wKiom1UsviPDW-8HAAGzUzKmy3A693.jpg

一臺機器的一個數據表 Collection1 存儲了 1T 數據,壓力太大了!在分給4個機器後,每個機器都是256G,則分攤了集中在一臺機器的壓力。也許有人問一臺機器硬盤加大一點不就可以了,爲什麼要分給四臺機器呢?不要光想到存儲空間,實際運行的數據庫還有硬盤的讀寫、網絡的IO、CPU和內存的瓶頸。在mongodb集羣只要設置好了分片規則,通過mongos操作數據庫就能自動把對應的數據操作請求轉發到對應的分片機器上。在生產環境中分片的片鍵可要好好設置,這個影響到了怎麼把數據均勻分到多個分片機器上,不要出現其中一臺機器分了1T,其他機器沒有分到的情況,這樣還不如不分片!

replica set,上兩節已經詳細講過了這個東東,怎麼這裏又來湊熱鬧!其實上圖4個分片如果沒有 replica set 是個不完整架構,假設其中的一個分片掛掉那四分之一的數據就丟失了,所以在高可用性的分片架構還需要對於每一個分片構建 replica set 副本集保證分片的可靠性。生產環境通常是 2個副本 + 1個仲裁。

說了這麼多,還是來實戰一下如何搭建高可用的mongodb集羣:

首先確定各個組件的數量,mongos 3個, config server 3個,數據分3片 shard server 3個,每個shard 有一個副本一個仲裁也就是 3 * 2 = 6 個,總共需要部署15個實例。這些實例可以部署在獨立機器也可以部署在一臺機器,我們這裏測試資源有限,只准備了 3臺機器,在同一臺機器只要端口不同就可以,看一下物理部署圖:

wKioL1UswCjgmYTwAAUnOHDR7OI538.jpg


下面是安裝配置

1,準備三臺機器

ip:10.19.21.241

   10.19.21.242

   10.19.21.243

2,分別在每臺機器上建立mongodb數據目錄

 我使用ansible工具來創建目錄

創建存放mongodb數據文件

ansible mongodb -m shell -a "mkdir /data/mongodb -p"

3,安裝mongodb,這裏使用yum來安裝

配置yum repo

vim /etc/yum.repos.d/mongodb-org.repo
[mongodb-org-2.6]
name=MongoDB 2.6 Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/
gpgcheck=0
enabled=1

拷貝過去

ansible mongodb -m copy -a "src=mongodb/mongodb-org.repo dest=/etc/yum.repos.d/"

錯誤如下:
10.19.21.243 | FAILED >> {
"checksum": "d79d6075271e933b3811455e74eaa9ef47f593e6",
"failed": true,
"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
}
解決方法:
ansible mongodb -m yum -a "name=libselinux-python state=latest"

安裝mongodb

ansible mongodb -m yum -a "name=mongodb-org state=latest"

4,每臺上創建mongos config shard1 shard2 shard3五個目錄,因爲mongos不存儲數據,只需建立日誌文件目錄

建立mongos目錄和日誌目錄

ansible mongodb -m shell -a "mkdir -p /data/mongodb/mongos/log"

建立config server數據目錄

ansible mongodb -m shell -a "mkdir -p /data/mongodb/config/data"

建立config server日誌目錄

ansible mongodb -m shell -a "mkdir -p /data/mongodb/config/log"

建立shard1數據目錄和日誌目錄

ansible mongodb -m shell -a "mkdir -p /data/mongodb/shard1/data /data/mongodb/shard1/log"

建立shard2數據目錄和日誌目錄

ansible mongodb -m shell -a "mkdir -p /data/mongodb/shard2/data /data/mongodb/shard2/log"

建立shard3數據目錄和日誌目錄

ansible mongodb -m shell -a "mkdir -p /data/mongodb/shard3/data /data/mongodb/shard3/log"

5,規劃5個組件對應的端口號,由於一個機器需要同時部署mongos, config server, shard1, shard2, shard3,所以需要用端口號進行區分

這個端口號可以自己定義,mongos:20000,config server:21000, shard1:22001, shard2:22002, shard3:22003


6,配置每臺服務器的配置文件

由於我們的mongodb是yum安裝,會有一個默認的配置文件,需要先備份

ansible mongodb -m shell -a "mv /etc/mongod.conf /etc/mongod.conf.bak"

配置每臺服配置服務器

cat mongod-configsvr.conf
dbpath=/data/mongodb/config/data
port=21000
logpath=/data/mongodb/config/log/config.log
fork=true
configsvr=true
logappend=true

配置每臺mongos服務器

cat mongod-mongos.conf
configdb=10.19.21.241:21000,10.19.21.242:21000,10.19.21.243:21000
port=20000
logpath=/data/mongodb/mongos/log/mongos.log
logappend=true
fork=true

配置各個分片的副本集

cat mongod-shardsvr1.conf
shardsvr=true
replSet=shard1
port=22001
dbpath=/data/mongodb/shard1/data
logpath=/data/mongodb/shard1/log/shard1.log
fork=true
logappend=true

cat mongod-shardsvr2.conf
shardsvr=true
replSet=shard2
port=22002
dbpath=/data/mongodb/shard2/data
logpath=/data/mongodb/shard2/log/shard2.log
fork=true
logappend=true

cat mongod-shardsvr3.conf
shardsvr=true
replSet=shard3
port=22003
dbpath=/data/mongodb/shard3/data
logpath=/data/mongodb/shard3/log/shard3.log
fork=true
logappend=true

創建配置文件目錄

ansible mongodb -m shell -a "mkdir /etc/mongodb"

拷貝配置文件到目錄

ansible mongodb -m copy -a "src=mongodb/mongod-configsvr.conf dest=/etc/mongodb/"
ansible mongodb -m copy -a "src=mongodb/mongod-mongos.conf dest=/etc/mongodb/"
ansible mongodb -m copy -a "src=mongodb/mongod-shardsvr1.conf dest=/etc/mongodb/"
ansible mongodb -m copy -a "src=mongodb/mongod-shardsvr2.conf dest=/etc/mongodb/"
ansible mongodb -m copy -a "src=mongodb/mongod-shardsvr3.conf dest=/etc/mongodb/"

啓動服務

ansible mongodb -m shell -a "mongod -f /etc/mongodb/mongod-configsvr.conf"
ansible mongodb -m shell -a "mongos -f /etc/mongodb/mongod-mongos.conf"

啓動這個報錯了
2015-04-10T20:42:37.340+0800 [mongosMain] MongoS version 2.6.9 starting: pid=19701 port=20000 64-bit host=VM-241 (--help for usage)
2015-04-10T20:42:37.340+0800 [mongosMain] db version v2.6.9
2015-04-10T20:42:37.340+0800 [mongosMain] git version: df313bc75aa94d192330cb92756fc486ea604e64
2015-04-10T20:42:37.340+0800 [mongosMain] build info: Linux build20.nj1.10gen.cc 2.6.32-431.3.1.el6.x86_64 #1 SMP Fri Jan 3 21:39:27 UTC 2014 x86_64 BOOST_LIB_VERSION=1_49
2015-04-10T20:42:37.340+0800 [mongosMain] allocator: tcmalloc
2015-04-10T20:42:37.341+0800 [mongosMain] options: { config: "/etc/mongodb/mongod-mongos.conf", net: { port: 20000 }, processManagement: { fork: true }, sharding: { configDB: "10.19.21.241:21000,10.19.21.242:21000,10.19.21.243:21000" }, systemLog: { destination: "file", path: "/data/mongodb/mongos/log/mongos.log" } }
2015-04-10T20:42:37.345+0800 [mongosMain] SyncClusterConnection connecting to [10.19.21.241:21000]
2015-04-10T20:42:37.346+0800 [mongosMain] SyncClusterConnection connecting to [10.19.21.242:21000]
2015-04-10T20:42:37.349+0800 [mongosMain] SyncClusterConnection connecting to [10.19.21.243:21000]
2015-04-10T20:42:37.414+0800 [mongosMain] scoped connection to 10.19.21.241:21000,10.19.21.242:21000,10.19.21.243:21000 not being returned to the pool
2015-04-10T20:42:48.522+0800 [mongosMain] waited 11s for distributed lock configUpgrade for upgrading config database to new format v5
2015-04-10T20:42:59.622+0800 [mongosMain] waited 22s for distributed lock configUpgrade for upgrading config database to new format v5
2015-04-10T20:43:10.720+0800 [mongosMain] waited 33s for distributed lock configUpgrade for upgrading config database to new format v5

然後網上找了下原因,由於每臺服務器時間不同步導致

這個坑爹問題都出現,看來是不夠仔細

ansible mongodb -m shell -a "date"
10.19.21.243 | success | rc=0 >>
Thu Apr  9 22:11:05 CST 2015
10.19.21.241 | success | rc=0 >>
Fri Apr 10 20:45:27 CST 2015
10.19.21.242 | success | rc=0 >>
Thu Apr  9 22:09:13 CST 2015
一看果然有問題

執行命令同步時間服務器

ansible mongodb -m shell -a "/usr/sbin/ntpdate cn.pool.ntp.org"
10.19.21.242 | FAILED | rc=127 >>
/bin/sh: /usr/sbin/ntpdate: No such file or directory
10.19.21.243 | FAILED | rc=127 >>
/bin/sh: /usr/sbin/ntpdate: No such file or directory
10.19.21.241 | success | rc=0 >>
13 Apr 17:11:59 ntpdate[19842]: adjust time server 202.112.29.82 offset 0.000138 sec

尼瑪只有一臺能正常同步,估計沒有安裝ntpdate命令

ansible mongodb -m shell -a "yum install ntpdate -y"
ansible mongodb -m shell -a "/usr/sbin/ntpdate cn.pool.ntp.org"
10.19.21.243 | success | rc=0 >>
13 Apr 17:14:03 ntpdate[2661]: step time server 202.112.31.197 offset 327602.420329 sec
10.19.21.241 | success | rc=0 >>
13 Apr 17:14:03 ntpdate[19888]: adjust time server 202.112.29.82 offset 0.004004 sec
10.19.21.242 | success | rc=0 >>
13 Apr 17:14:03 ntpdate[2681]: step time server 202.112.31.197 offset 327714.079649 sec
ansible mongodb -m shell -a "date"
10.19.21.242 | success | rc=0 >>
Mon Apr 13 17:14:08 CST 2015
10.19.21.243 | success | rc=0 >>
Mon Apr 13 17:14:08 CST 2015
10.19.21.241 | success | rc=0 >>
Mon Apr 13 17:14:08 CST 2015
順便把硬件時間也同步下
ansible mongodb -m shell -a "hwclock --systohc"
10.19.21.241 | success | rc=0 >>
10.19.21.243 | success | rc=0 >>
10.19.21.242 | success | rc=0 >>
繼續啓動mongos
ansible mongodb -m shell -a "mongos -f /etc/mongodb/mongod-mongos.conf"
10.19.21.243 | success | rc=0 >>
about to fork child process, waiting until server is ready for connections.
forked process: 2708
child process started successfully, parent exiting
10.19.21.241 | success | rc=0 >>
about to fork child process, waiting until server is ready for connections.
forked process: 19968
child process started successfully, parent exiting
10.19.21.242 | success | rc=0 >>
about to fork child process, waiting until server is ready for connections.
forked process: 2728
child process started successfully, parent exiting

啓動各個分片的副本集

ansible mongodb -m shell -a "mongod -f /etc/mongodb/mongod-shardsvr1.conf"
ansible mongodb -m shell -a "mongod -f /etc/mongodb/mongod-shardsvr2.conf"
ansible mongodb -m shell -a "mongod -f /etc/mongodb/mongod-shardsvr3.conf"

順便關閉開機自動啓動mongod

ansible mongodb -m shell -a "chkconfig mongod off"
10.19.21.243 | success | rc=0 >>
10.19.21.242 | success | rc=0 >>
10.19.21.241 | success | rc=0 >>

6,登陸任意一臺,連接mongodb

設置第一個分片副本集

[root@VM-241 ~]# mongo 127.0.0.1:22001
MongoDB shell version: 2.6.9
connecting to: 127.0.0.1:22001/test

使用admin數據庫

mongos> use admin
switched to db admin

定義副本集配置

mongos> config={_id:"shard1",members:[{_id:0,host:"10.19.21.241:22001"},{_id:1,host:"10.19.21.242:22001"},{_id:2,host:"10.19.21.243:22001",arbiterOnly:true}]}
{
"_id" : "shard1",
"members" : [
{
"_id" : 0,
"host" : "10.19.21.241:22001"
},
{
"_id" : 1,
"host" : "10.19.21.242:22001"
},
{
"_id" : 2,
"host" : "10.19.21.243:22001",
"arbiterOnly" : true
}
]
}

初始化副本集配置

> rs.initiate(config);
{
"info" : "Config now saved locally.  Should come online in about a minute.",
"ok" : 1
}


設置第二個分片副本集

[root@VM-241 ~]# mongo 127.0.0.1:22002
MongoDB shell version: 2.6.9
connecting to: 127.0.0.1:22002/test
> use admin
switched to db admin
> config={_id:"shard2",members:[{_id:0,host:"10.19.21.241:22002"},{_id:1,host:"10.19.21.242:22002"},{_id:2,host:"10.19.21.243:22002",arbiterOnly:true}]}
{
"_id" : "shard2",
"members" : [
{
"_id" : 0,
"host" : "10.19.21.241:22002"
},
{
"_id" : 1,
"host" : "10.19.21.242:22002"
},
{
"_id" : 2,
"host" : "10.19.21.243:22002",
"arbiterOnly" : true
}
]
}
> rs.initiate(config);
{
"info" : "Config now saved locally.  Should come online in about a minute.",
"ok" : 1
}

設置第三個分片副本集

[root@VM-241 ~]# mongo 127.0.0.1:22003
MongoDB shell version: 2.6.9
connecting to: 127.0.0.1:22003/test
> use admin
switched to db admin
> config={_id:"shard3",members:[{_id:0,host:"10.19.21.241:22003"},{_id:1,host:"10.19.21.242:22003"},{_id:2,host:"10.19.21.243:22003",arbiterOnly:true}]}
{
"_id" : "shard3",
"members" : [
{
"_id" : 0,
"host" : "10.19.21.241:22003"
},
{
"_id" : 1,
"host" : "10.19.21.242:22003"
},
{
"_id" : 2,
"host" : "10.19.21.243:22003",
"arbiterOnly" : true
}
]
}
> rs.initiate(config);
{
"info" : "Config now saved locally.  Should come online in about a minute.",
"ok" : 1
}

7,配置分片

目前搭建的mongodb配置服務器,路由服務器,各個分片服務器,不過應用程序連接到mongs路由服務器並不能使用分片機制,還需要在程序裏設置分片配置,讓分片生效。

連接mongos

[root@VM-241 ~]# mongo 127.0.0.1:20000
MongoDB shell version: 2.6.9
connecting to: 127.0.0.1:20000/test

使用admin數據庫

mongos> use admin
switched to db admin

串聯路由服務器與分配副本集1

mongos> db.runCommand({addshard:"shard1/10.19.21.241:22001,10.19.21.242:22001,10.19.21.243:22001"});
{ "shardAdded" : "shard1", "ok" : 1 }

串聯路由服務器與分配副本集2

mongos> db.runCommand({addshard:"shard2/10.19.21.241:22002,10.19.21.242:22002,10.19.21.243:22002"});
{ "shardAdded" : "shard2", "ok" : 1 }

串聯路由服務器與分配副本集3

mongos> db.runCommand({addshard:"shard3/10.19.21.241:22003,10.19.21.242:22003,10.19.21.243:22003"});
{ "shardAdded" : "shard3", "ok" : 1 }


查看分片服務器配置

mongos> db.runCommand({listshards:1})
{
"shards" : [
{
"_id" : "shard1",
"host" : "shard1/10.19.21.241:22001,10.19.21.242:22001"
},
{
"_id" : "shard2",
"host" : "shard2/10.19.21.241:22002,10.19.21.242:22002"
},
{
"_id" : "shard3",
"host" : "shard3/10.19.21.241:22003,10.19.21.242:22003"
}
],
"ok" : 1
}

由於10.19.21.243是每個分片副本集的仲裁節點,所以上面沒有列出


8,目前配置服務、路由服務、分片服務、副本集服務都已經串聯起來了,但我們的目的是希望插入數據,數據能夠自動分片,連接在mongos上,準備讓指定的數據庫、指定的集合分片生效

指定數據庫testdb使分片生效

mongos> db.runCommand({enablesharding:"testdb"});
{ "ok" : 1 }

指定數據庫裏需要分片的集合和片鍵

mongos> db.runCommand({shardcollection:"testdb.table1",key:{id:1}})
{ "collectionsharded" : "testdb.table1", "ok" : 1 }

我們設置testdb的 table1 表需要分片,根據 id 自動分片到 shard1 ,shard2,shard3 上面去。要這樣設置是因爲不是所有mongodb 的數據庫和表 都需要分片!

mongos> use testdb
switched to db testdb

插入測試數據

 for (var i=1;i<=100000;i++)db.table1.save({id:i,"test1":"testvar1"});
WriteResult({ "nInserted" : 1 })

查看分片情況如下:

mongos> db.table1.stats();
{
"sharded" : true,
"systemFlags" : 1,
"userFlags" : 1,
"ns" : "testdb.table1",
"count" : 100000,
"numExtents" : 12,
"size" : 11200000,
"storageSize" : 23212032,
"totalIndexSize" : 6091120,
"indexSizes" : {
"_id_" : 3278576,
"id_1" : 2812544
},
"avgObjSize" : 112,
"nindexes" : 2,
"nchunks" : 3,
"shards" : {
"shard1" : {
"ns" : "testdb.table1",
"count" : 5097,
"size" : 570864,
"avgObjSize" : 112,
"storageSize" : 696320,
"numExtents" : 4,
"nindexes" : 2,
"lastExtentSize" : 524288,
"paddingFactor" : 1,
"systemFlags" : 1,
"userFlags" : 1,
"totalIndexSize" : 335216,
"indexSizes" : {
"_id_" : 179872,
"id_1" : 155344
},
"ok" : 1
},
"shard2" : {
"ns" : "testdb.table1",
"count" : 0,
"size" : 0,
"storageSize" : 8192,
"numExtents" : 1,
"nindexes" : 2,
"lastExtentSize" : 8192,
"paddingFactor" : 1,
"systemFlags" : 0,
"userFlags" : 1,
"totalIndexSize" : 16352,
"indexSizes" : {
"_id_" : 8176,
"id_1" : 8176
},
"ok" : 1
},
"shard3" : {
"ns" : "testdb.table1",
"count" : 94903,
"size" : 10629136,
"avgObjSize" : 112,
"storageSize" : 22507520,
"numExtents" : 7,
"nindexes" : 2,
"lastExtentSize" : 11325440,
"paddingFactor" : 1,
"systemFlags" : 0,
"userFlags" : 1,
"totalIndexSize" : 5739552,
"indexSizes" : {
"_id_" : 3090528,
"id_1" : 2649024
},
"ok" : 1
}
},
"ok" : 1
}

可以看到數據分到3個分片,shard1:5097 shard2:0 shard3:94903

從結果看出,效果不是很理想,因爲shard2裏沒有分配到。還要調試。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章