学习 MongoDB(一)

1、介绍

MongoDB是C++语言编写,是一个基于分布式文件存储的开源数据库系统,MongoDB将数据存储为一个文档,
数据结构由键值对(key=>value)组成,MongoDB文档类似于 JSON 对象

2、MongoDB和MySQL对比

1、逻辑结构对比
MySQL            mongo
库                库
表                集合
字段              key:value
行                文档

2、内容对比:
1)mysql数据结构:
name            age     job  
oldzhang        28      it 
xiaozhang       28      it
xiaofei         18      student

2)mongo数据结构:
{name:'oldzhang',age:'28',job:'it'},
{name:'xiaozhang',age:'28',job:'it'},
{name:'xiaofei',age:'18',job:'student'}

3、应用场景

游戏场景: 使用 MongoDB 存储游戏的用户信息,装备、积分等直接以内嵌文档的形式存储,方便查询、更新
物流场景: 使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来
社交场景: 使用 MongoDB 存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能
物联网场景: 使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析
视频直播: 使用 MongoDB 存储用户信息、礼物信息等,用户评价
电商场景: 使用 MongoDB 存储上衣和裤子两种商品,除了有共同属性(产地、价格、材质、颜色等),还有各自不同的属性(上衣的肩宽、胸围、袖长,裤子臀围、脚口和裤长)

4、安装与部署

官方文档:https://docs.mongodb.com/manual/?_ga=2.57024426.1834178963.1557492386-816165234.1557492386
1、系统准备
1) redhat或cnetos6.2以上系统
2) 系统开发包完整
3) ip地址和hosts文件解析正常
4) iptables防火墙&SElinux关闭
5) 关闭大页内存机制
# echo never > /sys/kernel/mm/transparent_hugepage/enabled        
# echo never > /sys/kernel/mm/transparent_hugepage/defrag    
其他系统关闭参照官方文档:    https://docs.mongodb.com/manual/tutorial/transparent-huge-pages/
# vim /etc/security/limits.conf
  *     -    nofile   65535

2、二进制安装
下载地址:https://www.mongodb.org/dl/linux/
1)创建用户和组
# useradd mongodb -s /sbin/nologin -M

2)创建mongodb所需目录
# mkdir -p /mongodb/{conf,log,data}

3)下载并解压软件到指定位置
# wget  http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.2.16.tgz
# tar xf mongodb-linux-x86_64-rhel70-3.6.12_.tgz 
# cp -a mongodb-linux-x86_64-rhel70-3.6.12/bin /mongodb/

4)设置目录权限
# chown -R mongod:mongod  /mongodb

5)设置用户环境变量
# su - mongod
# vim .bash_profile
  export PATH=/mongodb/bin:$PATH
# source .bash_profile

3、启动mongodb
# su - mongod 
# mongod --dbpath=/mongodb/data --logpath=/mongodb/log/mongodb.log --port=27017 --logappend --fork 

4、配置文件说明(YAML格式)
systemLog:                                  #系统日志  
   destination: file                        #日志以文件保存           
   path: "/mongodb/log/mongodb.log"         #日志位置
   logAppend: true                          #日志以追加模式记录  
storage:                                    #数据存储
   journal:                                 #记录回滚日志
      enabled: true 
   dbPath: "/mongodb/data"                  #数据路径的位置 
   directoryPerDB: true
   wiredTiger:                              #存储引擎
      engineConfig:
         cacheSizeGB: 1                     #缓存大小
         directoryForIndexes: true          #索引单独存放
     collectionConfig:   
         blockCompressor: zlib              #启动压缩
     indexConfig:
         prefixCompression: true   
processManagement:                          #进程控制
   fork: true                               #后台守护进程
   pidFilePath: <string>                    #pid文件的位置,一般不配置,自动生成到data中      
net:                                        #网络配置
   bindIp: <ip>                             #监听地址
   port: <port>                             #端口号,不配置默认是: 27017     
security:                                   #安全配置 
  authorization: enabled                    #打开用户名密码验证
  
5、编写配置文件
# cat >  /mongodb/conf/mongo.conf <<EOF
  systemLog:
     destination: file
     path: "/mongodb/log/mongodb.log"
     logAppend: true
  storage:
     journal:
        enabled: true
     dbPath: "/mongodb/data/"
  processManagement:
     fork: true
  net:
     port: 27017
     bindIp: 10.0.1.51,127.0.0.1
EOF  

6、mongodb的关闭和启动方式
# mongod -f /mongodb/conf/mongo.conf  --shutdown    
# mongod -f /mongodb/conf/mongo.conf                
# mongo localhost:27017         #登录
> use admin                     #切换库
> db.shutdownServer()           #执行关机函数

7、systemd 管理(root)
# cat > /etc/systemd/system/mongod.service <<EOF
  [Unit]
  Description=mongodb 
  After=network.target remote-fs.target nss-lookup.target
  [Service]
  User=mongod
  Type=forking
  ExecStart=/mongodb/bin/mongod --config /mongodb/conf/mongo.conf
  ExecReload=/bin/kill -s HUP $MAINPID
  ExecStop=/mongodb/bin/mongod --config /mongodb/conf/mongo.conf --shutdown
  PrivateTmp=true  
  [Install]
  WantedBy=multi-user.target
