MySQL之17---MongoDB

MySQL之17---MongoDB

逻辑结构

MongoDB逻辑结构 MySQL逻辑结构
库(database)
集合(collection)
文档(document) 数据行

应用:非常适合存储大数据,按地理位置查询(360:270节点)

多模查询:B数索引(MySQL),全盘索引(ES),非关系型数据库(Redis)

支持事务

NoSQL数据库

安装

系统准备

  1. redhat或centos6.2版本以上系统
  2. 系统开发包完整
  3. ip地址和hosts文件解析正常
  4. 关闭iptables防火墙&SElinux
  5. 关闭大页内存机制:官方文档
sudo cat >> /etc/rc.local <<EOF
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
  echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
   echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
EOF
reboot
# 验证
[root@db01 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
[root@db01 ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
always madvise [never]

为什么要关闭?

透明大页面(THP)是一种Linux内存管理系统,它通过使用较大的内存页面来减少具有大量内存的计算机上的转换后备缓冲区(TLB)查找的开销。

但是,启用THP时,数据库工作负载通常表现不佳,因为它们往往具有稀疏而不是连续的内存访问模式。在Linux上运行MongoDB时,应禁用THP以获得最佳性能。


安装

  1. 官网下载二进制包
cd /opt
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.2.tgz
  1. 上传mongodb二进制包,解压并建立软链接
cd /opt
tar xf mongodb-linux-x86_64-rhel70-4.2.8.tgz
ln -s /opt/mongodb-linux-x86_64-rhel70-4.2.8 /usr/local/mongodb
  1. 创建mongodb所需用户并设置密码
useradd mongod
passwd mongod
  1. 创建mongodb所需目录并授权
mkdir -p /mongodb/{conf,log,data}
chown -R mongod:mongod /mongodb
  1. 切换到普通用户,设置用户环境变量
su - mongod
echo export PATH=/usr/local/mongodb/bin:\$PATH >> ~/.bash_profile && source ~/.bash_profile
  1. 启动mongodb
mongod --dbpath=/mongodb/data --logpath=/mongodb/log/mongodb.log --port=27017 --logappend --fork
  1. 登录mongodb
mongo
  1. 创建配置文件
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.0.51,127.0.0.1
EOF

注意:配置文件采用YAML模式--YAML不支持制表符缩进:请改用空格。

--系统日志有关  
systemLog:
destination: file        
path: "/mongodb/log/mongodb.log"    --日志位置
logAppend: true                     --日志以追加模式记录

--数据存储有关   
storage:
journal:
enabled: true
dbPath: "/mongodb/data"            --数据路径的位置

-- 进程控制  
processManagement:
fork: true                         --后台守护进程
pidFilePath: <string>              --pid文件的位置,默认自动生成到data中

--网络配置有关   
net:            
bindIp: <ip>                       -- 监听地址,默认只允许本地登录
port: <port>                       -- 端口号,默认27017

-- 安全验证有关配置      
security:
authorization: enabled              --是否打开用户名密码验证

------------------以下是复制集与分片集群有关----------------------  
replication:
oplogSizeMB: <NUM>
replSetName: "<REPSETNAME>"
secondaryIndexPrefetch: "all"

sharding:
clusterRole: <string>
archiveMovedChunks: <boolean>

---for mongos only
replication:
localPingThresholdMs: <int>

sharding:
configDB: <string>
  1. 重启mongodb
mongod -f /mongodb/conf/mongo.conf --shutdown
mongod -f /mongodb/conf/mongo.conf 
  1. 使用systemd管理mongodb
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

基本操作

默认库

管理MongoDB有关的系统库

  • admin:系统预留库,MongoDB系统管理库
  • local:本地预留库,存储关键日志
  • config:MongoDB配置信息库
  • test:登录时默认位于的库,实际不存在(库表即用即创建)

命令种类

db 对象相关命令

db.[TAB][TAB]
db.help()
db.oldboy.[TAB][TAB]
db.oldboy.help()

rs 复制集(replication set)

rs.[TAB][TAB]
rs.help()

sh 分片集群(sharding cluster)

sh.[TAB][TAB]
sh.help()

对象操作

mongo        mysql
库    ----->  库
集合  ----->  表
文档  ----->  数据行

库操作

显示所有库物理空间大小
show databases/show dbs
显示当前所在库名
db
切换库
use test
删除库
db.dropDatabase() 
{ "dropped" : "test", "ok" : 1 }

集合操作

方法1:创建集合
> db.createCollection('a')
方法2:当插入一个文档的时候,一个集合就会自动创建,无所谓字段。
> db.stu.insert({id:1,name:"zhangsan",age:20,gender:"m"})
> db.stu.insert({id:101,a:1,b:2})
显示当前所在库名下所有集合名
> show tables/show collections
查看集合存储信息:集合中索引+数据压缩存储之后的大小
> db.log.totalSize()

文档操作

数据录入:
for(i=0;i<10000;i++){db.log.insert({"uid":i,"name":"mongodb","age":6,"date":new Date()})}
查询数据行数:
db.log.count()
全表查询:
db.log.find()
每页显示50条记录:
DBQuery.shellBatchSize=50; 
按照条件查询
db.log.find({uid:999})
以标准的json格式显示数据
db.log.find({uid:999}).pretty()
{
    "_id" : ObjectId("5cc516e60d13144c89dead33"),
    "uid" : 999,
    "name" : "mongodb",
    "age" : 6,
    "date" : ISODate("2019-04-28T02:58:46.109Z")
}
删除集合中所有记录
db.log.remove({})

用户及权限管理

注意

验证库: 建立用户时use到的库。在使用用户登录时,必须指定验证库才能登陆。

对于管理员用户,必须在admin下创建。
1. 建用户时,use到的库,就是此用户的验证库
2. 登录时,必须明确指定验证库才能登录
3. 通常,管理员用的验证库是admin,普通用户的验证库一般是需要管理的库
4. 如果直接登录到数据库,不进行use,默认的验证库是test,不是我们生产建议的.
5. 从3.6版本开始,不添加bindIp参数,默认不让远程登录,只能本地管理员登录。

用户创建语法

use admin 
db.createUser({
    user: "<name>",                 # 用户名
    pwd: "<cleartext password>",    # 密码
    roles: [                        # 权限
       { role: "<role>",            # 角色名:readWrite,read 
     db: "<database>" } | "<role>", # 作用对象
    ...
    ]
})

# 连接数据库验证:
mongo -u oldboy -p 123 10.0.0.53/oldboy

image-20201124102550330

用户管理

  1. 创建超级管理员:管理所有数据库(必须use admin再去创建)
use admin
db.createUser({
    user: "root",
    pwd: "1",
    roles: [ { role: "root", db: "admin" } ]
})
  1. 切换用户验证
use admin
db.auth('root','1')
  1. 修改配置文件,启用用户验证
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.0.51,127.0.0.1
security:
  authorization: enabled
EOF
  1. 重启
mongod -f /mongodb/conf/mongo.conf --shutdown 
mongod -f /mongodb/conf/mongo.conf 
  1. 登录验证
mongo -uroot -p1 admin
mongo -uroot -p1 10.0.0.51/admin
  1. 创建应用用户
use oldboy
db.createUser(
    {
        user: "app01",
        pwd: "app01",
        roles: [ { role: "readWrite" , db: "oldboy" } ]
    }
)
  1. 查看用户信息
use admin
db.system.users.find().pretty()
  1. 删除用户(root身份登录,use到验证库)
use oldboy
db.dropUser("app01")

注意事项

  1. 建用户要有验证库,管理员admin,普通用户是要管理的库

  2. 登录时,注意指定验证库

mongo -uapp01 -papp01 10.0.0.51:27017/oldboy
  1. 重点参数
net:
   port: 27017
   bindIp: 10.0.0.51,127.0.0.1
security:
  authorization: enabled

复制集RS(ReplicationSet)

基本原理

基本构成是1主2从的结构,自带互相监控投票机制(Raft(MongoDB)-> Paxos(mysql MGR 用的是变种)):如果发生主库宕机,复制集内部会进行投票选举,选择一个新的主库替代原有主库对外提供服务。同时复制集会自动通知客户端程序,主库已经发生切换了。应用就会连接到新的主库。

环境准备

多实例 端口 配置文件
实例1 28017 /mongodb/28017/conf/mongod.conf
实例2 28018 /mongodb/28018/conf/mongod.conf
实例3 28019 /mongodb/28019/conf/mongod.conf
实例3 28020 /mongodb/28020/conf/mongod.conf

1主2从,普通复制集

  1. 创建所需目录
su - mongod
mkdir -p /mongodb/{28017,28018,28019,28020}/{conf,data,log}
  1. 创建所需配置文件
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 's#28017#28018#g' /mongodb/28018/conf/mongod.conf -i
sed 's#28017#28019#g' /mongodb/28019/conf/mongod.conf -i
sed 's#28017#28020#g' /mongodb/28020/conf/mongod.conf -i
  1. 启动多实例
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
  1. 主库配置普通复制集

  2. 主库查询复制集状态

rs.status();

复制集管理操作

查看复制集状态

rs.status();    //查看整体复制集状态
rs.isMaster();  //查看当前是否是主节点
rs.conf();     //查看复制集配置信息

添加删除节点

rs.remove("ip:port"); // 删除一个节点
rs.add("ip:port");
rs.addArb("ip:port"); // 新增仲裁节点

1主1从1 arbiter

arbiter可以在初始时配置:

mongo -port 28017 admin
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) 

arbiter不能在线直接切换,必须先删除一个普通从节点,再添加一个arbiter。

$ mongo -port 28017 admin
my_repl:PRIMARY> rs.remove("10.0.0.51:28019");
{
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1606188212, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1606188212, 1)
}
my_repl:PRIMARY> rs.addArb("10.0.0.51:28019");
{
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1606188288, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1606188288, 1)
}
my_repl:PRIMARY> rs.conf();
... ...
		{
			"_id" : 2,
			"host" : "10.0.0.51:28019",
			"arbiterOnly" : true,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 0,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
... ...
my_repl:PRIMARY> rs.status();
... ...
"_id" : 2,
			"name" : "10.0.0.51:28019",
			"health" : 0,
			"state" : 8,
			"stateStr" : "(not reachable/healthy)",
			"uptime" : 0,
			"lastHeartbeat" : ISODate("2020-11-24T03:27:22.838Z"),
			"lastHeartbeatRecv" : ISODate("2020-11-24T03:24:50.248Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "Error connecting to 10.0.0.51:28019 :: caused by :: Connection refused",
... ...
my_repl:PRIMARY> exit
# arbiter节点状态不正常,重启节点
mongod -f /mongodb/conf/mongo.conf --shutdown 
mongod -f /mongodb/conf/mongo.conf 

特殊从节点

  • arbiter节点:主要负责选主过程中的投票,但是不存储任何数据,也不提供任何服务
  • hidden节点:隐藏节点,不参与选主,也不对外提供服务。
  • delay节点:延时节点,数据落后于主库一段时间,因为数据是延时的,所以不参与选主,也不对外提供服务,所以通常会配合hidden(隐藏)。一般情况下会将delay+hidden一起配置使用

配置延时节点(一般延时节点也配置hidden)

# 新增普通节点
rs.add("10.0.0.51:28020");
# 配置延时节点
cfg=rs.conf() 
cfg.members[3].priority=0
cfg.members[3].hidden=true
cfg.members[3].slaveDelay=120
rs.reconfig(cfg)    
# 删除普通节点
rs.remove("10.0.0.51:28018");
# 恢复普通节点
cfg=rs.conf() 
cfg.members[2].priority=1
cfg.members[2].hidden=false
cfg.members[2].slaveDelay=0
rs.reconfig(cfg)    
# 查看复制集配置信息
rs.conf(); 

注意:cfg.members[N]中的N,并非id的值,而是members数组的下标。


复制集其他操作

-- 复制集角色切换(不要人为随便操作),单位秒
my_repl:SECONDARY> rs.stepDown()
-- 锁定从,使其不会转变成主库,单位秒
my_repl:SECONDARY> rs.freeze(300)
-- 从节点设置可读(默认不可读写):
my_repl:SECONDARY> rs.slaveOk()
-- 主库监控主从延时
my_repl:PRIMARY> rs.printSlaveReplicationInfo()
source: 10.0.0.51:28020
	syncedTo: Tue Nov 24 2020 11:50:57 GMT+0800 (CST)
	0 secs (0 hrs) behind the primary
-- 设置从库不参与选主,不投票(偶数节点保证选举)
cfg=rs.conf() 
cfg.members[3].priority=0
cfg.members[2].votes=0
rs.reconfig(cfg) 

默认admin库同步,local库不同步

分片集群 Sharding Cluster

架构规划

image-20201124143901382

10个实例:38017-38026

  1. config节点:38018-38020
    (PSS)(1主两从,不支持arbiter)38018-38020(复制集名字configsvr)
  2. shard节点:
    sh1:38021-23 (PSA)(1主两从,其中一个节点为arbiter,复制集名字sh1)
    sh2:38024-26 (PSA)(1主两从,其中一个节点为arbiter,复制集名字sh2)
  3. mongos节点:38017

Shard节点配置

  1. 创建目录
su - mongod
mkdir -p /mongodb/{38021,38022,38023,38024,38025,38026}/{conf,data,log}

  1. 创建配置文件
  • 第一组复制集搭建:21-23(1主 1从 1Arb)
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

  • 第二组节点:24-26(1主1从1Arb)
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

  1. 启动所有节点
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

  1. 搭建两套复制集
mongo --port 38021
use  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)
exit

mongo --port 38024 
use 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)
exit


