MongoDB 分片集群

一. 数据库管理系统

1.1 什么是数据

​ 数据(英语:data),是指未经过处理的原始记录。

  一般而言,数据缺乏组织及分类,无法明确的表达事物代表的意义,它可能是一堆的杂志、一大叠的报纸、数种的开会记录或是整本病人的病历纪录。数据描述事物的符号记录,是可定义为意义的实体,涉及事物的存在形式。是关于事件之一组离散且客观的事实描述,是构成讯息和知识的原始材料。

1.2 什么是数据库管理系统?

​ 数据库管理系统(英语:database management system,缩写:DBMS) 是一种针对对象数据库,为管理数据库而设计的大型电脑软件管理系统。
  具有代表性的数据管理系统有:Oracle、Microsoft SQL Server、Access、MySQL及PostgreSQL等。通常数据库管理师会使用数据库管理系统来创建数据库系统。
  现代DBMS使用不同的数据库模型追踪实体、属性和关系。在个人电脑、大型计算机和主机上应用最广泛的数据库管理系统是关系型DBMS(relational DBMS)。在关系型数据模型中,用二维表格表示数据库中的数据。这些表格称为关系。
  数据库管理系统主要分为俩大类:RDBMS、NOSQL

1.3 NoSQL 是什么?

1.3.1 NoSQL 简介

​ NoSQL是对不同于传统的关系数据库的数据库管理系统的统称。
  两者存在许多显著的不同点,其中最重要的是NoSQL不使用SQL作为查询语言。其数据存储可以不需要固定的表格模式,也经常会避免使用SQL的JOIN操作,一般有水平可扩展性的特征。

1.3.2 NoSQL数据库四大家族

NoSQL中的四大家族主要是:列存储、键值、图像存储、文档存储,其类型产品主要有以下这些。

1.3.3 NoSQL的优势

高可扩展性、分布式计算、没有复杂的关系、低成本、架构灵活、半结构化数据

1.3.4 NoSQL与RDBMS对比

NoSQL RDBMS
代表着不仅仅是 SQL 高度组织化结构化数据
没有声明性查询语言 结构化查询语言(SQL) (SQL)
没有预定义的模式 数据和关系都存储在单独的表中
键 – 值对存储,列存储,文档存储,图形数据库 数据操纵语言,数据定义语言
最终一致性,而非 ACID 属性 严格的一致性
非结构化和不可预知的数据 基础事务
CAP 定理
高性能,高可用性和可伸缩性

二. MongoDB

2.1 简介

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库(nosql)之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

2.2 优势

MongoDB目前3大核心优势:『灵活模式』+ 『高可用性』 + 『可扩展性』,通过json文档来实现灵活模式,通过副本集来保证高可用,通过Sharded cluster来保证可扩展性。

2.3 关系型数据库与mongodb对比

在传统的关系型数据库中,存储方式是以表的形式存放,而在MongoDB中,以文档的形式存在。
数据库中的对应关系,及存储形式的说明:

2.4 MongoDB适用场景

网站数据、缓存等大尺寸、低价值的数据,在高伸缩性的场景,用于对象及JSON数据的存储。

2.5 MongoDB 慎用场景

慎用场景 原因
PB 数据持久存储大数据分析数据湖 Hadoop、Spark提供更多分析运算功能和工具,并行计算能力更强MongoDB + Hadoop/Spark
搜索场景:文档有几十个字段,需要按照任意字段搜索并排序限制等 不建索引查询太慢,索引太多影响写入及更新操作
ERP、CRM或者类似复杂应用,几十上百个对象互相关联 关联支持较弱,事务较弱
需要参与远程事务,或者需要跨表,跨文档原子性更新的 MongoDB 事务支持仅限于本机的单文档事务
100% 写可用:任何时间写入不能停 MongoDB换主节点时候会有短暂的不可写设计所限

2.6 架构

2.6.1 Master-Slave 模式

Master-Slave 架构一般用于备份或者做读写分离,一般是一主一从设计和一主多从设计。
Master ( 主 ):可读可写,当数据有修改的时候,会将 Oplog 同步到所有连接的Salve 上去。
Slave ( 从 ):只读,所有的 Slave 从 Master 同步数据,从节点与从节点之间不感知。
特点:
- Master-Slave 只区分两种角色:Master 节点,Slave 节点;
- Master-Slave 的角色是静态配置的,不能自动切换角色,必须人为指定;
- 用户只能写 Master 节点,Slave 节点只能从 Master 拉数据;
- 还有一个关键点:Slave 节点只和 Master 通信,Slave 之间相互不感知,这种好处对于 Master 来说优点是非常轻量,缺点是:系统明显存在单点,那么多 Slave 只能从 Master 拉数据,而无法提供自己的判断;
总结:读写分离的结构只适合特定场景,对于必须需要数据强一致的场景是不合适这种读写分离的。