EOF
# systemctl restart mongod
# systemctl stop mongod
# systemctl start mongod

 5、mongodb基本操作

1、默认库
# mongo                                     #登录
> show databases                            #查看库
> show dbs
  admin库:   系统预留库,MongoDB系统管理库
  local库:   本地预留库,存储关键日志
  config库:  MongoDB配置信息库
  test库:    登录时默认存在的库(隐藏的库)

2、命令种类
1) 库
> db                                        #当前在的库
> db.[TAB]                                  #类似于linux中的tab功能
> db.help()                                 #db级别的命令使用帮助
2) 表(collection):
> db.Collection_name.xxx
3) 行(document)
> db.t1.insert()
4)复制集有关(replication set):
> rs.[TAB]    
> rs.help()
5)分片集群(sharding cluster)
> sh.[TAB]    
> sh.help()

3、帮助
> help
> KEYWORDS.help()
> KEYWORDS.[TAB]
> db.help()
> db.a.help()
> rs.help()
> sh.help()

4、常用操作
> db.version()                              #查看当前db版本
> db                                        #显示当前数据库
> db.getName()                              #显示当前数据库
> show dbs                                  #查询所有数据库
> use local                                 #切换数据库
> show  tables;                             #查看所有表
> db.stats()                                #显示当前数据库状态
> db.getMongo()                             #查看当前数据库的连接机器地址
> db.hello.insert({name:"a"})               #录入数据
> db.hello.find()                           #查看数据
> db.hello.drop()                           #删除表

5、库的操作
> use linux                                 #use库,自动创建(临时,show 看不到库)
> db.db.insert({name:"haha"})               #创建db库,并插入数据(永久库)
> db.dropDatabase()                         #删除数据库(要use库)

6、集合的操作
1) 创建表:
方法1:
> use app
> db.createCollection('a')
> db.createCollection('b')
> show tables;                              #查看当前库所有的表
> db.getCollectionNames()
方法2:
> use oldboy
> db.oldguo.insert({id:"1",name:"tom"})     #自动创建表
2) 查询数据
> db.oldguo.find()                          #查看所有数据(默认显示20条,输入it,查看下一页)
> db.oldguo.find({id:"1"})                  #查找某个条件
> db.oldguo.find({id:"1"}).pretty()         #按行显示(json)
3) 删除集合
> use app
> db.log.drop()                             #删除表
4) 重命名集合
> db.log.renameCollection("log1")           #更改表名
5) 批量插入数据
for(i=0;i<10000;i++){db.log.insert({"uid":i,"name":"mongodb","age":6,"date":newDate()})}
6) 其他
> DBQuery.shellBatchSize=50;                #每页显示50条记录
> db.log.findOne()                          #查看第1条记录
> db.log.count()                            #统计记录数
> db.log.remove({})                         #删除集合中所有记录
> db.log.distinct("name")                   #某列去重
> db.log.stats()                            #集合状态
> db.log.dataSize()                         #集合中数据的原始大小
> db.log.totalIndexSize()                   #集合中索引数据的原始大小
> db.log.totalSize()                        #集合中索引+数据压缩存储之后的大小
> db.log.storageSize()                      #集合中数据压缩存储的大小

 6、用户及权限管理

1、介绍
MySQL  的登录验证方式: 用户名+密码+IP+端口号
MongoDB的登录验证方式: 用户名+密码+IP+端口号+验证库

2、注意事项
验证库: 建立用户时use到的库,对于管理员用户,必须在admin库下创建
1) 建用户时,use到的库,就是此用户的验证库
2) 登录时,必须明确指定验证库才能登录
3) 管理员的验证库是admin,普通用户的验证库是所管理的库
4) 如果直接登录到数据库,不进行use,默认的验证库是test,生产不推荐
5) 从3.6 版本开始,不添加bindIp参数,默认不让远程登录,只能本地管理员登录

3、用户创建语法
> use admin                                 #在库下创建用户
> db.createUser(                            #创建用户命令
{
    user: "root",                           #用户名
    pwd: "root123",                         #密码
    roles: [
       { role: "root",                      #角色(root,readWrite,read)
     db: "admin" } ]                        #管理的库
}
)
登录
# mongo -u root -p 10.0.0.51/admin

4、创建超级管理员
1) 修改配置文件(开启认证功能)
# vim /mongodb/conf/mongo.conf 
  net:
    port: 27017
    bindIp: 10.0.0.51,127.0.0.1
  security:
    authorization: enabled
2) 创建管理员用户(必须use admin库下去创建,只能针对库设置权限,不能针对表)    
# mongo
> use admin
> db.createUser(
{
    user: "root",
    pwd: "root123",
    roles: [ { role: "root", db: "admin" } ]
}
)
3) 验证用户
> db.auth('root','root123')
4) 重启mongodb
# mongod -f /mongodb/conf/mongo.conf --shutdown 
# mongod -f /mongodb/conf/mongo.conf 
5) 登录验证
方法1:
# mongo -uroot -proot123  admin
# mongo -uroot -proot123  10.0.0.51/admin
# mongo -uroot -proot123  10.0.0.51:27017/admin
方法2:
# mongo
> use admin
> db.auth('root','root123')
6) 查看用户:
> use admin
> db.system.users.find().pretty()           #查看用户的信息  