Config节点配置

  1. 创建目录
mkdir -p /mongodb/{38018,38019,38020}/{conf,data,log}

  1. 创建配置文件
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

  1. 启动所有节点
mongod -f /mongodb/38018/conf/mongodb.conf
mongod -f /mongodb/38019/conf/mongodb.conf
mongod -f /mongodb/38020/conf/mongodb.conf

  1. 配置复制集
mongo --port 38018
use  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)
exit

注意:mongodb 3.4之后,要求config server为replica set,但是不支持arbiter。


mongos节点配置

  1. 创建目录
mkdir -p /mongodb/38017/{conf,log}

  1. 创建配置文件
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
processManagement: 
  fork: true
EOF

  1. 启动
mongos -f /mongodb/38017/conf/mongos.conf 
 

分片集群添加分片节点

  1. 连接到mongs的admin数据库
mongo 10.0.0.51:38017/admin
  1. 添加分片
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"} )

  1. 列出分片
db.runCommand( { listshards : 1 } )
  1. 查看分片整体状态
sh.status();

RANGE自动分片配置

先将数据写入某一个分片,然后自动分片

  1. 连接到mongs的admin数据库
mongo 10.0.0.51:38017/admin
  1. 启用autoshard库分片功能
use admin
db.runCommand( { enablesharding : "autoshard" } )
  1. 给autoshard库下的vast表建立分片键(索引)