2.6.2 Replica Set 副本集模式

Replica Set 是 mongod 的实例集合,包含三类节点角色:
Primary( 主节点 ):只有 Primary 是可读可写的,Primary 接收所有的写请求,然后把数据同步到所有 Secondary 。一个 Replica Set 只有一个 Primary 节点,当 Primary 挂掉后,其他 Secondary 或者 Arbiter 节点会重新选举出来一个 Primary 节点,这样就又可以提供服务了
Secondary( 副本节点 ):数据副本节点,当主节点挂掉的时候,参与选主。
Arbiter( 仲裁者 ):不存数据,不会被选为主,只进行选主投票。使用 Arbiter 可以减轻在减少数据的冗余备份,又能提供高可用的能力。
特点:

  • 数据多副本,在故障的时候,可以使用完的副本恢复服务。注意:这里是故障自动恢复
  • 读写分离,读的请求分流到副本上,减轻主(Primary)的读压力;
  • 节点直接互有心跳,可以感知集群的整体状态;

2.6.3 Sharding 模式

当MongoDB复制集遇到下面的业务场景时,你就需要考虑使用Sharded cluster
- 存储容量需求超出单机磁盘容量
- 活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能
- 写IOPS超出单个MongoDB节点的写服务能力

Sharding 模式下按照层次划分可以分为 3 个大模块:

  • 代理层:mongos

提供对外应用访问,所有操作均通过mongos执行。向上对接 Client ,收到 Client 写请求的时候,按照特定算法均衡散列到某一个 Shard 集群,然后数据就写到 Shard 集群了。收到读请求的时候,定位找到这个要读的对象在哪个 Shard 上,就把请求转发到这个 Shard 上,就能读到数据了。

  • 数据层:Shard 集群

存储应用数据记录,其实数据层就是由一个个 Replica Set 集群组成,单个 Replica Set 是有极限的,怎么办?那就搞多个 Replica Set ,这样的一个 Replica Set 我们就叫做 Shard

  • 配置中心:副本集群(mongod)

配置中心存储集群所有节点、分片数据路由信息。配置中心也是一个 Replica Set 集群,数据也是多副本的。

数据分布策略

Sharded cluster支持将单个集合的数据分散存储在多个shard上,用户可以指定根据集合内文档的某个字段即shard key来分布数据,我们把 Sharding Key 作为输入,按照特点的Sharding Strategy(分片策略)计算出一个值,值的集合形成了一个值域,我们按照固定步长去切分这个值域,每一个片叫做 Chunk ,每个 Chunk 出生的时候就和某个 Shard 绑定起来,这个绑定关系存储在配置中心里。

目前主要支持2种数据分布的策略,范围分片(Range based sharding)或hash分片(Hash based sharding)。

范围分片(Range based sharding):能很好的满足『范围查询』的需求,比如想查询x的值在[-30, 10]之间的所有文档,这时mongos直接能将请求路由到Chunk2,就能查询出所有符合条件的文档。

范围分片的缺点在于,容易导致热点,如果shardkey有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个chunk,无法扩展写的能力,比如使用_id作为shard key,而MongoDB自动生成的id高位是时间戳,是持续递增的。

hash分片(Hash based sharding):

Hash分片是根据用户的shard key计算hash值(64bit整型),根据hash值按照『范围分片』的策略将文档分布到不同的chunk。

Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。

上述2种分片策略都不能解决的问题包括

  1. shard key 取值范围太小(low cardinality),比如将数据中心作为 shard key,而数据中心通常不会很多,分片的效果肯定不好。
  2. shard key 某个值的文档特别多,这样导致单个 chunk 特别大(及 jumbo chunk),会影响chunk 迁移及负载均衡。
  3. 根据非 shard key 进行查询、更新操作都会变成 scatter-gather 查询,影响效率。

好的 shard key 应该拥有如下特性:

  • key 分布足够离散 (sufficient cardinality)
  • 写请求均匀分布 (evenly distributed write)
  • 尽量避免 scatter-gather 查询 (targeted read)