5、创建库管理用户
1) 管理员登录
# mongo -uroot -proot123  admin
2) 创建app库管理用户
> use app
> db.createUser(
{
    user: "admin",
    pwd: "admin",
    roles: [ { role: "dbAdmin", db: "app" } ]
}
)
3) 验证并登录测试
> db.auth('admin','admin')
# mongo -uadmin -padmin 10.0.0.51/app

6、创建app库,可读可写的用户
1) 管理员登录
# mongo -uroot -proot123  admin
2) 创建app库管理用户
> use app
> db.createUser(
{
    user: "app01",
    pwd: "app01",
    roles: [ { role: "readWrite", db: "app" } ]
}
)
3) 验证并登录测试
# mongo  -uapp01 -papp01 10.0.0.51/app

7、创建app库可读可写,并对test库只读的用户
1) 管理员登录
# mongo -uroot -proot123 10.0.0.51/admin
2) 创建app库管理用户
> use app
> db.createUser(
{
    user: "app02",
    pwd: "app02",
    roles: [ { role: "readWrite", db: "app" },
    { role: "read", db: "test" }]
}
)
3) 验证并登录测试
# mongo  -uapp02 -papp02 10.0.0.51/app
> db.system.users.find().pretty()               

8、删除用户
1) 管理员登录
# mongo -uroot -proot123 10.0.0.51/admin
2) 删除用户(必须use到用户的验证库)
> use app
> db.dropUser("app01")

 7、MongoDB复制集RS(ReplicationSet)

1、基本原理
基本1主2从的结构,自带互相监控投票机制(Raft(MongoDB)、Paxos(mysql MGR用的是变种))
如果发生主库宕机,复制集内部进行投票选举,选择一个新的主库,
并自动通知客户端程序,主库已经发生切换,应用就会连接到新的主库

2、 Replication Set配置
1) 环境准备
多实例: 三个以上的mongodb节点(28017280182801928020)
2) 创建目录
# su - mongod 
$ mkdir -p /mongodb/{28017,28018,28019,28020}/{data,conf,log}
3) 创建配置文件
$ cat > /mongodb/28017/conf/mongod.conf <<EOF
  systemLog:
    destination: file
    path: /mongodb/28017/log/mongodb.log
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/28017/data
    directoryPerDB: true
    #engine: wiredTiger
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  processManagement:
    fork: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 28017
  replication:
    oplogSizeMB: 2048
    replSetName: my_repl
EOF
$ cp /mongodb/28017/conf/mongod.conf  /mongodb/28018/conf/
$ cp /mongodb/28017/conf/mongod.conf  /mongodb/28019/conf/
$ cp /mongodb/28017/conf/mongod.conf  /mongodb/28020/conf/
$ sed -i 's#28017#28018#g' /mongodb/28018/conf/mongod.conf
$ sed -i 's#28017#28019#g' /mongodb/28019/conf/mongod.conf 
$ sed -i 's#28017#28020#g' /mongodb/28020/conf/mongod.conf 
4) 启动多个实例
$ mongod -f /mongodb/28017/conf/mongod.conf
$ mongod -f /mongodb/28018/conf/mongod.conf
$ mongod -f /mongodb/28019/conf/mongod.conf
$ mongod -f /mongodb/28020/conf/mongod.conf
5) 检查端口
$ netstat -lnp|grep 280

3、配置普通复制集(1主2从,从库普通从库)
1) 登录到28017节点
$ mongo --port 28017 admin
2) 定义一个config变量
> config = {_id: 'my_repl', members: [      
                    {_id: 0, host: '10.0.0.51:28017'},
                    {_id: 1, host: '10.0.0.51:28018'},
                    {_id: 2, host: '10.0.0.51:28019'}]
          }    
> rs.initiate(config)                       #复制集初始化
3) 查询复制集状态
> rs.status()
备注: 创建完复制集,从库默认不可读写,看不到数据,需要执行命令才能读
    临时命令(rs.slaveOk()),永久命令(echo "rs.slaveOk();" > ~/.mongorc.js)

4、1主1从1个arbiter
1) 登录到28017节点
$ mongo -port 28017 admin
2) 定义一个config变量
> config = {_id: 'my_repl', members: [
                    {_id: 0, host: '10.0.0.51:28017'},
                    {_id: 1, host: '10.0.0.51:28018'},
                    {_id: 2, host: '10.0.0.51:28019',"arbiterOnly":true}]
          }                
> rs.initiate(config) 

5、复制集管理操作
1) 查看复制集
> rs.status()                               #查看复制集状态
> rs.isMaster()                             #查看当前是否为主节点
> rs.conf()                                 #查看复制集配置信息
2) 添加删除节点
> rs.remove("ip:port")                      #删除一个从节点
> rs.add("ip:port")                         #添加一个从节点
> rs.addArb("ip:port")                      #添加一个仲裁节点

