mongodb分片概念和原理-實戰分片集羣

一、分片

分片是一種跨多臺機器分發數據的方法。MongoDB使用分片來支持具有非常大的數據集和高吞吐量操作的部署。

問題:

具有大型數據集或高吞吐量應用程序的數據庫系統可能會挑戰單個服務器的容量。例如,高查詢率會耗盡服務器的CPU容量。工作集大小大於系統的RAM會強調磁盤驅動器的I / O容量。

解決系統增長的方法有兩種:垂直和水平縮放。

垂直擴展涉及增加單個服務器的容量,例如使用更強大的CPU,添加更多RAM或增加存儲空間量。可用技術的侷限性可能會限制單個機器對於給定工作負載而言足夠強大。此外,基於雲的提供商基於可用的硬件配置具有硬性上限。結果,垂直縮放有實際的最大值。

水平擴展涉及劃分系統數據集並加載多個服務器,添加其他服務器以根據需要增加容量。雖然單個機器的總體速度或容量可能不高,但每臺機器處理整個工作負載的子集,可能提供比單個高速大容量服務器更高的效率。擴展部署容量只需要根據需要添加額外的服務器,這可能比單個機器的高端硬件的總體成本更低。權衡是基礎架構和部署維護的複雜性增加。

MongoDB支持通過分片進行水平擴展

二、分片集羣概述

MongoDB分片羣集包含以下組件:

分片:是一個獨立普通的mongod進程,保存數據信息。可以是一個副本集也可以是單獨的一臺服務器。

mongos:起到一個路由的功能,供程序連接。本身不保存數據,在啓動時從配置服務器加載集羣信息,開啓mongos進程需要知道配置服務器的地址,指定configdb選項。

配置服務器:是一個獨立的mongod進程,保存集羣和分片的元數據,即各分片包含了哪些數據的信息。最先開始建立,啓用日誌功能。像啓動普通的mongod一樣啓動配置服務器,指定configsvr選項。不需要太多的空間和資源,配置服務器的1KB空間相當於真是數據的200MB。保存的只是數據的分佈表。當服務不可用,則變成只讀,無法分塊、遷移數據。

交互圖如下:

1.png

MongoDB在集合級別對數據進行分片,將集合數據分佈在集羣中的分片上。

1、鎖片鍵

爲了在集合中分發文檔,MongoDB 使用分片鍵對集合進行分區。分片鍵 由目標集合中每個文檔中存在的不可變字段組成。

在分片集合時選擇分片鍵。分片後無法更改分片鍵的選擇。分片集合只能有一個分片 鍵。要對非空集合進行分片,集合必須具有 以分片鍵開頭的索引。對於空集合,如果集合尚未具有指定分片鍵的適當索引,MongoDB將創建索引。

分片鍵的選擇會影響分片羣集的性能,效率和可伸縮性。具有最佳硬件和基礎結構的羣集可能會因選擇分片鍵而受到瓶頸。選擇分片鍵及其支持索引也會影響羣集可以使用的分片策略。

2、大塊

MongoDB將分片數據劃分爲塊。每個塊都具有基於分片鍵的包含較低且獨佔的較高範圍 。

3、平衡器和偶數塊分配

爲了在羣集中的所有分片上實現塊的均勻分佈,平衡器在後臺運行以跨分片遷移塊。

4、Sharding的優點

(1)讀寫

MongoDB的分佈在整個的讀寫工作量 碎片將在分片集羣,使每個碎片來處理羣集操作的一個子集。通過添加更多分片,可以在羣集中水平擴展讀取和寫入工作負載。

對於包含分片鍵或複合分片鍵前綴mongos的查詢,可以在特定分片或分片集上定位查詢。這些目標操作通常比向羣集中的每個分片廣播更有效 。

(2)存儲容量

拆分分配整個數據碎片集羣中,允許每個碎片以包含總簇數據的子集。隨着數據集的增長,額外的分片會增加羣集的存儲容量。

(3)高可用性