举个例子,某物联网应用使用 MongoDB Sharded cluster 存储『海量设备』的『工作日志』,假设设备数量在百万级别,设备每10s向 MongoDB汇报一次日志数据,日志包含deviceId,timestamp 信息,应用最常见的查询请求是『查询某个设备某个时间内的日志信息』。

  • 方案1: 时间戳作为 shard key,范围分片
    • Bad
    • 新的写入都是连续的时间戳,都会请求到同一个 shard,写分布不均
    • 根据 deviceId 的查询会分散到所有 shard 上查询,效率低
  • 方案2: 时间戳作为 shard key,hash 分片
    • Bad
    • 写入能均分到多个 shard
    • 根据 deviceId 的查询会分散到所有 shard 上查询,效率低
  • 方案3:deviceId 作为 shardKey,hash分片(如果 id 没有明显的规则,范围分片也一样)
    • Bad
    • 写入能均分到多个 shard
    • 同一个 deviceId 对应的数据无法进一步细分,只能分散到同一个 chunk,会造成 jumbo chunk
    • 根据 deviceId的查询只请求到单个 shard,不足的时,请求路由到单个 shard 后,根据时间戳的范围查询需要全表扫描并排序
  • 方案4:(deviceId, 时间戳)组合起来作为 shardKey,范围分片(Better)
    • Good
    • 写入能均分到多个 shard
    • 同一个 deviceId 的数据能根据时间戳进一步分散到多个chunk
    • 根据 deviceId 查询时间范围的数据,能直接利用(deviceId, 时间戳)复合索引来完成。

三. 部署Sharded Cluster

3.1 集群规划

端口:
mongos:20000
config:21000
shard1:27001
shard2:27002
shard3:27003

3.2 下载

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.8.tgz;
tar xzvf mongodb-linux-x86_64-rhel70-4.4.8.tgz;
mv mongodb-linux-x86_64-rhel70-4.4.8 /opt/mongodb;

3.3创建相应目录

mkdir -p /data/mongodb/{config,shard1,shard2,shard3}/{data,logs};
mkdir -p /data/mongodb/mongos/logs;
mkdir -p /data/mongodb/{conf,keyfile};

3.4 配置环境变量

tee -a /etc/profile <<- 'EOF'
#MongoDB
export MONGODB_HOME=/opt/mongodb
export PATH=MONGODB_HOME/bin:PATH
EOF

立即生效

source /etc/profile;

Transparent Huge Pages (THP),通过使用更大的内存页面,可以减少具有大量内存的机器上的缓冲区(TLB)查找的开销。但是,数据库工作负载通常对THP表现不佳,因为它们往往具有稀疏而不是连续的内存访问模式。在Linux机器上禁用THP,以确保MongoDB的最佳性能。

cat >> /etc/rc.local <<'EOF'
#关闭Transparent Huge Pages(THP)
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

3.5 创建密钥文件

openssl rand -base64 756 > mongo.key;
mv mongo.key /data/mongodb/keyfile;
chmod 400 /data/mongodb/keyfile/mongo.key;

3.6 config server配置服务器

tee -a /data/mongodb/conf/config.conf <<-'EOF'
systemLog:
    destination: file
    logAppend: true
    path: /data/mongodb/config/logs/config.log
    logRotate: rename
storage:
    dbPath: /data/mongodb/config/data
    journal:
        enabled: true
        commitIntervalMs: 100
    directoryPerDB: false
    syncPeriodSecs: 60
    engine: wiredTiger
    #缓存设置大小(RAM-1)X0.5,最少2
    wiredTiger:
        engineConfig:
            cacheSizeGB: 3.5
            journalCompressor: snappy
        indexConfig:
            prefixCompression: true
processManagement:
    fork: true
    pidFilePath: /data/mongodb/config/logs/configsrv.pid

net:
    port: 21000
    bindIp: 0.0.0.0
    maxIncomingConnections: 10000
    wireObjectCheck: true
    ipv6: false
#security:
#   authorization: enabled
#   keyFile: /data/mongodb/keyfile/mongo.key

operationProfiling:
    slowOpThresholdMs: 100
    mode: slowOp
replication:
    oplogSizeMB: 2048
    replSetName: configs
sharding:
    clusterRole: configsvr
    archiveMovedChunks: true
EOF

3.7 配置分片

分片一