use autoshard
db.vast.ensureIndex( { id: 1 } )
  1. 启用分片键对集合分片
use admin
db.runCommand( { shardcollection : "autoshard.vast",key : {id: 1} } )
  1. 写入数据测试
use autoshard
for(i=1;i<1000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
db.vast.stats()
  1. 查看各切片行数

shard1:

mongo --port 38021
use autoshard
db.vast.count();
exit

shard2:

mongo --port 38024
use autoshard
db.vast.count();
exit


RANGE手动分片配置(4.0)

zone方式手工定制分片:事先确认范围

  1. 连接到mongs的admin数据库
mongo --port 38017 admin
  1. 给zonedb库下的vast表建立分片键(索引)
use zonedb
db.vast.ensureIndex( {order_id: 1 } )
  1. 启用zonedb库分片功能,启用分片键对集合分片
use admin
db.runCommand( { enablesharding : "zonedb" } )
sh.shardCollection("zonedb.vast", {order_id: 1});
  1. 定义标签
sh.addShardTag("shard1", "shard00")
sh.addShardTag("shard2", "shard01")
  1. 配置标签范围
sh.addTagRange(
"zonedb.vast", 
{  "order_id" : MinKey },
{  "order_id" : 500 },"shard00" )

sh.addTagRange( 
"zonedb.vast",
{"order_id" : 501 },
{"order_id" : MaxKey},"shard01" )
  1. 写入数据测试
use zonedb
for(i=1;i<10000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
db.vast.stats()
  1. 查看各切片行数

shard1:

mongo --port 38021
use zonedb
db.vast.count();
exit

shard2:

mongo --port 38024
use zonedb
db.vast.count();
exit


Hash分片配置

  1. 连接到mongs的admin数据库
mongo --port 38017 admin
  1. 给oldboy库下的vast表建立hash索引
use oldboy
db.vast.ensureIndex( { id: "hashed" } )
  1. 启用oldboy库分片功能,启用分片键对集合分片
use admin
db.runCommand( { enablesharding : "oldboy" } )
sh.shardCollection( "oldboy.vast", { id: "hashed" } )
  1. 写入数据测试
use oldboy
for(i=1;i<10000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
  1. 查看各切片行数

shard1:

mongo --port 38021
use oldboy
db.vast.count();
exit

shard2:

mongo --port 38024
use oldboy
db.vast.count();
exit


分片集群的查询及管理

  • 判断是否Shard集群
db.runCommand({ isdbgrid : 1})
  • 列出所有分片信息
db.runCommand({ listshards : 1})
  • 列出开启分片功能的库
use config
db.databases.find( { "partitioned": true } )
// 列出所有数据库分片情况
db.databases.find()
  • 查看分片碎片
db.vast.getShardDistribution()
  • 查看分片的片键
db.collections.find().pretty()
  • 查看分片的详细信息
sh.status()
  • 删除分片节点(谨慎)
// 确认blance是否在工作
sh.getBalancerState()
// 删除shard2节点(谨慎)
db.runCommand( { removeShard: "shard2" } )

注意:删除操作一定会立即触发blancer。


balancer操作

balancer是mongos的一个重要功能:自动巡查所有shard节点上的chunk的情况,自动做chunk迁移。

什么时候工作?

  1. 自动运行,会检测系统,不繁忙的时候做迁移
  2. 在做节点删除的时候,立即开始迁移工作
  3. 只能在预设的时间窗口内运行

关闭和开启blancer(备份的时候)

sh.stopBalancer()
sh.startBalancer()

自定义:自动平衡运行的时间段

必须配置,避开繁忙和备份的时候。参考

// connect to mongos
use config
sh.setBalancerState( true )
db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "3:00", stop : "5:00" } } }, true )