分片簇可以繼續執行,即使一個或多個碎片是不可用的部分讀/寫操作。雖然在停機期間無法訪問不可用分片上的數據子集,但是針對可用分片的讀取或寫入仍然可以成功。

備註:

(1)從MongoDB 3.2開始,您可以將配置服務器部署爲副本集。只要大多數副本集可用,具有配置服務器副本集(CSRS)的分片羣集就可以繼續處理讀取和寫入。

(2)在3.4版本中,MongoDB 刪除了對SCCC配置服務器的支持。

(3)在生產環境中,應將各個分片部署爲 副本集,從而提供更高的冗餘和可用性。

5、分片集羣注意事項

(1)分片集羣基礎架構要求和複雜性需要仔細規劃,執行和維護。

(2)選擇分片密鑰時需要認真考慮,以確保集羣性能和效率。分片後不能更改分片鍵,也不能取消分片分片。

(3)Sharding具有一定的操作要求和限制

(4)如果查詢不包括分片鍵或複合分片鍵的前綴 ,則mongos執行廣播操作,查詢分 片羣集中的所有分片。這些分散/收集查詢可以是長時間運行的操作。

6、分片策略

MongoDB支持兩種分片策略,用於跨分片羣集分發數據。

(1)散列分片

散列分片涉及計算分片鍵字段值的散列。然後,基於散列的分片鍵值爲每個塊分配一個範圍。

(2)遠程分片

遠程分片涉及基於分片鍵值將數據劃分爲範圍。然後根據分片鍵值爲每個塊分配一個範圍

7、 MongoDB Sharding Cluster角色

(1) Shard Server

即存儲實際數據的分片每個Shard 可以是一個mongod 實例也可以是一組mongod 實例

構成的Replica Set。爲了實現每個Shard 內部的auto-failoverMongoDB 官方建議每個Shard

爲一組Replica Set。

(2)Config Server

爲了將一個特定的collection 存儲在多個shard 中需要爲該collection 指定一個shard key

例如{age: 1} shard key 可以決定該條記錄屬於哪個chunk。Config Servers 就是用來存儲

所有shard 節點的配置信息、每個chunk 的shard key 範圍、chunk 在各shard 的分佈情況、

該集羣中所有DB 和collection 的sharding 配置信息。

(3)Route Process

這是一個前端路由客戶端由此接入然後詢問Config Servers 需要到哪個Shard 上查詢或

保存記錄再連接相應的Shard 進行操作最後將結果返回給客戶端。客戶端只需要將原本

發給mongod 的查詢或更新請求原封不動地發給Routing Process而不必關心所操作的記錄

存儲在哪個Shard 上。

三、分配集羣搭建

1、環境準備

(1)、數據庫環境

主機名

數據庫IP地址

數據庫版本

用途

系統

SQL_mongdb

172.169.18.128

mongodb4.0.3

配置3,路由1,分片2

cenots7.4

node01

172.169.18.162

mongodb4.0.3

路由1,分片2

centos7.4

node01

172.169.18.180

mongodb4.0.3

分片2

centos7.4

(2)暫時關閉防火牆和seliunx,測試完畢再開啓安全規則

(3)yum安裝mongdb4.0版本(省略)

同樣的,在node01和node02上安裝服務

在部署之前先明白片鍵的意義,一個好的片鍵對分片至關重要。片鍵必須是一個索引,數據根據這個片鍵進行拆分分散。通過sh.shardCollection加會自動創建索引。一個自增的片鍵對寫入和數據均勻分佈就不是很好,因爲自增的片鍵總會在一個分片上寫入,後續達到某個閥值可能會寫到別的分片。但是按照片鍵查詢會非常高效。隨機片鍵對數據的均勻分佈效果很好。注意儘量避免在多個分片上進行查詢。在所有分片上查詢,mongos會對結果進行歸併排序。

(4)

框架圖

2.png

2、配置服務器的啓動。(SQL_mongdb上開啓3個,Port:21000、22000、2300)

備註:配置服務器必須開啓1個或則3個,開啓2個則會報錯:

(1)創建目錄

[root@SQL_mongdb /]# mkdir -p /opt/mongodb/date1

[root@SQL_mongdb /]# mkdir -p /opt/mongodb/date2

[root@SQL_mongdb /]# mkdir -p /opt/mongodb/date3

(2)新建配置文件

[root@SQL_mongdb ~]# cat /etc/mongodb_21000.conf

#數據目錄

dbpath=/opt/mongodb/date1/

#日誌文件

logpath=/opt/mongodb/mongodb_21000.log

#日誌追加

logappend=true

#端口

port = 21000

#最大連接數

maxConns = 50

pidfilepath = /opt/mongodb/mongo_21000.pid

#日誌,redo log

journal = true

#刷寫提交機制

journalCommitInterval = 200

#守護進程模式

fork = true

#刷寫數據到日誌的頻率

syncdelay = 60

#storageEngine = wiredTiger

#操作日誌,單位M

oplogSize = 1000

#命名空間的文件大小,默認16M,最大2G。

nssize = 16

noauth = true

unixSocketPrefix = /tmp

configsvr = true

replSet=jiangjj

bind_ip = 172.169.18.128

[root@SQL_mongdb ~]# cat /etc/mongodb_22000.conf

#數據目錄

dbpath= /opt/mongodb/date2/

#日誌文件

logpath= /opt/mongodb/mongodb_22000.log

#日誌追加

logappend=true

#端口

port = 22000

#最大連接數

maxConns = 50

pidfilepath = /opt/mongodb/mongo_22000.pid

#日誌,redo log

journal = true

#刷寫提交機制

journalCommitInterval = 200

#守護進程模式

fork = true

#刷寫數據到日誌的頻率

syncdelay = 60

#storageEngine = wiredTiger

#操作日誌,單位M

oplogSize = 1000

#命名空間的文件大小,默認16M,最大2G。

nssize = 16

noauth = true

unixSocketPrefix = /tmp

configsvr = true

replSet=jiangjj

bind_ip = 172.169.18.128

[root@SQL_mongdb ~]# cat /etc/mongodb_23000.conf

#數據目錄

dbpath= /opt/mongodb/date3/

#日誌文件

logpath= /opt/mongodb/mongodb_23000.log

#日誌追加

logappend=true

#端口

port = 23000

#最大連接數

maxConns = 50

pidfilepath = /opt/mongodb/mongo_23000.pid

#日誌,redo log

journal = true

#刷寫提交機制

journalCommitInterval = 200

#守護進程模式

fork = true

#刷寫數據到日誌的頻率

syncdelay = 60

#storageEngine = wiredTiger

#操作日誌,單位M

oplogSize = 1000

#命名空間的文件大小,默認16M,最大2G。

nssize = 16

noauth = true

unixSocketPrefix = /tmp

configsvr = true

replSet=jiangjj

bind_ip = 172.169.18.128

(3)啓動配置文件(實例進程)

[root@SQL_mongdb ~]# mongod -f /etc/mongodb_21000.conf

[root@SQL_mongdb ~]# mongod -f /etc/mongodb_22000.conf

[root@SQL_mongdb ~]# mongod -f /etc/mongodb_23000.conf

3.png

備註:

關閉進程服務

# mongod -f /etc/mongodb_21000.conf --shutdown

如果非正常訪問,重新啓動會報錯,必須要刪除mongd.lock後才能啓動成功。

(4)將節點配置組成集羣(副本集)

在任意節點啓動配置,這裏使用SQL_jiangjj節點

登錄數據庫

[root@SQL_mongdb ~]# mongo --host 172.169.18.128:21000

> use admin

> cfg={ _id:"jiangjj",members:[{_id:0,host:'172.169.18.128:21000',priority:3},{_id:1,host:'172.169.18.128:22000',priority:2},{_id:2,host:'172.169.18.128:23000',priority:1}] };

#配置生效命令

> rs.initiate(cfg)

3、路由配置(在SQL_mongodb和node01上各開啓1個,port:3000)