tee -a /data/mongodb/conf/shard1.conf <<-'EOF'
systemLog:
    destination: file
    logAppend: true
    path: /data/mongodb/shard1/logs/shard1.log
    logRotate: rename
storage:
    dbPath: /data/mongodb/shard1/data
    journal:
        enabled: true
        commitIntervalMs: 100
    directoryPerDB: false
    syncPeriodSecs: 60
    engine: wiredTiger
    wiredTiger:
        engineConfig:
            cacheSizeGB: 3.5
            journalCompressor: snappy
        indexConfig:
            prefixCompression: true
processManagement:
    fork: true
    pidFilePath: /data/mongodb/shard1/logs/shard1.pid

net:
    port: 27001
    bindIp: 0.0.0.0
    maxIncomingConnections: 10000
    wireObjectCheck: true
    ipv6: false
#security:
#   authorization: enabled
#   keyFile: /data/mongodb/keyfile/mongo.key

operationProfiling:
    slowOpThresholdMs: 100
    mode: slowOp
replication:
    oplogSizeMB: 2048
    replSetName: shard1
sharding:
    clusterRole: shardsvr
    archiveMovedChunks: true
EOF

分片二

tee -a /data/mongodb/conf/shard2.conf <<-'EOF'
systemLog:
    destination: file
    logAppend: true
    path: /data/mongodb/shard2/logs/shard2.log
    logRotate: rename
storage:
    dbPath: /data/mongodb/shard2/data
    journal:
        enabled: true
        commitIntervalMs: 100
    directoryPerDB: false
    syncPeriodSecs: 60
    engine: wiredTiger
    wiredTiger:
        engineConfig:
            cacheSizeGB: 3.5
            journalCompressor: snappy
        indexConfig:
            prefixCompression: true
processManagement:
    fork: true
    pidFilePath: /data/mongodb/shard2/logs/shard2.pid

net:
    port: 27002
    bindIp: 0.0.0.0
    maxIncomingConnections: 10000
    wireObjectCheck: true
    ipv6: false
#security:
#   authorization: enabled
#   keyFile: /data/mongodb/keyfile/mongo.key

operationProfiling:
    slowOpThresholdMs: 100
    mode: slowOp
replication:
    oplogSizeMB: 2048
    replSetName: shard2
sharding:
    clusterRole: shardsvr
    archiveMovedChunks: true
EOF

分片三

tee -a /data/mongodb/conf/shard3.conf <<-'EOF'
systemLog:
    destination: file
    logAppend: true
    path: /data/mongodb/shard3/logs/shard3.log
    logRotate: rename
storage:
    dbPath: /data/mongodb/shard3/data
    journal:
        enabled: true
        commitIntervalMs: 100
    directoryPerDB: false
    syncPeriodSecs: 60
    engine: wiredTiger
    wiredTiger:
        engineConfig:
            cacheSizeGB: 3.5
            journalCompressor: snappy
        indexConfig:
            prefixCompression: true
processManagement:
    fork: true
    pidFilePath: /data/mongodb/shard3/logs/shard3.pid

net:
    port: 27003
    bindIp: 0.0.0.0
    maxIncomingConnections: 10000
    wireObjectCheck: true
    ipv6: false
#security:
#   authorization: enabled
#   keyFile: /data/mongodb/keyfile/mongo.key

operationProfiling:
    slowOpThresholdMs: 100
    mode: slowOp
replication:
    oplogSizeMB: 2048
    replSetName: shard3
sharding:
    clusterRole: shardsvr
    archiveMovedChunks: true
EOF

3.8 配置路由服务器 mongos

tee -a /data/mongodb/conf/mongos.conf <<-'EOF'
systemLog:
    destination: file
    logAppend: true
    path: /data/mongodb/mongos/logs/mongos.log
processManagement:
    fork: true
    pidFilePath: /data/mongodb/mongos/logs/mongos.pid

net:
    port: 20000
    bindIp: 0.0.0.0
    maxIncomingConnections: 10000
#security:
#   keyFile: /data/mongodb/keyfile/mongo.key
sharding:
   configDB: configs/192.168.121.91:21000,192.168.121.92:21000,192.168.121.93:21000
EOF

传输到另外两台服务器上

scp -r /opt/mongodb root@ip:/opt
scp  -r /data/mongodb root@ip:/datascp  -r /data/mongodb root@ip:/data

3.9 启动config server并初始化

启动三台服务器的config server