6、实例
1) 连接到主节点
$ mongo --port 28018 admin
2) 添加仲裁节点
> rs.addArb("10.0.0.53:28020")
3) 查看节点状态
> rs.isMaster()
4) 删除一个节点
> rs.remove("10.0.0.53:28019");
> rs.isMaster()
5) 新增从节点
> rs.add("10.0.0.53:28019")
> rs.isMaster()

7、特殊从节点
1) 介绍
arbiter节点: 负责选主过程中的投票,不存储任何数据,不提供任何服务
hidden节点: 隐藏节点,不参加选主,不对外提供服务
delay节点: 延时节点,数据落后于主库一段时间,不提供服务,不参加选主,通常配合hidden使用
priority 0: 权重为0,不参加选主
2) 配置延时节点(一般延时节点也配置成hidden)
> cfg=rs.conf()                             #把rs.conf()输出信息,赋值给变量cfg
> cfg.members[2].priority=0                 #利用cfg变量调用节点,修改相应部分
> cfg.members[2].hidden=true                
> cfg.members[2].slaveDelay=120
> rs.reconfig(cfg)                          #重新读取
3) 查看状态
> rs.conf()
4) 取消延时节点
> cfg=rs.conf() 
> cfg.members[2].priority=1
> cfg.members[2].hidden=false
> cfg.members[2].slaveDelay=0
> rs.reconfig(cfg)    
5) 注意事项
[2]: 中括号中的数字,不是id 的值,是节点的编号,从0开始

8、其他操作命令
> rs.conf()                                 #查看副本集的配置信息
> rs.status()                               #查看副本集的状态
> rs.stepDown()                             #副本集角色切换(不要人为随便操作)
> rs.freeze(300)                            #锁定从库,不会变成主库(freeze()和stepDown单位都是秒)
> rs.slaveOk()                              #设置从库可读,在从库执行
> rs.printSlaveReplicationInfo()            #查看副本节点(监控主从延时)

9、配置文件解析
1) 日志
systemLog:                                  #系统日志
destination: file                           #日志输出,可指定file或syslog(输出到日志文件),若不指定,则输出到标准输出
verbosity: 0                                #日志级别,0:默认值,包含info信息,1~5包含debug信息
logAppend: true                             #日志追加,当mongod/mongos重启后,true(追加模式继续记录),false(创建新的日志文件)
logRotate: rename                           #日志轮询,rename(重命名日志文件,默认值),reopen(利用logrotate特性,关闭并重新打开此日志文件,logAppend必须为true)
2)存储
storage:                                    #存储相关
journal                                     #是否开启回滚日志,用来恢复数据,仅对mongod进程有效,64位默认(true),32位(false)
directoryPerDB: true                        #是否将不同DB的数据,存储在不同的目录中
engine                                      #存储引擎类型,3.0之后支持mmapv1(相当于MyISAM)、wiredTiger(相当于InnoDB),默认: mmapv1
wiredTiger:                                 #存储引擎
cacheSizeGB: 1                              #wiredTiger缓存工作集,内存大小
directoryForIndexes: true                   #是否将索引和collections存储到不同的目录
blockCompressor: zlib                       #数据压缩,算法可选none、snappy、zlib
prefixCompression: true                     #是否对索引数据使用前缀压缩,前缀压缩(对经过排序的值压缩,有效减少索引数据的内存使用量)
3) 进程管理
processManagement:                          #进程相关
fork: true                                  #后台运行
pidFilePath: /mongodb/data/mongod.pid       #PID 文件路径
4)复制集
replication:                                #主从复制 
oplogSizeMB: 2048                           #oplog日志表的大小,oplog是记录到表中,默认为磁盘的5%
replSetName:                                #复制集的名,主从复制中集群的名字必须相同,在分片集群中,不同的分片,应有不同的名字

 8、MongoDB 分片集群SH(Sharding Cluster) 

1)、介绍

Shard: 分片集群,存储实际的数据,生产环境中一个shard集群,由多台机器多实例组成,防止单点故障
Config Server: 配置集群,mongod实例,存储整个集群的Metadata,其中包括chunk信息
mongos: 和客户端打交道的模块,数据路由,本身没有任何数据,处理数据时,直接找config server

2)、安装部署

1、规划:
10个实例:38017-38026
1) configserver: 38018-38020(3台构成的复制集,1主两从,不支持arbiter,复制集名字configsvr)  
2) shard节点: sh1: 38021-38023,sh2: 38024-38026(1主两从,其中一个节点为arbiter,复制集名字sh1,sh2)
3) mongos: 38017

2、shard节点配置
1) 创建目录
# mkdir -p /mongodb/{38021,38022,38023,38024,38025,38026}/{log,data,conf}
2) 修改配置文件
A、sh1(分片节点一,21-23,1主1从1选举Arb)
# cat > /mongodb/38021/conf/mongodb.conf<<EOF 
  systemLog:
    destination: file
    path: /mongodb/38021/log/mongodb.log   
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/38021/data
    directoryPerDB: true
    #engine: wiredTiger
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38021
  replication:
    oplogSizeMB: 2048
    replSetName: sh1
  sharding:
    clusterRole: shardsvr                   #集群角色名,官方定义,不能自定义
  processManagement: 
    fork: true