路由服務器不保存數據,把日誌記錄一下即可

(1)在SQL_mongodb上新增配置文件

[root@SQL_mongdb ~]# vim /etc/mongodb_30000.conf

#日誌文件

logpath = /opt/mongodb/mongodb_route.log

#日誌追加

logappend = true

#端口

port = 30000

#最大連接數

maxConns = 20000

#chunkSize=1

#綁定地址

bind_ip = 0.0.0.0

pidfilepath = /opt/mongodb/mongo_30000.pid

#必須是1個或則3個配置

configdb = jiangjj/172.169.18.128:21000,172.169.18.128:22000,172.169.18.128:23000

#configdb=127.0.0.1:20000  #報錯

#守護進程模式

fork = true

(2)開啓mongos

[root@SQL_mongdb ~]# mongos -f /etc/mongodb_30000.conf

4.png

(3)配置一個普通分片文件

5.png

查看狀態

6.png

按照上面的方法再到node01上開啓分片服務和路由服務(配置文件一樣),以及在node02上開啓分片服務。到此分片的配置服務器、路由服務器、分片服務器都已經部署完成。

備註:分片其中一個配置,其他的類似

[root@node01 etc]# vim mongodb_60000.conf

#mongodb

dbpath=/opt/mongodb/date2/

logpath=/opt/mongodb_60000.log

pidfilepath=/opt/mongodb/mongodb_60000.pid

directoryperdb=true

logappend=true

bind_ip=172.169.18.162

port=60000

oplogSize=100

fork=true

noprealloc=true

4、配置分片:下面的操作都是在mongodb的命令行裏執行

(1)登陸路由服務器mongos 操作:

[root@SQL_mongdb ~]# mongo --port=30000

mongos> use admin

mongos> db.runCommand({addshard:'172.169.18.128:60000'})

mongos> db.runCommand({addshard:'172.169.18.162:60000'})

mongos> db.runCommand({addshard:'172.169.18.180:60000'})

7.png

#查看

mongos> sh.status()

8.png

(2)開啓分片功能:sh.enableSharding("庫名")、sh.shardCollection("庫名.集合名",{"key":1})

mongos> sh.enableSharding('jiangjj')

mongos> sh.status()

9.png

mongos> sh.shardCollection("jiangjj.text",{"name":1})

報錯如下:

Cannot accept sharding commands if not started with --shardsvr

10.png

在分片配置文件中加入如下參數:

shardsvr = true

重啓進程後執行上面的命令

11.png

查看:mongos> sh.status()

12.png

查看詳細信息:

mongos> sh.status({"verbose":1})

或則

mongos> db.printShardingStatus("vvvv")

或則

mongos> printShardingStatus(db.getSisterDB("config"),1)

#判斷是否是Sharding

13.png

5、測試查看

1、在路由Mongos端添加數據庫和數據,如此

14.png

2、添加的數據庫分配到不聽的分片節點上

15.png

備註:這裏我們做的都是單點的,要是一個分片壞了,則數據會丟失,我們可以利用副本集減少災難

四、高可用:Sharding+Replset

1、在三個節點各自添加一個分片,port:50000,name:user01

其中一個集羣分片,根據實際情況修改調整

#mongodb

dbpath=/opt/mongodb/date1/

logpath=/opt/mongodb_50000.log

pidfilepath=/opt/mongodb/mongodb_50000.pid

#keyFile=/opt/mongodb/mongodb.key  //節點間用戶驗證文件,內容必須一致,權限600,僅副本集模式有效

directoryperdb=true

logappend=true

replSet=user01

bind_ip=172.169.18.162

port=50000

#auth=true

oplogSize=100

fork=true

noprealloc=true

#maxConns=4000

shardsvr = true

2、將分片設置成副本集

登錄數據庫

[root@SQL ~]# mongo --host 172.169.18.128:50000

> use admin

> user01db={ _id:"user01",members:[{_id:0,host:'172.169.18.128:50000',priority:3},{_id:1,host:'172.169.18.162:50000',priority:2},{_id:2,host:'172.169.18.180:50000',priority:1}] };