mongod -f /data/mongodb/conf/config.conf

配置副本集,登录任意一台服务器即可

mongo 192.168.121.91:21000
config = {
    _id : "configs",
    members : [
        {_id : 0, host : "192.168.121.91:21000" },
        {_id : 1, host : "192.168.121.92:21000" },
        {_id : 2, host : "192.168.121.93:21000" }
     ]
}

初始化副本集

rs.initiate(config)

查看分区状态

rs.status();

3.10 启动分片服务,配置副本集

分片一

mongod -f /data/mongodb/conf/shard1.conf;

配置副本集,登录主或副节点即可,仲裁节点上执行会报错

mongo --port 27001
use admin;
config = {
   _id : "shard1",
    members : [
        {_id : 0, host : "192.168.121.91:27001",priority:10},
        {_id : 1, host : "192.168.121.92:27001",priority:8},
        {_id : 2, host : "192.168.121.93:27001", arbiterOnly: true}
    ]
}

初始化副本集

rs.initiate(config)

查看分区状态

rs.status();

分片二

mongod -f /data/mongodb/conf/shard2.conf;

初始化

mongo --host 192.168.121.92 --port 27002
use admin;
config = {
   _id : "shard2",
    members : [
        {_id : 0, host : "192.168.121.91:27002",arbiterOnly: true},
        {_id : 1, host : "192.168.121.92:27002",priority:10},
        {_id : 2, host : "192.168.121.93:27002", priority:8}
    ]
}

初始化副本集

rs.initiate(config)

查看分区状态

rs.status();

分片三

mongod -f /data/mongodb/conf/shard3.conf;
mongo 192.168.121.93:27003
use admin;
config = {
   _id : "shard3",
    members : [
        {_id : 0, host : "192.168.121.91:27003",priority:8},
        {_id : 1, host : "192.168.121.92:27003",arbiterOnly: true},
        {_id : 2, host : "192.168.121.93:27003",priority:10}
    ]
}

初始化副本集

rs.initiate(config)

查看分区状态

rs.status();

3.11 启动mongos并初始化

启动三台服务器的mongos

mongos -f /data/mongodb/conf/mongos.conf;

初始化

mongo --port 20000
use admin;
#串联路由服务器与分配副本集
sh.addShard("shard1/192.168.121.91:27001,192.168.121.92:27001,192.168.121.93:27001")
sh.addShard("shard2/192.168.121.91:27002,192.168.121.92:27002,192.168.121.93:27002")
sh.addShard("shard3/192.168.121.91:27003,192.168.121.92:27003,192.168.121.93:27003")
#查看集群状态
sh.status()

列出所有分片信息

db.runCommand({ listshards : 1})

指定数据库分片生效

db.runCommand( { enablesharding :"history"});
db.runCommand( { shardcollection : "数据库名称.集合名称",key : {分片键: 1} } )
db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}})

3.12 创建用户

db.createUser({
    user:'root',pwd:'LNEi9SSGxpE90bUz',
    roles:[
        {role:'clusterAdmin',db:'admin'},
        {role:'userAdminAnyDatabase',db:'admin'},
        {role:'dbAdminAnyDatabase',db:'admin'},
        {role:'readWriteAnyDatabase',db:'admin'}
]})

添加普通用户

use demo;
db.createUser({user:'demo',pwd:'LbT6cXep2fk',roles:[{role:'readWrite',db:'demo'}]});
use history;
db.createUser({user:'history',pwd:'history',roles:[{role:'readWrite',db:'history'}]});

启动认证,去掉之前的注释即可

config.conf  shard1.conf  shard2.conf  shard3.conf
security:
   authorization: enabled
   keyFile: /data/mongodb/keyfile/mongo.key
mongos.conf
security:
   keyFile: /data/mongodb/keyfile/mongo.key

3.13 服务启动脚本

tee -a /opt/mongodb/start.sh <<-'EOF'
#!/bin/bash
mongod -f /data/mongodb/conf/config.conf;
mongod -f /data/mongodb/conf/shard1.conf;
mongod -f /data/mongodb/conf/shard2.conf;
mongod -f /data/mongodb/conf/shard3.conf;
mongos -f /data/mongodb/conf/mongos.conf;
ps -efl | grep mongo;
netstat -tnlp;
EOF
tee -a /opt/mongodb/stop.sh <<-'EOF'
#!/bin/bash
ps -ef | grep mongo| grep -v grep | awk '{print $2}'|xargs kill -4
EOF