EOF
# cp  /mongodb/38021/conf/mongodb.conf  /mongodb/38022/conf/
# cp  /mongodb/38021/conf/mongodb.conf  /mongodb/38023/conf/
# sed 's#38021#38022#g' /mongodb/38022/conf/mongodb.conf -i
# sed 's#38021#38023#g' /mongodb/38023/conf/mongodb.conf -i
B、sh2(分片节点二,24-26,1主1从1选举Arb)
# cat > /mongodb/38024/conf/mongodb.conf<<EOF 
  systemLog:
    destination: file
    path: /mongodb/38024/log/mongodb.log   
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/38024/data
    directoryPerDB: true
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38024
  replication:
    oplogSizeMB: 2048
    replSetName: sh2
  sharding:
    clusterRole: shardsvr
  processManagement: 
    fork: true
EOF
# cp  /mongodb/38024/conf/mongodb.conf  /mongodb/38025/conf/
# cp  /mongodb/38024/conf/mongodb.conf  /mongodb/38026/conf/
# sed 's#38024#38025#g' /mongodb/38025/conf/mongodb.conf -i
# sed 's#38024#38026#g' /mongodb/38026/conf/mongodb.conf -i
3) 启动节点,并配置复制集
A、启动
# mongod -f  /mongodb/38021/conf/mongodb.conf 
# mongod -f  /mongodb/38022/conf/mongodb.conf 
# mongod -f  /mongodb/38023/conf/mongodb.conf 
# mongod -f  /mongodb/38024/conf/mongodb.conf 
# mongod -f  /mongodb/38025/conf/mongodb.conf 
# mongod -f  /mongodb/38026/conf/mongodb.conf  
B、分片节点一
# mongo --port 38021 admin
> config = {_id: 'sh1', members: [
                    {_id: 0, host: '10.0.0.51:38021'},
                    {_id: 1, host: '10.0.0.51:38022'},
                    {_id: 2, host: '10.0.0.51:38023',"arbiterOnly":true}]
           }
> rs.initiate(config)
C、分片节点二
# mongo --port 38024  admin
> config = {_id: 'sh2', members: [
                    {_id: 0, host: '10.0.0.51:38024'},
                    {_id: 1, host: '10.0.0.51:38025'},
                    {_id: 2, host: '10.0.0.51:38026',"arbiterOnly":true}]
           } 
> rs.initiate(config)

3、config节点配置
1) 创建目录
# mkdir -p /mongodb/{38018,38019,38020}/{log,data,conf}
2) 修改配置文件
# cat > /mongodb/38018/conf/mongodb.conf <<EOF
  systemLog:
    destination: file
    path: /mongodb/38018/log/mongodb.conf
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/38018/data
    directoryPerDB: true
    #engine: wiredTiger
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38018
  replication:
    oplogSizeMB: 2048
    replSetName: configReplSet
  sharding:
    clusterRole: configsvr                  #集群角色名,官方定义,不能自定义
  processManagement: 
    fork: true
EOF
# cp /mongodb/38018/conf/mongodb.conf /mongodb/38019/conf/
# cp /mongodb/38018/conf/mongodb.conf /mongodb/38020/conf/
# sed 's#38018#38019#g' /mongodb/38019/conf/mongodb.conf -i
# sed 's#38018#38020#g' /mongodb/38020/conf/mongodb.conf -i
3) 启动节点,并配置复制集
A、启动
# mongod -f /mongodb/38018/conf/mongodb.conf 
# mongod -f /mongodb/38019/conf/mongodb.conf 
# mongod -f /mongodb/38020/conf/mongodb.conf 
B、配置复制集
# mongo --port 38018 admin
< config = {_id: 'configReplSet', members: [
                    {_id: 0, host: '10.0.0.51:38018'},
                    {_id: 1, host: '10.0.0.51:38019'},
                    {_id: 2, host: '10.0.0.51:38020'}]
           }
> rs.initiate(config)  
备注: configserver老版本中,可以是一个节点,新版本中,必须是复制集,新老版本都不支持arbiter

4、mongos节点配置
1) 创建目录
# mkdir -p /mongodb/38017/conf  /mongodb/38017/log 
2) 修改配置文件
# cat >/mongodb/38017/conf/mongos.conf<<EOF
  systemLog:
    destination: file
    path: /mongodb/38017/log/mongos.log
    logAppend: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38017
  sharding:
    configDB: configReplSet/10.0.0.51:38018,10.0.0.51:38019,10.0.0.51:38020   #configserver集群节点
  processManagement: 
    fork: true
EOF 
3) 启动mongos
# mongos -f /mongodb/38017/conf/mongos.conf 
备注: 启动不了,检查configserver集群节点,mongos依赖configserver