#配置生效命令

> rs.initiate(user01db)

21.png

3、配置路由節點

[root@SQL_mongdb ~]# mongo --port=30000

切換到admin庫

mongos> use admin

#添加分片節點

mongos> sh.addShard("user01/172.169.18.128:50000")

22.png

備註:

#也可以直接在路由節點添加副本集

mongos>sh.addShard("user01/172.169.18.128:50000,172.169.18.162:50000,172.169.18.180:50000")

#查看集羣信息

mongos> sh.status()

23.png

補充說明:均衡器

24.png

均衡器:均衡器負責數據遷移,週期性的檢查分片是否存在不均衡,如果不存在則會開始塊的遷移,config.locks集合裏的state表示均衡器是否找正在運行,0表示非活動狀態,2表示正在均衡。均衡遷移數據的過程會增加系統的負載:目標分片必須查詢源分片的所有文檔,將文檔插入目標分片中,再清除源分片的數據。可以關閉均衡器(不建議):關閉會導致各分片數據分佈不均衡,磁盤空間得不到有效的利用。 

查看狀態:mongos> sh.getBalancerState()

關閉命令:mongos> sh.stopBalancer()

開啓命令:mongos> sh.setBalancerState(true)

4、在Mongos添加兩個數據庫user01和user02,添加數據測試副本集

分配在不同的分片節點上,查看的數據不同26.png

5、分片數據庫遷移,刪除分片

刪除分片時,必須確保該分片上的數據被移動到其他分片中,對於以分片的集合,使用均衡器來遷移數據塊,對於非分片的集合,必須修改集合的主分片。

1)將shard0001分片上的數據庫jiangjj04遷移到user01集合分片上

mongos> use admin

mongos> db.runCommand({moveprimary:"jiangjj04",to:"user01"})

27.png

如下:

28.png

2、刪除分片:

#需要到admin下面刪除(需要執行兩次)

mongos> db.runCommand({"removeshard":"jiangjj01"})

注意:MongoDB的分片不能刪除最後一個,否則報如下錯誤

31.png

3、刪除分片上的數據庫

mongos> use jsqdb

mongos> db.dropDatabase()

32.png

三、集羣用戶驗證設置


1、創建驗證祕鑰文件

keyFile文件的作用: 集羣之間的安全認證,增加安全認證機制KeyFile(開啓keyfile認證就默認開啓了auth認證了,爲了保證後面可以登錄,我已創建了用戶)

# cd /opt/mongodb/

#  touch .keyFile

#  chmod 600 .keyFile

# openssl rand -base64 102 > .keyFile

102:是文件大小

注意:創建keyFile前,需要先停掉副本集中所有主從節點的mongod服務,然後再創建,否則有可能出現服務啓動不了的情況。

2、在Mongos節點添加root賬號

mongos> use admin

mongos> db.createUser({

... user:'root',

... pwd:'123456',

... roles:[{role:'root',db:'admin'}]

... })

33.png

3、更新所有配置分片節點配置文件,在路由配置文件只配置keyFile參數即可

keyFile=/home/data/.keyFile

auth=true

4、啓動副本集,測試

登錄驗證

root用戶

34.png

現在只有兩個路由節點端口30000有權訪問數據庫,其他節點訪問如下圖報錯信息

35.png

在mongos節點給jiangjj01配置用戶

添加一個jiangjj用戶擁有讀寫權限

36.png

登錄Mongos節點驗證成功。

37.png

補充知識點:

權限伸縮

1)如何增加權限

db.grantRolesToUser(

<user_name>,

[{role:<role_name>,db:<db_name>}])

注意:此方法接受2個參數,而不是兩個對象, 而且如何權限重複不會覆蓋,新的會增加

例如:

db.grantRolesToUser('roleTest,[{role:'readWrite',db:'test'}])\

2)如何收縮權限

db.revokeRolesToUser(

<user_name>,

[{role:<role_name>,db:<db_name>}])

權限配置詳細請參考官方


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