mongod进程收到SIGINT信号或者SIGTERM信号,会做一些处理
- 关闭所有打开的连接
- 将内存数据强制刷新到磁盘
- 当前的操作执行完毕
- 安全停止
切忌kill -9

数据库直接关闭,数据丢失,数据文件损失,修复数据库
kill -2 PID
原理:-2表示向mongod进程发送SIGINT信号。

kill -4 PID
原理:-4表示向mognod进程发送SIGTERM信号。

3.14 设置数据平衡窗口

在MongoDB中,balancer是一个后台进程,负责chunk的迁移,从而均衡各个shard server的负载,系统初始1个chunk,chunk size默认值64M,生产库上选择适合业务的chunk size是最好的。ongoDB会自动拆分和迁移chunks。

确认balance开启中

use config;
sh.getBalancerState()

如未开启,执行命令

sh.setBalancerState( true )

修改balance窗口时间

db.settings.update(
   { _id: "balancer" },
   { set: { activeWindow : { start : "<start-time>", stop : "<stop-time>" } } },
   { upsert: true }
)
#设置凌晨1点到4点
db.settings.update({ _id : "balancer" }, {set : { activeWindow : { start : "01:00", stop : "4:00" } } }, true )
#查看设置
db.settings.find();

删除balance窗口

use config
db.settings.update({ _id : "balancer" }, { $unset : { activeWindow : true } })

关闭balance

sh.stopBalancer();
#重新打开
sh.setBalancerState(true);
#查看banlancer是否正在工作
sh.isBalancerRunning()

四. Mongodb操作命令

Mongodb中关键字种类:

db(数据库实例级别)
         db本身
             db.connection 数据库下的集合信息
                 db.collection.xxx()
rs(副本集级别)
sh(分片级别)

4.1 查询操作

#账号认证
mongo --port 20000
use admin;
db.auth("root","LNEi9SSGxpE90bUz")
#显示当前数据库
db
db.getName()
#查询所有数据库
show dbs;
show databases;
#切换数据库
use test;
#查看集合
show collections
show tables;
#查看数据库当前状态
db.stats()
#查看当前数据库的连接机器地址
db.getMongo()
#集群状态
sh.status()
printShardingStatus()

4.2 数据管理

#创建库
use test;
#库启用分片
db.runCommand( { enablesharding :"history"});
sh.enableSharding("<database>")
#集合分片
#hash分片
sh.shardCollection("<database>.<collection>", { <shard key field> : "hashed" } )
#范围分片
sh.shardCollection("<database>.<collection>", { <shard key field> : 1, ... } )
#举例
db.runCommand( { shardcollection : "数据库名称.集合名称",key : {分片键: 1} } )
db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}})
#删除库
use test;
db.dropDatabase()
#创建集合
db.createCollection('a')
#查看当前数据库下的所有集合
show collections;
db.getCollectionNames()
#插入文档,一个集合就会自动创建
db.b.insert({name:'test'});
#查看集合里的内容
db.b.find()
#重命名集合
db.b.renameCollection("boss")
#删除集合
db.a.drop()
#插入1w行数据
for(i=0;i<10000;i++){ db.log.insert({"uid":i,"name":"mongodb","age":7,"date":new Date()}); }
#查看插入的所有记录
db.log.find()
#查询总的记录数
db.log.count() 
#查询UID为1000的数据
db.log.find({uid:1000});
#查询结果更加美观
db.log.find({uid:1000}).pretty()
#查询去掉当前集合中某列的重复数据
db.log.distinct("name")
#删除集合中的所有记录
db.log.remove({})
#查询数据状态
db.log.stats()
#集合中数据的原始大小
db.log.dataSize()
#集合中索引数据的原始大小
db.log.totalIndexSize()
#集合中索引+数据压缩存储之后的大小
db.log.totalSize()
#集合中数据压缩存储的大小
db.log.storageSize()

4.3 用户管理