5、分片集群添加节点(把shar所有节点加入到configserver集群中)
1)连接mongs的admin数据库
# su - mongod
# mongo 10.0.0.51:38017/admin
2) 添加分片
> db.runCommand( { addshard : "sh1/10.0.0.51:38021,10.0.0.51:38022,10.0.0.51:38023",name:"shard1"} )
> db.runCommand( { addshard : "sh2/10.0.0.51:38024,10.0.0.51:38025,10.0.0.51:38026",name:"shard2"} )
3) 列出分片
> mongos> db.runCommand( { listshards : 1 } )
4) 查看集群状态
> sh.status()

 3)、分片集群操作

 

 

 

分片集群操作
1、介绍
1) 分片规则: 
默认数据存储在shard1上,在shard1初始1个chunk(默认大小64M),chunk大于64M,会自动拆分,
如果shard1的chunk比较多,会自动迁移一部分到shard2,mongos会自动检查所有节点chunk情况,
若发现分片不均衡,会触发balancer操作,自动chunk迁移(通过网络迁移)

2) 分片键
必须为分片collection定义分片键,基于一个或多个列(类似一个索引)
分片键定义数据空间,想象key space类似一条线上一个点数据
一个key range是一条线上一段数据,我们可以按照分片键进行Range和Hash分片
分片键是不可变,分片键必须有索引,分片键大小限制512字节,分片键用于路由查询
MongoDB不接受已进行collection级分片的collection上插入无分片键的文档(不支持空行)

2、Range分片
1) 激活分片功能
# mongo --port 38017 admin
> db.runCommand( { enablesharding : "test" } )
2) 创建索引(分片键必须要建索引)
> use test
> db.vast.ensureIndex( { id: 1 } )
3) 开启分片(range分片一般是数字列,条件查询多的列)
> use admin
> db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )    #1:从小到大,-1:从大到小
4) 插入数据
admin> use test
test> for(i=1;i<1000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
test> db.vast.stats()
5) 查看分片结果
shard1:
# mongo --port 38021
> use test
> db.vast.count();
shard2:
# mongo --port 38024
> use test
> db.vast.count();
备注:去分片节点查看数据,会发现只写在一个节点上,是因为没有设置blancer,
      数据录完后,mogos会触发blancer操作,进行chunk自动转移,所以要等一段时间

3、Hash分片
1) 激活分片功能
# mongo --port 38017 admin
> use admin
> db.runCommand( { enablesharding : "oldboy" } )
2) 创建哈希索引
> use oldboy
> db.vast.ensureIndex( { id: "hashed" } )
3) 开启分片 
> use admin
> sh.shardCollection( "oldboy.vast", { id: "hashed" } )
4) 插入数据
> use oldboy
> for(i=1;i<100000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
5) 查看分片结果
shard1:
# mongo --port 38021
> use oldboy
> db.vast.count();
shard2:
# mongo --port 38024
> use oldboy
> db.vast.count();

4、分片集群的查询
> sh.status()                               #分片状态(重要)
> db.runCommand({ isdbgrid : 1})            #判断是否Shard集群
> db.runCommand({ listshards : 1})          #列出所有分片信息
> use config                                #列出开启分片的数据库
> db.databases.find( { "partitioned": true } )
> db.databases.find()                       #列出所有数据库分片情况
> db.collections.find().pretty()            #查看分片的分片键
> db.printShardingStatus()                  #查看分片的详细信息

5、分片集群的删除及添加
1) 确认blance是否在工作
> sh.getBalancerState()
2) 删除shard2节点(谨慎)
> db.runCommand( { removeShard: "shard2" } )
注意: 删除操作会立即触发blancer,自动chunk迁移
3) 添加分片
> db.runCommand( { addshard : "sh3/192.168.2.10:38030,192.168.2.11:38031,192.168.2.12:38032",name:"shard3"} )
注意: 添加操作会触发blancer,自动chunk迁移

4)、balancer操作

1、介绍
mongos的一个重要功能,自动巡查所有shard节点上的chunk的情况,自动做chunk迁移。

2、什么时候工作?
1) 自动运行,会检测系统不繁忙的时候做迁移
2) 在做节点删除的时候,立即开始迁移工作
3) balancer只能在预设定的时间窗口内运行(balancer默认24小时工作的,为了性能,必须设置时间)
4) 有需要时可以关闭和开启blancer(备份时,要关闭balancer)
> sh.stopBalancer()
> sh.startBalancer()

3、自定义balancer的时间段
官网文档: https://docs.mongodb.com/manual/tutorial/manage-sharded-cluster-balancer/#schedule-the-balancing-window
1) 登录到mongos
# mongo --port 38017 admin
2) 设置balancer的时间段
> use config
> sh.setBalancerState( true )
> db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "3:00", stop : "5:00" } } }, true )
3) 查看balancer(2个都可以查看)
> sh.getBalancerWindow()
> sh.status()
4) 关闭某个集合的balance(了解)
> sh.disableBalancing("students.grades")
5) 打开某个集合的balancer(了解)
> sh.enableBalancing("students.grades")
6) 确定某个集合的balance是开启或者关闭(了解)
> db.getSiblingDB("config").collections.findOne({_id : "students.grades"}).noBalance;

9、MongoDB数据备份恢复