验证

sh.getBalancerWindow()
sh.status()

关于集合的balancer(了解)

// 关闭某个集合的balance
sh.disableBalancing("students.grades")
// 打开某个集合的balancer
sh.enableBalancing("students.grades")
// 确定某个集合的balance是开启或者关闭
db.getSiblingDB("config").collections.findOne({_id : "students.grades"}).noBalance;

备份恢复

备份恢复工具:

  • mongoexport/mongoimport:json csv
    • 异构平台迁移:mysql <---> mongodb
    • 同平台,跨大版本:mongodb 2 ----> mongodb 3
  • mongodump/mongorestore
    • 日常备份恢复时使用.

导出工具mongoexport

  • 参数说明:
-h: 指明数据库宿主机的IP
-u: 指明数据库的用户名
-p: 指明数据库的密码
-d: 指明数据库的名字
-c: 指明collection的名字
-f: 指明要导出那些列
-o: 指明到要导出的文件名
-q: 指明导出数据的过滤条件
--authenticationDatabase admin
--type:指明要导出的格式(默认json)
  • 单表备份至json格式
mongoexport -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/log.json
  • 单表备份至csv格式
mongoexport -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy -c log --type=csv -f uid,name,age,date -o /mongodb/log.csv

导入工具mongoimport

  • 参数说明:
-h: 指明数据库宿主机的IP
-u: 指明数据库的用户名
-p: 指明数据库的密码
-d: 指明数据库的名字
-c: 指明collection的名字
-f: 指明要导入那些列
-j, --numInsertionWorkers=<number>  要同时运行的插入操作数 (defaults to 1)
--headerline: 指明第一行是列名,不需要导入。
  • 恢复json格式表数据到log1
mongoimport -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy -c log1 /mongodb/log.json
  • 恢复csv格式的文件到log2

    • csv格式的文件头行,有列名字
    mongoimport -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy -c log2 --type=csv --headerline --file /mongodb/log.csv
    
    • csv格式的文件头行,没有列名字
    mongoimport -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy -c log3 --type=csv -f id,name,age,date --file /mongodb/log.csv
    

异构平台迁移案例

mysql -----> mongodb


① 导出mysql的world数据库下city表,导入到mongodb

  1. mysql开启安全路径
vim /etc/my.cnf   --->添加以下配置
secure-file-priv=/tmp

--重启数据库生效
/etc/init.d/mysqld restart
  1. 导出mysql的city表数据
source /root/world.sql
select * from world.city into outfile '/tmp/city.csv' fields terminated by ',';
  1. 处理备份文件
# 查看city表字段
mysql> desc world.city;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int      | NO   | PRI | NULL    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   | MUL |         |                |
| District    | char(20) | NO   |     |         |                |
| Population  | int      | NO   |     | 0       |                |
+-------------+----------+------+-----+---------+----------------+
# 在备份文件第一行添加列名信息
vim /tmp/city.csv   
ID,Name,CountryCode,District,Population
  1. 导入mongodb