Read 允许用户读取指定数据库
readWrite 允许用户读写指定数据库
dbAdmin 允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin 允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin 只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase 只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase 只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase 只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase 只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root 只在admin数据库中可用。超级账号,超级权限
#进入管理数据库
use admin
#创建管理用户,root权限
db.createUser(
  {
    user: "root",
    pwd: "root",
    roles: [ { role: "root", db: "admin" } ]
  }
)
#在test库中创建只读用户tst
use test
db.createUser(
  {
    user: "test",
    pwd: "test",
    roles: [ { role: "read", db: "test" } ]
  }
)
#创建读写用户
db.createUser(
  {
    user: "test1",
    pwd: "test1",
    roles: [ { role: "readWrite", db: "test" } ]
  }
)
#创建对多库不通权限的用户
use app
db.createUser(
  {
    user: "app",
    pwd: "app",
roles: [ { role: "readWrite", db: "app" },
         { role: "read", db: "test" }
 ]
  }
)
#查看创建的用户
show users
#验证用户,返回 1 即为成功
db.auth("root","root")

4.4 Config Server

#查看config
use config
db.getCollectionNames()
#查看shards
db.shards.find()

4.5 增加/减少节点

#启动新的分片
mongod -f /data/mongodb/conf/shard4.conf;
#配置新副本集
mongo --port 27004
use admin;
config = {
   _id : "shard4",
    members : [
        {_id : 0, host : "192.168.121.91:27004",priority:10},
        {_id : 1, host : "192.168.121.92:27004",priority:8},
        {_id : 2, host : "192.168.121.93:27004", arbiterOnly: true}
    ]
}
#初始化
rs.initiate(config)
#增加新分片
mongo --port 20000
use admin;
#串联路由服务器与分配副本集
sh.addShard("shard4/192.168.121.91:27004,192.168.121.92:27004,192.168.121.93:27004")
#减少节点必须保证平衡器已启用
use config;
sh.getBalancerState()
#确定分片名称
db.adminCommand( { listShards: 1 } )
#转移分片,从shard4转移到shard3
db.adminCommand( { movePrimary: "history", to: "shard3" })
#移除分片,这个命令也可以查看迁移状态
db.adminCommand( { removeShard: "shard4" } )

4.6 备份恢复

#导出与导入,备份过程中不影响写入,备份内容为写入的那个时间点
#备份前最好关闭平衡器,mongodump只捕获数据库中的文档,mongorestore恢复的时候会自动创建索引
nohup mongodump  --port 20000 -u root -p xxx  -d history -c log -o /opt/ --authenticationDatabase admin >> ouput.log 2>&1 &
nohup mongorestore --port 20000 -u root -p xxx -d history   /data/bak/history/history_xx.bson  --authenticationDatabase admin >> input.log 2>&1 &
#意外关机,修复数据库
#以下情况中恢复
#重建所有索引。丢弃损坏的数据。为丢失的数据/元数据文件创建空/存根文件。
mongod --repair
#创建数据文件的备份并修复
mongod --dbpath /data/bak --repair
#如果修复因任何原因未能完成,必须重新启动实例并--repair提供完成修复的选项。

五. 性能诊断

5.1 下载mongodb-database-tools

wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel70-x86_64-100.5.0.tgz;
tar zxvf mongodb-database-tools-rhel70-x86_64-100.5.0.tgz;
mv mongodb-database-tools-rhel70-x86_64-100.5.0 /opt/mongodb-database-tools;
cd /opt/mongodb-database-tools/bin;
#admin 3是间隔3秒的意思
./mongostat -h 192.168.121.92:20000 -u root  --authenticationDatabase=admin 3
insert query update delete getmore command flushes mapped vsize   res faults qrw arw net_in net_out conn                time
    *0    *0     *0     *0       0     0|0       0     0B 1.39G 25.0M      0 0|0 0|0   118b   4.94k    3 Sep 16 13:01:40.446

添加字段到mongostat输出

./mongostat -h 192.168.121.92:20000 -u root -O='host,version,network.numRequests=network requests' --authenticationDatabase=admin 3
insert query update delete getmore command flushes mapped vsize   res faults qrw arw net_in net_out conn                time                 host version network requests
    *0    *0     *0     *0       0     0|0       0     0B 1.39G 26.0M      0 0|0 0|0   118b   4.94k    3 Sep 16 13:22:09.412 192.168.121.92:20000   4.4.8              176

指定输出字段

