mongodb分片機制原理
一、概念:
分片(sharding)是指將數據庫拆分,將其分散在不同的機器上的過程。將數據分散到不同的機器上,不需要功能強大的服務器就可以存儲更多的數據和處理更大的負載。基本思想就是將集合切成小塊,這些塊分散到若干片里,每個片只負責總數據的一部分,最后通過一個均衡器來對各個分片進行均衡(數據遷移)。通過一個名為mongos的路由進程進行操作,mongos知道數據和片的對應關系(通過配置服務器)。大部分使用場景都是解決磁盤空間的問題,對於寫入有可能會變差,查詢則盡量避免跨分片查詢。使用分片的時機:
1,機器的磁盤不夠用了。使用分片解決磁盤空間的問題。
2,單個mongod已經不能滿足寫數據的性能要求。通過分片讓寫壓力分散到各個分片上面,使用分片服務器自身的資源。
3,想把大量數據放到內存里提高性能。和上面一樣,通過分片使用分片服務器自身的資源。
二、分片集群架構(來自官網)
上圖中主要有如下所述三個主要組件:
Shard:分片服務器
用於存儲實際的數據塊,實際生產環境中一個shard server角色可由幾台機器組個一個replica set承擔,防止主機單點故障
Config Server:配置服務器
mongod實例,存儲了整個 分片群集的配置信息,其中包括 chunk信息。
Query Routers:前端路由
客戶端由此接入,且讓整個集群看上去像單一數據庫,前端應用可以透明使用
這里的兩個shard(分片)相當於mongodb節點服務器,內部的塊是將order集合再切割的結果,隨着數據量的的增大,分片會分割和遷移,以滿足數據的均勻分布。
請求分流:通過路由節點將請求分發到對應的分片和塊中
數據分流:內部提供平衡器保證數據的均勻分布,這是數據平均分布式、請求平均分布的前提
塊的拆分:3.4版本塊的最大容量為64M或者10w的數據,當到達這個閾值,觸發塊的拆分,一分為二
塊的遷移:為保證數據在分片節點服務器分片節點服務器均勻分布,塊會在節點之間遷移。一般相差8個分塊的時候觸發
MongoDB分片優勢:
減少單個分片需要處理的請求數,提高群集的存儲容量和吞吐量 比如,當插入一條數據時,應用只需要訪問存儲這條數據的分片 減少單分片存儲的數據,提高數據可用性,提高大型數據庫查詢服務的性能。 當MongoDB單點數據庫服務器存儲和性能成為瓶頸,或者需要部署大型應用以充分利用內存時,可以使用分片技術
環境准備
docker、docker-compose、lunux。版本問題應該不大,我用的是Docker version 18.09.0, build 4d60db4、docker-compose version 1.23.0-rc3, buildea3d406e、centos7.2。
本套Mongodb搭建分片集群是基於mongodb4.0.5,直接從官方鏡像倉庫拉取docker pull mongo:4.0.5即可
完成准備之后,docker images看一下,mongodb.鏡像是否搞定了。
1.編寫yaml文件,這里我命名fates-mongo-compose.yaml
version: '2'
services:
shard1:
image: mongo:4.0.5
container_name: mongo_shard1
# --shardsvr: 這個參數僅僅只是將默認的27017端口改為27018,如果指定--port參數,可用不需要這個參數
# --directoryperdb:每個數據庫使用單獨的文件夾
command: mongod --shardsvr --directoryperdb --replSet shard1
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/shard1:/data/db
privileged: true
mem_limit: 16000000000
networks:
- mongo
shard2:
image: mongo:4.0.5
container_name: mongo_shard2
command: mongod --shardsvr --directoryperdb --replSet shard2
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/shard2:/data/db
privileged: true
mem_limit: 16000000000
networks:
- mongo
shard3:
image: mongo:4.0.5
container_name: mongo_shard3
command: mongod --shardsvr --directoryperdb --replSet shard3
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/shard3:/data/db
privileged: true
mem_limit: 16000000000
networks:
- mongo
config1:
image: mongo:4.0.5
container_name: mongo_config1
# --configsvr: 這個參數僅僅是將默認端口由27017改為27019, 如果指定--port可不添加該參數
command: mongod --configsvr --directoryperdb --replSet fates-mongo-config --smallfiles
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/config1:/data/configdb
networks:
- mongo
config2:
image: mongo:4.0.5
container_name: mongo_config2
command: mongod --configsvr --directoryperdb --replSet fates-mongo-config --smallfiles
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/config2:/data/configdb
networks:
- mongo
config3:
image: mongo:4.0.5
container_name: mongo_config3
command: mongod --configsvr --directoryperdb --replSet fates-mongo-config --smallfiles
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/config3:/data/configdb
networks:
- mongo
mongos:
image: mongo:4.0.5
container_name: mongo_mongos
# mongo3.6版默認綁定IP為127.0.0.1,此處綁定0.0.0.0是允許其他容器或主機可以訪問
command: mongos --configdb fates-mongo-config/config1:27019,config2:27019,config3:27019 --bind_ip 0.0.0.0 --port 27017
ports:
- 27017:27017
volumes:
- /etc/localtime:/etc/localtime
depends_on:
- config1
- config2
- config3
networks:
- mongo
networks:
mongo:
external: true
具體含義看注釋
2.編寫deploy-and-start.sh腳本
#!/bin/sh docker-compose -f fates-mongo-compose.yaml up -d #睡眠兩分鍾,等待mongodb所有容器起來之后將它們配置加入分片 sleep 30s docker-compose -f fates-mongo-compose.yaml exec config1 bash -c "echo 'rs.initiate({_id: \"fates-mongo-config\",configsvr: true, members: [{ _id : 0, host : \"config1:27019\" },{ _id : 1, host : \"config2:27019\" }, { _id : 2, host : \"config3:27019\" }]})' | mongo --port 27019" docker-compose -f fates-mongo-compose.yaml exec shard1 bash -c "echo 'rs.initiate({_id: \"shard1\",members: [{ _id : 0, host : \"shard1:27018\" }]})' | mongo --port 27018" docker-compose -f fates-mongo-compose.yaml exec shard2 bash -c "echo 'rs.initiate({_id: \"shard2\",members: [{ _id : 0, host : \"shard2:27018\" }]})' | mongo --port 27018" docker-compose -f fates-mongo-compose.yaml exec shard3 bash -c "echo 'rs.initiate({_id: \"shard3\",members: [{ _id : 0, host : \"shard3:27018\" }]})' | mongo --port 27018" docker-compose -f fates-mongo-compose.yaml exec mongos bash -c "echo 'sh.addShard(\"shard1/shard1:27018\")' | mongo" docker-compose -f fates-mongo-compose.yaml exec mongos bash -c "echo 'sh.addShard(\"shard2/shard2:27018\")' | mongo" docker-compose -f fates-mongo-compose.yaml exec mongos bash -c "echo 'sh.addShard(\"shard3/shard3:27018\")' | mongo"
該腳本流程詳細描述一下
1)先啟動mongodb分片容器組
2) 睡眠30s等待容器全部完全啟動(可能不需要30s)
3)操作config1,配置config副本集,將config*容器組作為config角色,此時config1作為config副本集里的主節點
4)操作shard1、shard2、shard3,將shard*容器組作為shard角色。
5)將shard1、shard2、shard3加入分片集群組。
3.運行
執行腳本
# sh deploy-and-start.sh 等待腳本啟動完成,如果出現connect fail報錯,檢查一下網絡,再次啟動一次腳本即可。
到這里,單機版的mongodb的分片集群,就搭建好了,一般真正的運維環境,Mongodb集群應該分布在不同的機器,但是只要熟悉這套部署方案的機制,只要稍作修改,就可以實現。
但是,Mongodb庫默認是不會將你的表進行分片的,是需要手動配置的,如果不配置,數據都會全部存放在主節點,不會均勻分配到各個分片。
現在手動將一個表做分片,就拿um_t_staff表作為例子
//前提是分片的片鍵必須是索引
sh.enableSharding("'mongodbDemo")//先讓當前庫支持分片
sh.shardCollection('mongodbDemo.um_t_staff',{timestamp:1})//當前集合加入分片,遞增片鍵(timestamp已經作為索引了)
db.adminCommand("flushRouterConfig")//刷新路由
sh.enableBalancing("mongodbDemo.um_t_staff")//讓當前分片支持平衡
sh.startBalancer() //開啟平衡
sh.status({"verbose":1})//查看詳細分片信息
db.um_t_staff.getShardDistribution()//查看該表分片數據信息
OK 。docker-compose搭建分片集群已經大功告成了。
感謝前輩的技術輸出。參考博文: https://juejin.im/post/5c3c3105f265da611b58909a#heading-14