mongoimport -uroot -p1 --port 27017 --authenticationDatabase admin -d world -c city --type=csv -f ID,Name,CountryCode,District,Population --file  /tmp/city1.csv
  1. mongodb中查看验证结果
use world
db.city.find({CountryCode:"CHN"});

② world共100张表,全部迁移到mongodb

导出:

-- 查看语句
select table_name,group_concat(column_name) from columns where table_schema='world' group by table_name;
-- 导出语句
select * from world.city into outfile '/tmp/world_city.csv' fields terminated by ',';
-- 构建批量导出语句
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';

导入:

提示,使用infomation_schema.columns + information_schema.tables


# mysql导出csv:
select * from test_info   
into outfile '/tmp/test.csv'   
fields terminated by ','    ------字段间以,号分隔
optionally enclosed by '"'   ------字段用"号括起
escaped by '"'            ------字段中使用的转义符为"
lines terminated by '\r\n';  ------行以\r\n结束

# mysql导入csv:
load data infile '/tmp/test.csv'   
into table test_info    
fields terminated by ','  
optionally enclosed by '"' 
escaped by '"'   
lines terminated by '\r\n'; 

导出工具mongodump

​ mongodump能够在Mongodb运行时进行备份,它的工作原理是对运行的Mongodb做查询,然后将所有查到的文档写入磁盘。
​ 但是使用mongodump产生的备份不一定是数据库的实时快照,如果我们在备份时对数据库进行了写入操作,则备份出来的文件可能不完全和Mongodb实时数据相等。另外在备份时可能会对其它客户端性能产生不利的影响。

  • 参数说明:
-h: 指明数据库宿主机的IP
-u: 指明数据库的用户名
-p: 指明数据库的密码
-d: 指明数据库的名字
-c: 指明collection的名字
-o: 指明到要导出的文件名
-q: 指明导出数据的过滤条件
-j, --numParallelCollections=要并行转储的集合数 (4 by default)
--oplog: 备份的同时备份oplog
  • 全库备份
mkdir /mongodb/backup
mongodump -uroot -p1 --port 27017 --authenticationDatabase admin -o /mongodb/backup
  • 备份world库
mongodump -uroot -p1 --port 27017 --authenticationDatabase admin -d world -o /mongodb/backup/
  • 备份oldboy库下的log集合
mongodump -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/backup/
  • 压缩备份
mongodump -uroot -p1 --port 27017 --authenticationDatabase admin -o /mongodb/backup/ --gzip
mongodump -uroot -p1 --port 27017 --authenticationDatabase admin -d oldguo -o /mongodb/backup/ --gzip
mongodump -uroot -p1 --port 27017 --authenticationDatabase admin -d app -c vast -o /mongodb/backup/ --gzip

导入工具mongorestore

  • 恢复world库
mongorestore -uroot -p1 --port 27017 --authenticationDatabase admin -d world1  /mongodb/backup/world
  • 恢复oldguo库下的t1集合
mongorestore -uroot -p1 --port 27017 --authenticationDatabase admin -d world -c t1 --gzip /mongodb/backup/oldboy/log1.json.gz
  • drop表示恢复的时候把之前的集合drop掉(危险)
mongorestore -uroot -p1 --port 27017 --authenticationDatabase admin -d oldboy --drop /mongodb/backup/oldboy

mongodump和mongorestore高级应用(--oplog)

介绍

oplog是replica set或者master/slave模式专用,分片使用oplog获取时间点快照。

replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改),位于local库的db.oplog.rs。其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。

当空间用完时,新记录自动覆盖最老的记录。其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。

准备:启动复制集,连接数据库

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
mongo --port 28017 admin

查看本地所有oplog详情

use local
db.oplog.rs.find().pretty()

查询指定oplog详情