1、备份恢复工具介绍
1) mongoexport/mongoimport      **
2) mongodump/mongorestore       *****

2、备份工具区别
mongoexport/mongoimport     导入/导出的是JSON格式或者CSV格式
mongodump/mongorestore      导入/导出的是BSON格式
1)JSON可读性强但体积大,BSON是二进制文件,体积小但可读性弱
2)跨版本还原时,BSON格式随版本可能有所不同,不同版本数据迁移会失败,推荐使用JSON格式
3)JSON虽有较好的跨版本通用性,但只保留数据部分,不保留索引,账户等其他基础信息

3、应用场景总结
mongoexport/mongoimport: json csv 
1) 异构平台迁移    mysql  <---> mongodb
2) 同平台,跨大版本 mongodb 2  ----> mongodb 3
mongodump/mongorestore
日常备份恢复时使用

4、导出工具(mongoexport)
1) 介绍
mongoexport: 把一个collection导出成JSON或CSV格式的文件
使用场景: 版本差异较大,异构平台数据迁移
2) 参数说明
# mongoexport --help  
  -h:                                       #指明数据库宿主机的IP
  -u:                                       #指明数据库的用户名
  -p:                                       #指明数据库的密码
  -d:                                       #指明数据库的名字
  -c:                                       #指明collection的名字
  -f:                                       #指明要导出那些列
  -o:                                       #指明到要导出的文件名
  -q:                                       #指明导出数据的过滤条件
  --authenticationDatabase admin            #验证库
3) 单表导出json格式
# mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/log.json
4) 单表导出csv格式
# mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log --type=csv -f uid,name,age,date  -o /mongodb/log.csv  
5) 注意事项
备份文件名可自定义,默认导出JSON格式数据,加--type=csv -f 字段,导出CSV格式
  
5、导入工具(mongoimport)  
1) 介绍
mongoimport: 一个特定格式文件中的内容,导入到指定的collection中,可以导入JSON或CSV格式数据
2) 参数说明
# mongoimport --help
  -h:                                       #指明数据库宿主机的IP
  -u:                                       #指明数据库的用户名
  -p:                                       #指明数据库的密码
  -d:                                       #指明数据库的名字
  -c:                                       #指明collection的名字
  -f:                                       #指明要导入那些列
  -j:                                       #并行(cpu核数)
  --drop:                                   #覆盖原来表中内容
3) 恢复json格式数据
# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log1 /mongodb/log.json
4) 恢复csv格式数据 
# csv格式的文件头行,有列名
# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log2 --type=csv --headerline --file  /mongodb/log.csv
# csv格式的文件头行,没有列名
# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log3 --type=csv -f id,name,age,date --file  /mongodb/log1.csv 
5) 注意事项
--headerline: 指明第一行是列名,不需要导入,如果导入没有头行,不想加-f只想用--headerline,要手工(vi编辑)加入列名

6、案例(异构平台数据迁移)
1) 介绍
mysql -----> mongodb(mysql里world库city表进行数据导出,再导入到mongodb)
2) mysql开启安全路径
# vim /etc/my.cnf   
  secure-file-priv=/tmp
# /etc/init.d/mysqld restart
3) 导出mysql的city表数据
以csv的格式导出(fields terminated by ',': 默认分隔符是空格,设置分隔符逗号)
mysql> select * from world.city into outfile '/tmp/city1.csv' fields terminated by ',';
4) 处理备份csv文件
mysql>> desc world.city                   #查看表字段
# vim /tmp/city.csv(添加第一行列名信息,文件大,不推荐) 
  ID,Name,CountryCode,District,Population
5) 导入数据
方法1(有列名)
# mongoimport -uroot -proot123 --port=27017 --authenticationDatabase admin -d world -c city --type=csv --headerline /tmp/city1.csv
方法2(无列名)
# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d world -c city --type=csv -f ID,Name,CountryCode,District,Population --file /tmp/city1.csv
6) 检查数据
# mongo --port 38017 admin
> use world
> db.city.find();

7、案例2(world库下100张表,全部迁移到mongodb)
1) 思路
mysql> select * from world.city into outfile '/tmp/world_city.csv' fields terminated by ',';
使用infomation_schema.columns(导出字段),information_schema.tables(导出语句)
2) 批量导出字段
mysql> use information_schema
mysql> select table_name ,group_concat(column_name) from columns where table_schema='world' group by table_name;
3) 批量导出语句
mysql> use information_schema
mysql> select concat("select * from ",table_schema,".",table_name ," into outfile '/tmp/",table_schema,"_",table_name,".csv' fields terminated by ',';")
from information_schema.tables where table_schema ='world';
4) mysql导出csv
mysql> select * from test_info   
into outfile '/tmp/test.csv'   
fields terminated by ','                   #字段间以,号分隔
optionally enclosed by '"'                  #字段用"号括起
escaped by '"'                          #字段中使用的转义符为"
lines terminated by '\r\n';                 #行以\r\n结束
5) mysql导入csv
mysql> load data infile '/tmp/test.csv'   
into table test_info    
fields terminated by ','  
optionally enclosed by '"' 
escaped by '"'   
lines terminated by '\r\n'; 

