MongoDB集群搭建
MongoDB的复制集群类型:
·主从模式(master/slave)
·副本集模式(replica set)
副本及模式至少3个节点(一主二从),从节点负责复制主节点的oplog到本地并且应用到本地从而实现冗余。
(·arbiter:仅参与选举,但不持有任何数据
·0优先级:可以触发选举,但是不能被选举成为主节点
·可以使用repiset来定义集群名称)
1.编译安装MongDB
准备环境:
系统:Debian 7.2 64位
mongodb:mongodb-linux-x86_64-2.4.5.tgz(官网有下)
- root@namenode1:/usr/local/tools# tar xfmongodb-linux-x86_64-2.4.5.tgz
- root@namenode1:/usr/local/tools# mv mongodb-linux-x86_64-2.4.5 /usr/local/
- root@namenode1:/usr/local/tools# cd /usr/local/
- root@namenode1:/usr/local# ln -s /usr/local/mongodb-linux-x86_64-2.4.5//usr/local/mongodb
- root@namenode1:/usr/local# ll | grep mongo
- lrwxrwxrwx 1 root staff 38 3月 17 15:35 mongodb ->/usr/local/mongodb-linux-x86_64-2.4.5/
- drwxr-sr-x 3 root staff 4096 3月 17 15:08 mongodb-linux-x86_64-2.4.5
#创建用户
- root@namenode1:~# groupadd -r mongod
- root@namenode1:~# useradd -M -r -g mongod -d /data/db -s /bin/false -c mongodmongod
#建立目录
- root@namenode1:~# mkdir -p /var/log/mongo/
- root@namenode1:~# mkdir -p /mongo/data
- root@namenode1:~# chown mongod /mongo/data /var/log/mongo/
- root@namenode1:~# ll /var/log/ | grep mongo
- drwxr-xr-x 2mongod root 4096 Mar 17 15:25mongo
- root@namenode1:~# ll /mongo/
- total 4
- drwxr-xr-x 2 mongod root 4096 Mar 17 15:27 data
#将LC_ALL="C"加入环境变量,以防启动出错
- root@namenode1:~# echo ‘export LC_ALL="C"’ >> /etc/profile
#创建配置文件(将之前rpm包安装mongodb后的配置文件拷贝过来即可)
- root@namenode1:~# cat /etc/mongod.conf
- # mongo.conf
- #where to log
- logpath=/var/log/mongo/mongod.log
- logappend=true
- # fork and run in background
- fork = true
- #port = 27017
- dbpath=/mongo/data
- # location of pidfile
- pidfilepath = /var/run/mongodb/mongod.pid
- # Disables write-ahead journaling
- # nojournal = true
- # Enables periodic logging of CPU utilization and I/O wait
- #cpu = true
- # Turn on/off security. Off is currently the default
- #noauth = true
- #auth = true
- # Verbose logging output.
- #verbose = true
- # Inspect all client data for validity on receipt (useful for
- # developing drivers)
- #objcheck = true
- # Enable db quota management
- #quota = true
- # Set oplogging level where n is
- # 0=off (default)
- # 1=W
- # 2=R
- # 3=both
- # 7=W+some reads
- #diaglog = 0
- # Ignore query hints
- #nohints = true
- # Disable the HTTP interface (Defaults to localhost:27018).
- #nohttpinterface = true
- # Turns off server-side scripting. This will result in greatly limited
- # functionality
- #noscripting = true
- # Turns off table scans. Any query that would do a table scan fails.
- #notablescan = true
- # Disable data file preallocation.
- #noprealloc = true
- # Specify .ns file size for new databases.
- # nssize = <size>
- # Accout token for Mongo monitoring server.
- #mms-token = <token>
- # Server name for Mongo monitoring server.
- #mms-name = <server-name>
- # Ping interval for Mongo monitoring server.
- #mms-interval = <seconds>
- # Replication Options
- # in replicated mongo databases, specify here whether this is a slave or master
- #slave = true
- #source = master.example.com
- # Slave only: specify a single database to replicate
- #only = master.example.com
- # or
- #master = true
- #source = slave.example.com
启动mongodb
- export LC_ALL="C"
- root@namenode2:/usr/local/mongodb/bin# mongod -f /etc/mongod.conf
2.安装Rockmongo
RockMongo 是一个PHP5写的MongoDB管理工具。主要特征:使用宽松的New BSD License协议,速度快,安装简单,与mysql的phpmyadmin相似
- root@namenode1:~# apt-get install apache2 php5 php5-dev php5-cli
- root@namenode1:/etc/apache2# cd /var/www/
- root@namenode1:/var/www# wgethttp://rock-php.googlecode.com/files/rockmongo-v1.0.11.zip
- root@namenode1:/var/www# unzip rockmongo-v1.0.11.zip
#二次编译php模块
- root@namenode1:/var/www/mongo-php-driver-master# phpize
- root@namenode1:/var/www/mongo-php-driver-master# ./configure
- root@namenode1:/var/www/mongo-php-driver-master# make && makeinstall
#找到php模块所在路径
- root@namenode1:/var/www/mongo-php-driver-master# php -i | grepextension_dir
- extension_dir => /usr/lib/php5/20100525 => /usr/lib/php5/20100525
- root@namenode1:/var/www/mongo-php-driver-master# ll /usr/lib/php5/20100525
- total 2084
- -rwxr-xr-x 1 root root 2016810 Mar 17 16:35 mongo.so
- -rw-r--r-- 1 root root 113072 Dec 12 16:53 pdo.so
#php在debian系统所安装的路径在以下的位置,如果是其他系统需根据相对路径进行查找
- root@namenode1:/var/www/mongo-php-driver-master# ll/etc/php5/apache2/php.ini
- -rw-r--r-- 1 root root 65755 Dec 12 16:53 /etc/php5/apache2/php.ini
- root@namenode1:/var/www/mongo-php-driver-master# vi/etc/php5/apache2/php.ini
在733行加入内容,并保存退出
- 733 extension = mongo.so
重启apache并查看url是否生效
- root@namenode1:/etc/init.d/apache restart
访问以下地址
- http://172.23.214.50/rockmongo/index.php?action=index.login
可以看到如下图所示,已经可以正常显示mongodb的管理登陆界面,默认情况下用户名与密码默认都为admin
确认用户名和密码,登陆成功,如下所示
部署MongoDB主从复制:
1.规划如下:
服务器IP |
服务器角色 |
172.23.214.47 |
Master |
172.23.214.50 |
Slave |
2.配置主从
编辑Master配置文件:
- root@namenode2:/var/log/mongo# grep -v "#" /etc/mongod.conf |grep -v "^$"
- logpath=/var/log/mongo/mongod.log
- logappend=true
- fork = true
- port = 27017
- dbpath=/mongo/data
- pidfilepath = /var/run/mongodb/mongod.pid
- rest = true
- maxConns=1024
- master=true #将指定其为master
- oplogSize=2048
编辑Slave配置文件
- root@namenode1:/etc# cat mongod.conf.bak_slave | grep -v "#" | grep -v"^$"
- logpath=/var/log/mongo/mongod.log
- logappend=true
- fork = true
- port = 27017
- dbpath=/mongo/data
- maxConns = 1024
- slave = true #指定其为slave
- source = 172.23.214.47:27017 #指定master的主机地址及端口号
- autoresync = true
- pidfilepath = /var/run/mongodb/mongod.pid
编辑好配置文件,双方启动mongodb
- root@namenode1: mongod --f /etc/mongod.conf
主库查看日志信息:
- root@namenode2:/var/log/mongo# cat mongod.log
- Tue Mar 18 13:24:32.115 [initandlisten] connection accepted from172.23.214.50:57356 #2 (1 connection now open)
从库查看日志信息
- root@namenode1:/var/log/mongo# tail mongod.log | grep 47
- Tue Mar 18 13:24:30.025 [initandlisten] options: { autoresync:"true", config: "/etc/mongod.conf", dbpath:"/mongo/data", fork: "true", logappend: "true",logpath: "/var/log/mongo/mongod.log", maxConns: 1024, pidfilepath:"/var/run/mongodb/mongod.pid", port: 27017, slave: "true",source: "172.23.214.47:27017" }
- Tue Mar 18 13:24:31.188 [replslave] repl: syncingfrom host:172.23.214.47:27017
验证:主库创建库,并在从库查看
- > db.testcoll.find()
- > show collections
- > db.testcoll.insert ( {name:"tom"})
- > show collections
- system.indexes
- testcoll
- > db.testcoll.find()
- { "_id" : ObjectId("5327dabc9d62778b7a74ccab"),"name" : "tom" }
在从库上查看
- >show dbs;
- local 0.078125GB
- testdb 0.203125GB
- > use testdb;
- switched to db testdb
- > db.testcoll.find()
- { "_id" : ObjectId("5327dabc9d62778b7a74ccab"),"name" : "tom" }
查看从库日志
- root@namenode1:/var/log/mongo# tail mongod.log
- Tue Mar 18 13:33:48.042 [replslave] build index testdb.testcoll { _id: 1 }
- Tue Mar 18 13:33:48.042 [replslave] fastBuildIndexdupsToDrop:0
- Tue Mar 18 13:33:48.043 [replslave] build index done. scanned 1 totalrecords. 0 secs
- Tue Mar 18 13:33:48.062 [replslave] resync: done with initial clone for db:testdb
- Tue Mar 18 13:34:55.757 [initandlisten] connection accepted from127.0.0.1:32942 #1 (1 connection now open)
- Tue Mar 18 13:35:53.979 [replslave] repl: checkpoint applied 15operations
- Tue Mar 18 13:35:53.979 [replslave] repl: syncedTo: Mar 18 13:35:445327db30:1
- Tue Mar 18 13:38:06.018 [conn1] end connection 127.0.0.1:32942 (0 connectionsnow open)
- Tue Mar 18 13:38:23.981 [replslave] repl: checkpoint applied 15operations
- Tue Mar 18 13:38:23.982 [replslave] repl: syncedTo: Mar 18 13:38:145327dbc6:1
登录主库管理页面,查看其状态信息(master:1)
2.mongodb副本集部署
准备环境
服务器IP |
服务器角色 |
系统环境 |
172.23.214.47 |
master |
DeBian 7 |
172.23.214.50 |
Slave |
DeBian 7 |
172.23.215.61 |
Slave |
DeBian 7 |
首先屏蔽掉配置文件中的master/slave这等敏感信息,将配置文件还原为最初状态
最好配置hosts,如果不指hosts则写ip也可以
编辑配置文件:
3台主机配置文件都相同
- root@namenode1:~# grep -v "#" /etc/mongod.conf | grep -v"^$"
- logpath=/var/log/mongo/mongod.log
- logappend=true
- fork = true
- port = 27017
- dbpath=/mongo/data
- pidfilepath = /var/run/mongodb/mongod.pid
- replSet = true #副本集的名字
- rest = true
- maxConns=1024
- oplogSize=2048
先将master节点启动起来,登录想成为master的主机,启动mongod
- root@ namenode2:~# mongod -f /etc/mongod.conf
进入mongo
- root@namenode2:/mongo/data# mongo
初始化副本集:
- >rs.initiate()
构建对象
- {
- "_id" : "ture", #副本集的名字,要与配置文件对应
- "members" : [ #指定副本集成员
- {
- "_id" : 0, #指定副本集成员的id号
- "host" : 172.23.214.47:27017" #先将master添加进来而后再依次将其他成员添加进副本集
- }
- ]
- }
等待大约30秒钟
- > rs.initiate( rsconf )
- {
- "info" : "Config now savedlocally. Should come online in about a minute.", #提示需要等待大约1分钟,如果及时查看副本集内容很可能报错
- "ok" : 1
查看副本集
- > rs.conf()
添加slave
- true:PRIMARY> rs.add("172.23.214.47:27017")
- { "ok" : 1 }
- true:PRIMARY> rs.add("172.23.215.61:27017")
- { "ok" : 1 }
分别在slave上执行:
- true:RECOVERING> rs.slaveOk()
验证:
在master上创建库:
- true:PRIMARY> use testdb;
- switched to db testdb
- true:PRIMARY> for(i=1;i<=100;i++) db.testcoll.insert({Name:"User"+i,Age:i,Gender:"M",preferbook:["bluebook","yellow book"]})
在slave节点上查看数据库,可以看到已经被通过到本地
- true:RECOVERING> show dbs;
- local 2.0771484375GB
- testdb 0.203125GB
- rs.initiate()//先初始化,再通过rs.add等方法修改
- 这里的config_object会记录在local.system.replset这个集合内,这个集合会自动的在副本集成员之间广播,而且我们不能直接修改他们,需要使用命令来改变它,例如(replSetInitiate 命令)。
设定某节点的优先级
将一个普通数据节点修改为passive节点,也就是能同步数据、投票,但是不能成为primay
除了仲裁节点,其他每个节点都有个优先权,我们可以通过设置优先权来决定谁的成为primay的权重最大,MongoDB replica sets中通过设置priority的值来决定优先权的大小,这个值的范围是0--100,值越大,优先权越高。如果值是0,那么不能成为prima
如下所示:
(#这个环境是之前保留的镜像副本,以Host_Name进行添加的)
- true:PRIMARY> rs.conf()
- {
- "_id" : "true",
- "version" : 3,
- "members" : [
- {
- "_id" : 0,
- "host" : "namenode1:27017"
- },
- {
- "_id" : 1,
- "host" : "namenode2:27017"
- },
- {
- "_id" : 2,
- "host" : "datanode1:27017"
- }
- ]
- }
设置优先级别
#参考http://www.cnblogs.com/Amaranthus/p/3616951.html
- true:PRIMARY> cfg.members[0].priority=2
- true:PRIMARY> rs.conf()
- {
- "_id" : "true",
- "version" : 3,
- "members" : [
- {
- "_id" : 0,
- "host" : "namenode1:27017"
- "priority": 2
- },
- {
- "_id" : 1,
- "host" : "namenode2:27017"
- },
- {
- "_id" : 2,
- "host" : "datanode1:27017"
- }
- ]
- }
节点变更
如果需要对副本集进行扩容,例如加入一台mongodb服务器进入副本集,需要先启动这个节点(最好是将数据事先拷贝一份启动,不然一个新的空的数据库进来同步可能会复制过多的数据而导致应用崩溃)
比如我们想将节点datanode1:27017 移除从而新加入节点test:27017
那么首先将集群中的datanode1:27017节点移除
查看节点
- true:PRIMARY> rs.status()
- {
- "set" : "true",
- "date" : ISODate("2014-03-19T04:38:52Z"),
- "myState" : 1,
- "members" : [
- {
- "_id" : 0,
- "name" : "namenode1:27017",
- "health" : 1,
- "state" : 1,
- "stateStr" : "PRIMARY",
- "uptime" : 9510,
- "optime" : Timestamp(1395197587, 1),
- "optimeDate" : ISODate("2014-03-19T02:53:07Z"),
- "self" : true
- },
- {
- "_id" : 1,
- "name" : "namenode2:27017",
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 9183,
- "optime" : Timestamp(1395197587, 1),
- "optimeDate" : ISODate("2014-03-19T02:53:07Z"),
- "lastHeartbeat" : ISODate("2014-03-19T04:38:51Z"),
- "lastHeartbeatRecv" : ISODate("2014-03-19T04:38:51Z"),
- "pingMs" : 0,
- "syncingTo" : "namenode1:27017"
- },
- {
- "_id" : 2,
- "name" : "datanode1:27017", #将这个节点删除
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 6345,
- "optime" : Timestamp(1395197587, 1),
- "optimeDate" : ISODate("2014-03-19T02:53:07Z"),
- "lastHeartbeat" : ISODate("2014-03-19T04:38:50Z"),
- "lastHeartbeatRecv" : ISODate("2014-03-19T04:38:51Z"),
- "pingMs" : 0,
- "syncingTo" : "namenode1:27017"
- }
- ],
- "ok" : 1
- }
移除节点
- true:PRIMARY> rs.remove("datanode1:27017")
- Wed Mar 19 12:40:44.497 DBClientCursor::init call() failed
- Wed Mar 19 12:40:44.498 JavaScript execution failed: Error: error doing query:failed at src/mongo/shell/query.js:L78
- Wed Mar 19 12:40:44.498 trying reconnect to 127.0.0.1:27017
- Wed Mar 19 12:40:44.498 reconnect 127.0.0.1:27017 ok
再次查看副本集状态,发现datanode1已经没有了
- true:PRIMARY> rs.status()
- {
- "set" : "true",
- "date" : ISODate("2014-03-19T04:41:03Z"),
- "myState" : 1,
- "members" : [
- {
- "_id" : 0,
- "name" : "namenode1:27017",
- "health" : 1,
- "state" : 1,
- "stateStr" : "PRIMARY",
- "uptime" : 9641,
- "optime" : Timestamp(1395204044, 1),
- "optimeDate" : ISODate("2014-03-19T04:40:44Z"),
- "self" : true
- },
- {
- "_id" : 1,
- "name" : "namenode2:27017",
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 19,
- "optime" : Timestamp(1395204044, 1),
- "optimeDate" : ISODate("2014-03-19T04:40:44Z"),
- "lastHeartbeat" : ISODate("2014-03-19T04:41:02Z"),
- "lastHeartbeatRecv" : ISODate("2014-03-19T04:41:03Z"),
- "pingMs" : 0,
- "lastHeartbeatMessage" : "syncing to: namenode1:27017",
- "syncingTo" : "namenode1:27017"
- }
- ],
- "ok" : 1
- }
接着配置启动test节点并启动,配置文件是相同的,启动之后它会自动复制数据。如果数据量过大,还是建议事先通过其它机制同步数据
在master加入新节点
- true:PRIMARY> rs.add("test:27017")
- { "ok" : 1 }
查看状态
- true:PRIMARY> rs.status()
- {
- "set" : "true",
- "date" : ISODate("2014-03-19T04:43:08Z"),
- "myState" : 1,
- "members" : [
- {
- "_id" : 0,
- "name" : "namenode1:27017",
- "health" : 1,
- "state" : 1,
- "stateStr" : "PRIMARY",
- "uptime" : 9766,
- "optime" : Timestamp(1395204185, 1),
- "optimeDate" : ISODate("2014-03-19T04:43:05Z"),
- "self" : true
- },
- {
- "_id" : 1,
- "name" : "namenode2:27017",
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 144,
- "optime" : Timestamp(1395204185, 1),
- "optimeDate" : ISODate("2014-03-19T04:43:05Z"),
- "lastHeartbeat" : ISODate("2014-03-19T04:43:06Z"),
- "lastHeartbeatRecv" : ISODate("2014-03-19T04:43:07Z"),
- "pingMs" : 0,
- "syncingTo" : "namenode1:27017"
- },
- {
- "_id" : 2,
- "name" : "test:27017",
- "health" : 1,
- "state" : 6,
- "stateStr" : "UNKNOWN",
- "uptime" : 3,
- "optime" : Timestamp(0, 0),
- "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
- "lastHeartbeat" : ISODate("2014-03-19T04:43:07Z"),
- "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
- "pingMs" : 0,
- "lastHeartbeatMessage" : "still initializing"
- }
- ],
- "ok" : 1
- }
切换至test节点查看数据库
- root@test:/var/log/mongo# mongo
- MongoDB shell version: 2.4.5
- connecting to: test
- true:SECONDARY> show dbs;
- admin (empty)
- local 2.0771484375GB
- testdb 0.203125GB
- true:SECONDARY> rs.slaveOk()
部署Sharding集群
sharding通过将数据集分布于多个也称作分片(shard)的节点上来降低单节点的访问压力。每个分片都是一个独立的数据库,所有的分片组合起来构成一个逻辑上的完整意义的数据库。因此,分片机制降低了每个分片的数据操作量及需要存储的数据量
sharding的实现思路
选择一个合适索引而减少索引量,这种索引叫做重复索引
能够在索引中直接查找到所有要查询的索引,叫做覆盖索引,能够满足覆盖索引的条件并且排序次序又能够与索引的次序相同,这种次序是"3星"的
所以任何时候创建索引的目的一定要与搜索码完全匹配,至少保持一致
mongodb中可以使用db.mycoll.find().hint().explain()
来显示索引的查询过程mysql中可以使用 explain select XXX
副本集的集群在刚开始配置的时候有以下几个细节:
1、初始化:根据定义好的配置文件初始化,也可以让其系统本身进行简单初始化
2、简单初始化只是将同一个repiset节点的信息添加进来,但默认只初始化当前节点信息
如果想重新配置这个集群的话,可以实现将现有的配置信息读取出来而后在里面做设置之后并重新让后续的配置生效,而也可以在后续新增节点到集群中也可以将已经运行的节点从集群中移除出去,不管是新增和移除它们之间都会进行选举操作的
mongodb shard架构
1、config server : 元数据服务器,3台,1台为单点故障,而如果使用2台在选举时候,会无法得到分布式 (zookeeper)在实验环境中有一个即可
2、mongos:路由,默认端口27017 ,启动的时候必须制定其config server为其指路
3、shard:能够存储分片的服务,可以是独立的服务器,也可以是replica set(副本集,生成环境建议使用此类型),因此生成环境中,一般都需要部署这样的集群
sharding集群
sharding目的:
·当单个节点所持有的数据太大,单个节点无法存储下的时候需要做shard
·如果某个单节点所持有的数据集太大,一个节点无法存储下的时候,则需要做shard
·如果某个单节点承载的读写并发请求过大时
·可预见的时间内,单个节点索引、经常被访问数据量,难在内存容纳下的时候,意味着可能用到swap,如果使用swap那么性能显著下降,对于此种情况需要用到shard
sharding主要做法无非将一个数据分割为多块,平局分布在各个节点,为了保证读写的性能,那么读的操作则不做离散,而写操作需要做离散操作
所以,mongodb主要是根据sharding key来决定分片切割的:
sharding key就是collection的索引,而collection的索引(sharding key)的选择至关重要。通常是第一个shard,也就是主shard
在shard上使用索引
使用顺序索引:
使用顺序插入时,写操作会集中在有限的shard上这样写操作很难均匀分布
使用离散索引:
会被分散到各节点中去,很难提高读性能
如何使用sharding key
假设我们数据库中有个表,表内数据分别为name,Age,Gender, 那么假设将一个collection 按照name切割,而name上创建的索引而是顺序索引,那就意味着是按范围进行切割的,那切割完成之后,那我们经常按照name查询,一般问题不大,查询的请求只交给config server即可,config server可以帮我们完成路由,而name则是charding key。
config server中保存的是每个shard和它所持有的数据的key的范围
以Age为例
如果是范围分区的话,那么我们想查询年龄在0-30岁的时候,则在哪个shard上则会保存在config server上?如果找不到响应的内容,那么则要对其进行全shard扫描
如果是离散的话,那么30在哪个服务器 40在哪里 。。等 config server全都会有记录
对应的key条目和它所对应的shard映射信息就是元数据,就在config server上
那如果我们对name来创建的,那么非常明显config server上所创建的就是某个名字和shard的映关系
所以如果按照age来进行查找的话,则没有办法去查找,那么这时则全shard扫描
如果大多数查询都是根据age来查询,而我们非选择sharding key为name 那么麻烦就大了
所以选择sharding key至关重要
真正选择shard的话 需要根据业务模型来选择的,一定要明白选择标准是什么。
sharding选择思路:
如果选择一个sharding key之后 有可能导致写不均匀,但做shard主要目的是离散写入均匀,所以我们在选择key的时候尽可能
1、尽可能范围选择shard
2、一旦落在某个shard以后仍然会变得过大,我们可以再进行将各chunk分布出去,则可以使用自合索引,比如:
将name和age同时当做sharding key 来使用
{name:1,age: 1} #先根据name做分区,意味着作为name的范围匹配了之后落在同一个shard上会根据age再次分区,如果内容量过大的话,会再次分割开的而不会单独在这shard上操作
3、也可以使用三级索引
{name:1,age: 1,preferbooks} 有时我们存储了大量的数据进去,其会先对name进行分割发现落在某个shard的量过大,它会根据age再次分割,而后再次根据prefer books再次分割 这样可以使得写操作均匀分布,同样如果根据name范围查找的话,本来第一次分割是根据name分割的,很显然在一个范围内的用户通常会落在有限的shard上,所以读操作也做到了集中
在真正集群业务中并不是每个表都可以做shard的
比如有时候做shard可能带来很多问题
以博客为例:
我们以用户名做了shard 结果不同的用户可能被切割到不同shard中去,一个用户所发布的博文信息以及每个博文下的评论信息,每个用户发布的评论可能被存放在当前用户的shard上,当某个用户想查看自己博文下的所有评论信息的时候,那么评论的shard可能来自于多个用户,那么我对用户做了shard,也就意味着这些信息是根据用户所存储的 对应的用户所发布的评论也就有可能分布到多个shard上去 由此某个用户想查看自己博文下的所有评论,那么则会对其做全shard扫描,因此根据name来切割则是行不通的
以上的这种情况只能使用多个键
先根据文章和评论进行切割再根据用户名进行切割,意味着文章为标准,但同一个用户则放在有限的shard上去,这就是组合索引的好处
(尽可能保证前端的查询操作过于分散,这样就可以保证可以查询同一个或有限的shard)
如果文章与评论不是同一类的话:
那么既要考虑用户 又要考虑文章与评论 既然做分区了,如果用户本身信息量不是特别大的话,那么可以将一些有关联的表单独存放在一个库中
分片最主要的因素是选择sharding key
选择sharding key的标准:
1、应该在哪存数据
2、应该在哪得到希望的数据
读数据尽可能来自同一个点,写数据尽可能分散处理
夸分片做查询,比单个分片查询性能要差 但是只要不是太多的分片(2-3个)那么让读只落在有限的分片
总结:sharing基本法则
1、sharing key 应该是主键
2、选择分sharding key的时候应该选择那些避免跨分片查询,但是又得保证写是均匀的
3、将有关联的表放置在独立库中
部署分片集群
规划:
服务器IP |
服务器角色 |
操作系统 |
172.23.215.61 |
config server、mongos、mongod |
Debian GNU/Linux 7.2 |
172.23.214.50 |
config server、mongos、mongod |
Debian GNU/Linux 7.2 |
172.23.214.47 |
mongos、mongod |
Debian GNU/Linux 7.2 |
配置文件路径:
- /mongo/etc/configsvr.conf
- /mongo/etc/mongod.conf
- /mongo/etc/mongos.conf
日志路径:
- config server /var/log/mongo/mongod_config_server.log
- mongod /var/log/mongo/mongod.log
- mongos /var/log/mongo/mongos.log
数据存放路径:
- /mongo/data/configdb
- /mongo/data/configsvr
- /mongo/data/mongod
1.建立副本集
修改各节点配置文件,如下所示:
- root@datanode1:/mongo/etc# cat mongod.conf | grep -v "#"
- logpath=/var/log/mongo/mongod.log
- logappend=true
- fork = true
- port = 27017
- dbpath=/mongo/data
- pidfilepath = /var/run/mongodb/mongod.pid
- replSet = rs0
- rest = true
- maxConns=1024
- oplogSize=2048
启动各个节点mongod
- root@datanode1:/mongo/etc# mongod -f mongod.conf
将master添加进副本集
- root@datanode1:/mongo/etc# mongo> rsconf = { _id: "rs0",members: [ { _id: 0, host: "172.23.215.61:27017" } ] }
- {
- "_id" : "rs0",
- "members" : [
- {
- "_id" : 0,
- "host" : "172.23.215.61:27017"
- }
- ]
- }
激活副本集
- > rs.initiate( rsconf )
- {
- "info" : "Config now savedlocally. Should come online in about a minute.",
- "ok" : 1
- }
- > rs.conf()
- {
- "_id" : "rs0",
- "version" : 1,
- "members" : [
- {
- "_id" : 0,
- "host" : "172.23.215.61:27017"
- }
- ]
- }
陆续添加mongod节点
- rs0:PRIMARY> rs.add("172.23.214.50:27017")
- rs0:PRIMARY> rs.add("172.23.214.47:27017")
查看成员
- rs0:PRIMARY> rs.conf()
- {
- "_id" :"rs0",
- "version" : 3,
- "members" : [
- {
- "_id" : 0,
- "host" :"172.23.215.61:27017"
- },
- {
- "_id" : 1,
- "host" :"172.23.214.50:27017"
- },
- {
- "_id" : 2,
- "host" :"172.23.214.47:27017"
- }
- ]
- }
测试:
新建集合并插入数据,在从库查看是否同步
- rs0:PRIMARY> use test11;
- switched to db test11
- rs0:PRIMARY> for(i=1;i<=100;i++)db.testcoll.insert({Name:"User"+i,Age:i,Gender:"M",preferbook:["bluebook","yellow book"]})
去从库查看
- rs0:SECONDARY> show dbs;
- local 2.0771484375GB
- test11 0.203125GB
- testdb 0.203125GB
2.配置config server
新建立配置文件,各节点内容相同
- root@datanode1:/mongo/etc# cat configsvr.conf
- configsvr=true
- dbpath=/mongo/data/configdb/
- port=27019
- logpath=/var/log/mongo/mongod_config_server.log
- logappend=true
- fork=true
启动config server
- root@datanode1:/mongo/etc# mongod -f configsvr.conf
查看端口是否被监听
- root@datanode1:/mongo/etc# netstat -lnt | grep 27
- tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
- tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
- tcp 0 0 0.0.0.0:27017 0.0.0.0:* LISTEN
- tcp 0 0 0.0.0.0:27019 0.0.0.0:* LISTEN
3.配置mongos
- root@datanode1:/mongo/etc# cat mongos.conf
- # mongo.conf
- port=27020
- configdb=172.23.215.61:27019,172.23.214.47:27019,172.23.214.50:27019 #指定各config server的ip地址或hostname,以及端口
- fork = true
- logpath=/var/log/mongo/mongos.log
- chunkSize = 100
- logappend = true
启动路由(mongos)
- root@datanode1:/mongo/etc# mongos -f mongos.conf
使用mongo命令连入mongos实例
- root@datanode1:/mongo/etc# mongo 172.23.215.61:27020
向分区集群中添加各shard服务器或副本集,如果添加的shard是副本集,则需要使用如下格式:
- mongos> sh.addShard("rs0/172.23.215.61:27017")
- { "shardAdded" : "rs0", "ok" : 1 }
查看状态
- mongos> sh.status()
- --- Sharding Status ---
- sharding version: {
- "_id" : 1,
- "version" : 3,
- "minCompatibleVersion" : 3,
- "currentVersion" : 4,
- "clusterId" :ObjectId("532fa07065574826130abfbf")
- }
- shards:
- { "_id" : "rs0", "host" :"rs0/172.23.214.47:27017,172.23.214.50:27017,172.23.215.61:27017" }
- databases:
- { "_id" : "admin", "partitioned" : false, "primary" : "config"}
- { "_id" : "test11", "partitioned" : false, "primary" : "rs0" }
- { "_id" : "testdb", "partitioned" : false, "primary" : "rs0" }
4.启用sharding功能
mongodb的shard功能实现于collection级别,但若要在collection上启动shard,还需要事先其相关的数据库上启用之。在数据库上启用shard功能后,MongoDB会为其指定一个主shard。
激活数据库分片
- switched to db adminmongos
- mongos> db.runCommand( { enablesharding : "test11" } );
- { "ok" : 1 }
- mongos> db.runCommand( { enablesharding : "testdb" } );
- { "ok" : 1 }
激活collection分片
- mongos> use test11
- mongos> show collections
- system.indexes
- testcoll #将此表进行激活
进入admin库,激活collection分片并配置shard key唯一
- >use admin
- mongos> db.runCommand( { shardcollection : "test11.testcoll",key : {_id : 1 } , unique : true } )
- { "collectionsharded" : "test11.testcoll", "ok" :1 }
查看分片状态信息
- mongos> db.printShardingStatus();
- --- Sharding Status ---
- sharding version: {
- "_id" : 1,
- "version" : 3,
- "minCompatibleVersion" : 3,
- "currentVersion" : 4,
- "clusterId" :ObjectId("532fa07065574826130abfbf")
- }
- shards:
- { "_id" : "rs0", "host" :"rs0/172.23.214.47:27017,172.23.214.50:27017,172.23.215.61:27017" }
- databases:
- { "_id" : "admin", "partitioned" : false, "primary" : "config"}
- { "_id" : "test11", "partitioned" : true, "primary" : "rs0" }
- test11.testcoll
- shard key: { "_id" : 1 }
- chunks:
- rs0 1
- { "_id" : { "$minKey" : 1 } } -->> { "_id": { "$maxKey" : 1 } } on : rs0 Timestamp(1, 0)
- { "_id" : "testdb", "partitioned" : true, "primary" : "rs0" }
- { "_id" : "test", "partitioned" : false, "primary" : "rs0" }