my_repl:PRIMARY> db.oplog.rs.find({"ts" : Timestamp(1606187724, 2)}).pretty()
{
	"ts" : Timestamp(1606187724, 2),
	"t" : NumberLong(1),
	"h" : NumberLong(0),
	"v" : 2,
	"op" : "n",
	"ns" : "",
	"wall" : ISODate("2020-11-24T03:15:24.530Z"),
	"o" : {
		"msg" : "Creating indexes. Coll: config.system.sessions"
	}
}

"op" : 可选值
"n": info
"i": insert
"u": update
"d": remove
"c": db cmd

查询当前oplog时间窗口预计值

my_repl:PRIMARY> rs.printReplicationInfo()
configured oplog size:   2048MB <--集合大小
log length start to end: 24595secs (6.83hrs) <--预计窗口覆盖时间
oplog first event time:  Tue Nov 24 2020 11:13:06 GMT+0800 (CST)
oplog last event time:   Tue Nov 24 2020 18:03:01 GMT+0800 (CST)
now:                     Tue Nov 24 2020 18:03:07 GMT+0800 (CST)

oplog 配合mongodump实现热备

--oplog 功能:在备份时,将备份过程中产生的日志也进行备份,文件必须存放在/mongodb/backup下,自动命名为oplog.bson

  1. 准备测试数据
mongo --port 28017
use oldboy
for(i=1;i<10000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
exit

  1. 备份
mongodump --port 28017 --oplog -o /mongodb/backup
  1. 在备份过程中,模拟数据插入
mongo --port 28017
use oldboy
for(var i = 1 ;i < 100; i++) {
    db.foo.insert({a:i});
}
db.oplog.rs.find({"op":"i"}).pretty()
  1. 恢复
mongorestore --port 28017 --oplogReplay /mongodb/backup

oplog 配合全备故障恢复

背景:每天0点全备,oplog恢复窗口为48小时。某天,上午10点 world.city 业务表被误删除。
恢复思路:
0、停应用
2、找测试库
3、恢复昨天晚上全备
4、截取全备之后到world.city误删除时间点的oplog,并恢复到测试库
5、将误删除表导出,恢复到生产库


  1. 模拟原始数据
mongo --port 28017
use wo
for(var i = 1 ;i < 20; i++) {
    db.ci.insert({a: i});
}
exit

  1. 全备数据库
rm -rf /mongodb/backup/*
mongodump --port 28017 --oplog -o /mongodb/backup

  1. 模拟业务数据
mongo --port 28017
use wo
db.ci1.insert({id:1})
db.ci2.insert({id:2})

  1. 上午10点:删除wo库下的ci表
db.ci.drop()
show tables;
exit

  1. 备份现有的oplog.rs表
mongodump --port 28017 -d local -c oplog.rs -o /mongodb/

  1. 截取oplog并恢复到drop之前的位置
# 在数据库中查询误删操作
mongo --port 28017
use local
db.oplog.rs.find({op:"c"}).pretty();
... ...
{
	"ts" : Timestamp(1606213390, 1),
	"t" : NumberLong(1),
	"h" : NumberLong(0),
	"v" : 2,
	"op" : "c",
	"ns" : "wo.$cmd",
	"ui" : UUID("b16808bc-4ac0-4b8e-885f-92a0d29f1e16"),
	"o2" : {
		"numRecords" : 19
	},
	"wall" : ISODate("2020-11-24T10:23:10.698Z"),
	"o" : {
		"drop" : "ci"
	}
}
... ...
# 获取到误删除时间点位置oplog:先删表,再删库
"ts" : Timestamp(1606213390, 1)
  1. 使用全部 oplog.rs.bson 覆盖全备的 oplog.bson
\cp /mongodb/local/oplog.rs.bson /mongodb/backup/oplog.bson
  1. 恢复备份时应用oplog
mongorestore --port 28017  --oplogReplay --oplogLimit "1606213390:1"  --drop /mongodb/backup/
  1. 登录数据库查看:误删的表已经恢复
mongo --port 28017
use wo
show tables
exit


分片集群的备份思路(了解)

1、你要备份什么?
config server
shard 节点

单独进行备份
2、备份有什么困难和问题
(1)chunk迁移的问题
    人为控制在备份的时候,避开迁移的时间窗口
(2)shard节点之间的数据不在同一时间点。
    选业务量较少的时候       
        
Ops Manager 
posted @ 2021-01-04 11:15  原因与结果  阅读(98)  评论(0编辑  收藏  举报