8、mongodump和mongorestore基本使用
1) 介绍
能够在Mongodb运行时备份,工作原理是对运行的Mongodb做查询,然后将查到的结果写入磁盘,但备份不一定是数据库的实时快照,
如果备份时数据库有写入操作,备份的文件可能和数据库的数据不一致,备份时对其它客户端性能会产生的影响
2) mongodump参数说明
$ mongodump --help
  -h:                                       #数据库宿主机的IP
  -u:                                       #数据库的用户名
  -p:                                       #数据库的密码
  -d:                                       #数据库的名字
  -c:                                       #collection的名字
  -o:                                       #要导出的文件名
  -q:                                       #导出数据的过滤条件
  -j,                                       #并行   
  --oplog                                   #同时备份oplog
3) 备份
全备
# mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup
单库备份
# mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -d world -o /mongodb/backup/
单表备份
# mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/backup/
压缩备份
# mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup/ --gzip
# mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup/ | xargs tar -czf all.tar.gz
4) 恢复
恢复全备
# mongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin /mongodb/backup/
# mongorestore -uroot -proot123 --port=27017 --authenticationDatabase admin /mongodb/backup/ --gzip
单库恢复
# mongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin -d world1 /mongodb/backup/world
单表恢复
# mongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin -d world -c t1 --gzip /mongodb/backup/oldboy/log1.bson.gz 
恢复前drop库
# mongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy --drop /mongodb/backup/oldboy
5) bson二进制转换json恢复
备份出来的表文件有json和bson格式,json:表中的列信息,bson:源数据,bson二进制文件可以用命令查看或导出json格式的文件
# bsondump abc.bson > abc.json
# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c abc abc.json

9、MongoDB集群备份和恢复
1) oplog介绍
oplog: 记录mongod实例一段时间内数据库的变更(插入/更新/删除)操作,replica set或master/slave模式专用
在replica set中oplog是一个定容集合(capped collection),默认大小是磁盘空间的5%(通过--oplogSizeMB参数修改)
位于local库的db.oplog.rs,当空间用完时会自动覆盖最老的记录
2) 查看oplog内容
> use local 
> db.oplog.rs.find().pretty()               
"ts" : Timestamp(1553597844, 1),            #时间戳,1:时间内第几个操作
    "op" : "n"                              #操作类型
    "o"  :                                  #具体操作内容
op类型:"i":insert, "u":update, "d":delete, "c":db cmd(drop操作)
3) oplog大小规划    
> rs.printReplicationInfo()                 #查看oplog时间窗口
configured oplog size:   2048MB                                         #集合大小
log length start to end: 423849secs (117.74hrs)                         #预计窗口覆盖时间
oplog first event time:  Wed Sep 09 2015 17:39:50 GMT+0800 (CST)
oplog last event time:   Mon Sep 14 2015 15:23:59 GMT+0800 (CST)
now:                     Mon Sep 14 2015 16:37:30 GMT+0800 (CST)
方法1: 设置足够大的空间(但管理很麻烦)
方法2: 定期备份oplog.rs表
4) oplog备份和恢复
热备(--oplog:会记录备份过程中的数据变化,以oplog.bson保存)
# mongodump --port 28017 --oplog -o /mongodb/backup
恢复
# mongorestore --port 28017 --oplogReplay /mongodb/backup

10、案例
1) 背景
每天0点全备,oplog恢复窗口为48小时
某天,上午10点world.city 业务表被误删除
2) 恢复思路:
停应用,找测试库
恢复昨天晚上全备
截取全备之后到world.city误删除时间点的oplog,并恢复到测试库
将误删除表导出,恢复到生产库
3) 模拟原始数据
# mongo --port 28017
> use wo
> for(var i = 1 ;i < 20; i++) {db.ci.insert({a: i});}
4) 全备(将备份过程中产生的日志进行备份)
# mongodump --port 28017 --oplog -o /mongodb/backup
5) 插入新数据
> db.ci1.insert({id:1})
> db.ci2.insert({id:2})
6) 误删除数据
> db.ci.drop()
> show tables;
7) 备份oplog.rs表
# mongodump --port 28017 -d local -c oplog.rs  -o /mongodb/backup
8) 获取oplog误删除时间点位置
$ mongo --port 28017
> use local
> db.oplog.rs.find({op:"c"}).pretty();
  "ts" : Timestamp(1553659908, 1)
9) 恢复备份+应用oplog
# cp oplog.rs.bson /mongodb/backup/oplog.bson 
# mongorestore --port 28018 --oplogReplay --oplogLimit "1553659908:1" --drop /mongodb/backup/

11、分片集群的备份
1) 要备份什么
config server、shard 节点(单独进行备份)
2) 备份有什么困难和问题
chunk迁移的问题: 备份的时,避开迁移的时间窗口
shard节点之间的数据不在同一时间点: 选业务量较少的时候
3) 手工备份
停balancer
备份时,同一个时间点,把configserver和shard节点的从库,临时摘下来
备份完成后,再把从库加回去

 

posted on 2020-10-10 14:16  五光十色  阅读(239)  评论(0编辑  收藏  举报

导航