./mongostat -h 192.168.121.92:20000 -u root -o='host,time,metrics.document.inserted' --authenticationDatabase=admin 3
host                time metrics.document.inserted
192.168.121.92:20000 Sep 16 13:27:30.357                   INVALID
字段
inserts 每秒插入数据库的对象数。如果后跟星号(例如*),则数据指的是复制操作 res 调用时使用的驻留内存量
query 每秒查询操作数 qrw 等待从 MongoDB 实例读取/写入数据的客户端队列的长度
update 每秒更新操作数 arw 执行读取/写入操作的活动客户端的数量
delete 每秒删除操作的次数 netIn 接收的网络流量(以字节为单位)
getmore 每秒获取更多(即游标批处理)操作的次数 netOut 发送的网络流量(以字节为单位)
command 每秒的命令数。显示由管道字符(例如|) 分隔的两个值local|replicated conn 打开的连接总数
flushes 每个轮询间隔之间触发的 WiredTiger 检查点的数量 host 系统的主机名
vsize 调用时进程使用的虚拟内存量 version 版本
network.numRequests 服务器收到的不同请求的总数 metrics.document.returned 查询返回的文档总数

5.2 慢查询日志

#查询是否开启
db.getProfilingStatus()
#开启:0,关闭;1,记录慢速操作;2,记录所有操作
db.setProfilingLevel(level)
#因mongos上无法为单独实例开启慢查询,如需开启可以在各个分片上开启
#单独实例需要单独的认证 ,创建实例认证,然后再开启慢查询
db.createUser(
  {
    user: "root",
    pwd: "root",
    roles: [ { role: "root", db: "admin" } ]
  }
)
#该was字段指示当前的分析级别。该slowms字段指示操作时间阈值(以毫秒为单位),超过该阈值的操作将被视为慢速。该sampleRate字段指示应分析的慢速操作的百分比。

六. MongoShake迁移

6.1 下载

wget https://github.com/alibaba/MongoShake/releases/download/release-v2.6.5-20210630/mongo-shake-v2.6.5.tar.gz;
tar zxvf mongo-shake-v2.6.5.tar.gz;
cd mongo-shake-v2.6.5;

6.2 修改配置

collector.conf:
# 同步模式,all表示全量+增量同步,full表示全量同步,incr表示增量同步。
sync_mode = all
# 源MongoDB连接串信息,逗号分隔同一个副本集内的结点,分号分隔分片sharding实例,免密模式
# 可以忽略“username:password@”,注意,密码里面不能含有'@'符号。
# 分片集:
mongo_urls = mongodb://192.168.121.91:27001,192.168.121.92:27001;mongodb://192.168.121.92:27002,192.168.121.93:27002;mongodb://192.168.121.93:27003,192.168.121.91:27003
# 如果源端是sharding,此处需要配置源端sharding的cs的地址
mongo_cs_url = mongodb://192.168.121.91:21000,192.168.121.92:21000,192.168.121.93:21000
# 如果源端采用change stream拉取,这里还需要配置至少一个mongos的地址,多个mongos地址以逗号(,)分割
mongo_s_url = mongodb://192.168.121.91:20000,192.168.121.92:20000,192.168.121.93:20000
#目的端连接串信息,分号分割不同的mongos。
tunnel.address = mongodb://192.168.121.94:20000;192.168.121.95:20000;192.168.121.96:20000
# checkpoint存储信息,用于支持断点续传。可以为第三方的,默认不用填写
MongoDB
checkpoint.storage.url =
# 内部发送的worker数目,如果机器性能足够,可以提高worker个数。
incr_sync.worker = 2
# 对于目的端是kafka等非direct tunnel,启用多少个序列化线程,必须为"incr_sync.worker"的倍数。
# 默认为"incr_sync.worker"的值。
incr_sync.tunnel.write_thread = 4

6.3 插入测试数据

mongos> for(i=0;i<10000000;i++){    db.log.insert({name:'nametest',age:i})     }

6.4 开始迁移

./collector.linux -conf=collector.conf

6.5 监控迁移状态

/mongoshake-stat --port=9100

6.6 校验

./comparison.py --src="192.168.121.223:20000" --dest="192.168.121.226:20000" --count=10000000 --excludeDbs=admin,local,mongoshake --excludeCollections=system.profile --comparisonMode=all

参考文献:
https://www.cnblogs.com/clsn/p/8214194.html#auto-id-25
https://www.cnblogs.com/clsn/p/8214345.html#auto-id-0
https://docs.mongodb.com/manual/tutorial/backup-with-filesystem-snapshots/

全面剖析 MongoDB 高可用架构

干货!万亿级数据库MongoDB集群性能优化实践合辑(上)

MongoDB 最佳实践 - 持续更新版


https://docs.mongodb.com/manual/administration/production-notes/

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录