DBA数据库笔记之(九)MongoDB基础及运维
MongoDB安装及常用命令
- MongoDB有哪些特点?
- 面向文档
- 高性能
- 高可用
- 丰富的查询语句
- 支持多种主流的开发语言
- MongoDB的适用场景
- 游戏
- 物流
- 社交
- 视频直播
- 物联网
- 电商
- MongoDB相关的术语和概念
database 数据库
collection 集合
document 文档
field 字段
index 索引
primary key 主键
MongoDB6.0的安装
- 下载压缩包并解压
官方下载地址
cd /usr/src/
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2204-6.0.12.tgz
tar zxvf mongodb-linux-x86_64-ubuntu2204-6.0.12.tgz
mv mongodb-linux-x86_64-ubuntu2204-6.0.12 /usr/local/mongodb6/
- 添加环境变量并创建MongoDB目录
vim /etc/profile
# 增加
export PATH=$PATH:/usr/local/mongodb6/bin
# 使修改生效
source /etc/profile
mongod --version
# 创建数据和日志文件夹
mkdir -p /data/mongodb/{db,log}
- 启动MongoDB
# --fork 后台demo的形式运行
mongod --dbpath /data/mongodb/db --logpath /data/mongodb/log/mongod.log --fork
ps -ef|grep mongodb
连接MongoDB
# centos 系统
wget https://downloads.mongodb.com/compass/mongodb-mongosh-2.1.1.x86_64.rpm
yum install mongodb-mongosh-2.1.1.x86_64.rpm
mongosh --version
- 无密码登录MongoDB
mongosh
show dbs
- 通过用户密码登录MongoDB
# 设置用户和密码
use admin
db.createUser(
{
user:"root",
pwd:"xxxxx",
roles:[{role:"root",db:"admin"}]
}
)
# 重启MongoDB开启验证模式
ps -ef|grep mongodb
kill -9 2536
# 启动
mongod --dbpath /data/mongodb/db --logpath /data/mongodb/log/mongod.log --fork --auth
# 登录
mongosh -u root -p xxxxx
show dbs
db相关命令
- 创建和使用ddatabase
# 创建和使用一个库都可以用 use
use martin
db.test.insert({"num":1})
- 查看有哪些database
show dbs
- 删除database
use martin
db.dropDatabase()
用户相关命令
- 创建管理用户并赋权
use admin
db.createUser(
{
user:"root",
pwd:"xxxxx",
roles:[{role:"root",db:"admin"}]
}
)
- 创建普通用户并赋权
use martin
db.createUser(
{
user:"martin_u",
pwd:"xxxxx",
roles:[{role:"readWrite",db:"martin"}]
}
)
- 查看创建的用户
# 只能查看当前库的用户
show users;
use admin
show users;
# 或者
db.system.users.find()
常用内置角色
- root 超级权限
- readWrite 某个非系统库的读写权限
- read 某个非系统库的读权限
- readWriteAnyDatabase 对所有库的读写权限
- readAnyDatabase 对所有库的读权限
集合管理命令
- 创建集合
use martin
db.createCollection("one")
- 查看集合
show tables;
# 或者
show collections;
- 删除集合
# db.集合名字.drop()
db.one.drop()
CRUD操作
- 插入文档
# 如果没有这个集合就会自动创建
db.one.insertOne({name:"li"})
# 或者
db.one.insert({name:"zhang"})
# 插入多字段
db.one.inset({name:"wang",age:23})
# 插入多行
db.one.insetMany([{name:"zeng",age:23},{name:"wang",age:24}])
# 循环插入多行
for (var 1=1;i <= 101; i++) db.two.insert({num:i,name:'a'});
- 查询文档
# 查询one集合所有数据
db.one.find()
# 查询two集合所有数据
db.two.find()
# 带条件查询
db.one.find({name:'zhang'})
- 更新文档
db.one.update({name:'zhang'},{$set:{name:'li'}})
# 修改多行
db.one.updateMany({name:'li'},{$set:{name:'liu'}})
- 删除文档
# 只删除一条
db.one.deleteOne({name:'liu'})
# 删除满足条件的所有数据
db.one.deleteMany({name:'liu'})
# 删除某个集合中的全部数据
db.one.deleteMany({})
条件相关命令
- 条件操作符
$gt 大于; $lt 小于
$gte 大于等于;$lte 小于等于
- 条件查询
db.one.find({age:{$gt:20}})
db.one.find({age:{$lt:20}})
db.one.find({$and:[{"name":"li"},{"age":28}]})
db.one.find({$or:[{"name":"zhang"},{"age":16}]})
统计计算
- 排序
# 升序
db.one.find().sort({"age":1})
db.one.find({age:{$gt:20}}).sort({"age":1})
# 降序
db.one.find().sort({"age":-1})
- 求和及平均
# 请求
db.one.countDocuments()
db.one.countDocuments({age"{$gt:20}})
# 求某个字段和
db.three.aggregate([{'$group':{_id:'$class','sum_score':{'$sum':'$score'}}}])
# 请平均值
db.three.aggregate([{'$group':{_id:'$class','avg_score':{'$avg':'$score'}}}])
- 最大最小值
# 最大值
db.three.aggregate([{'$group':{_id:'$class','max_score':{'$max':'$score'}}}])
# 最低分
db.three.aggregate([{'$group':{_id:'$class','min_score':{'$min':'$score'}}}])
MongoDB查询优化
慢查询
- 慢查询开启和关闭
# 查看慢查询是否开启;was:0 表示没有开启;slowms:100 慢查询预值单位毫秒;sampleRate:1采样率,1都采样
db.getProfilingStatus()
# 开启慢查询 1 表示开启,100超过100毫秒的语句记录到慢查询
db.setProfilingLevel(1,100)
# 关闭慢查询
db.setProfilingLevel(0)
- 查看慢查询
# 测试表
for (var i=1 ; i <= 100000 ; i++) db.slow_test.insert({num:i,name:"a"})
# 开启慢查询
db.setProfilingLevel(1,100)
# 执行语句
db.slow_test.find({"num":9999})
# 查询慢查询记录
db.system.profile.find()
- 慢查询分析
command 执行的命令
keysExamined:0 索引扫描的行数,0表示这条语句没有走索引
docsExamined:100000 表示扫描的文档数
nreturned:1 表示返回的文档数
responseLenngth:151 表示命令返回的字节数
millis:117 表示命令执行的时间,117毫秒
planSummary:'COLLSCAN' 表示扫描的方式,COLLSCAN表示全集合扫描
ts 表示命令执行的时间点
client:'127.0.0.1' 表示慢查询的客户端
查询计划
- 基本用法
# 默认queryPlanner查询优化器选择查询优化的详细信息
db.slow_test.find({num:99}).explain()
db.slow_test.find({num:99}).explain("queryPlanner")
# executionStats 详细分布查询计划和分布时间
db.slow_test.find({num:99}).explain("executionStats")
# allPlansExecution 表示查看所有的执行计划 或者 true
db.slow_test.find({num:99}).explain("allPlansExecution")
db.slow_test.find({num:99}).explain(true)
- 条件字段没索引的执行计划
db.slow_test.find({num:99}).explain(true)
# 分析结果
nReturnd:1 返回的行数
executionTimeMillis:86 花费的时间
totalKeysExamined:0 扫描了多少索引项
totalDocsExamined:100000 扫描了多少文档
stage:'COLLSCAN' 全集合扫码,IXSCAN索引扫码
- 条件字段有索引的执行计划
# 添加索引 为slow_test表num字段添加一个增序索引
db.slow_test.createIndex({"num":1})
# 再查询执行计划
db.slow_test.find({num:99}).explain(true)
索引管理
- 索引创建
# 写入测试数据
for (var i=1 ; i <= 10000 ; i++) db.index_test.insert({num:i,name:'a'})
# 查询集合的前10个文档
db.index_test.find().limit(10)
# 添加所以 1 按升序创建索引,-1 按降序创建索引
db.idnex_test.createIndex({"num":1})
- 查询索引
db.index_test.getIndexes()
- 删除索引
# 接索引名字
db.idnex_test.dropIndex("num_1")
多种索引类型
- 单键索引
- 组合索引
db.index_test.createIndex({"num":1,"name":1})
- 多值索引也叫数组索引
# 测试数据
db.index_test_01.insert({name:"martin",tag:["a","b","c"]})
# 创建索引
db.index_test.createIndex({"tag":1})
# 查看执行计划
db.index_test_01.find({tag:"b"}).explain(true)
- 全文索引
# 一个集合最多创建一个全文索引
db.index_test_01.createIndex({"name":"text"})
- 哈希索引
# 哈希索引不支持范围查询且不支持多键hash
db.index_test_01.createIndex({"name":"hashed "})
- 地理位置索引
# 写入地理位置数据
db.index_test_02.insertMamy([{loc:[9,9]},{loc:[11,11]},{loc:[100,100]}])
# 创建地理位置索引
db.index_test_02.createIndex({"loc":"2d"})
# 查询地理数据
db.index_test_02.find({loc:{$geoWithin:{$box:[[10,10],[12,12]]}}})
索引原理
![](https://img.haomeiwen.com/i19961919/d51438227b3644ae.jpg)
MongoDB副本集(高可用方案)
副本集架构介绍
![](https://img.haomeiwen.com/i19961919/9e1ff4403ff0a7a6.jpg)
副本集原理
- 副本集复制原理
创建副本集之后会进行一次全量同步,在primary节点克隆出除local库之外的数据库
# 查看local库
mongosh -u root -p xxx
show dbs
并且会扫描出原数据库中每个集合并将所有数据插入到这些集合自己的副本中,在复制过程中目标成员会拉取新添加的oplog记录,这样就可以记录在全量数据传输过程中,在primary所做的增量操作。全量数据导入完后再应用oplog可以保证跟源端数据一致,当数据同步之后如果有primary节点有修改操作,就会记录到oplog里面,在secondary有一个线程会持续监听log的变化,有变化的时候会把变动传到secondary节点再进行回放,保证持续数据是同步的。
- oplog
如果没有指定oplog大小,如果是内存的存储引擎默认是物理内存的5%,最小值是50M,最大值是50G;如果是WiredTiger存储引擎默认是物理内存的5%,最小值是999M,最大值是50G。
- 故障恢复原理
在副本集当中节点之间两两是互相发送心跳的,当超过一定时间没有收到对方心跳时判断对方失联,如果失联的是主节点那从节点就会发起选举,选出新的主节点,如果失联的是从节点则不会触发新的选举直接踢出失联的从节点。
副本集的安装
- 下载并解压MongoDB
三台机器
cd /usr/src/
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2204-6.0.12.tgz
tar zxvf mongodb-linux-x86_64-ubuntu2204-6.0.12.tgz
mv mongodb-linux-x86_64-ubuntu2204-6.0.12 /usr/local/mongodb6/
# 修改环境变量
vim /etc/profile
# 增加
export PATH=$PATH:/usr/local/mongodb6/bin
# 使修改生效
source /etc/profile
mongod --version
# 创建数据和日志文件夹
mkdir -p /data/mongodb27001/{data,conf,run,logs}
- 创建密钥文件
# 随机生成一个复杂的密码;rand 随机;-base64 随机数据以base编码输出;756字节数
openssl rand -base64 756 > /ddata/mongodb27001/conf/keyfile
chmod 400 /ddata/mongodb27001/conf/keyfile
# 传输到其它两台机器
scp /ddata/mongodb27001/conf/keyfile 192.168.12.162:/data/mongodb27001/conf/
scp /ddata/mongodb27001/conf/keyfile 192.168.12.163:/data/mongodb27001/conf/
- 每台机器修改配置文件
vim /data/mongodb27001/conf/mongod.conf
# 系统日志
systemLog:
# 文件类型
destination: file
# true 追加的方式
logAppend: true
# 路径
path: /data/mongodb27001/logs/mongod.log
# 存储相关的配置
storage:
dbPath: /data/mongodb27001/data
# 日志配置
journal:
enabled: true
# 进程管理相关的配置
processManagement:
fork: true
pidFilePath: /data/mongodb27001/run/mongod.pid
timeZoneInfo: /usr/share/zoneinfo
# 网络相关的配置
net:
port: 27001
# 0.0.0.0 对所有机器开放访问
bindIp: 0.0.0.0
# 集群相关配置
replication:
oplogSizeMB: 4096
# 副本集的名字,同一个副本集每一个成员replSetName要一样
replSetName: martin_repl
# 加密相关
security:
keyFile: /data/mongodb27001/conf/keyfile
- 启动MongoDB
# 三台机器
mongod -f /data/mongodb27001/conf/mongod.conf
# 三台机器安装mongosh
# centos 系统
wget https://downloads.mongodb.com/compass/mongodb-mongosh-2.1.1.x86_64.rpm
yum install mongodb-mongosh-2.1.1.x86_64.rpm
mongosh --version
- 创建集群
# 第一台机器
mongosh --port 27001
rs.initiate({
_id:"martin_repl",
members:[
{_id: 0,host:'192.168.12.161:27001',priority:1},
{_id: 1,host:'192.168.12.162:27001',priority:1},
{_id: 2,host:'192.168.12.163:27001',arbiterOnly:true}
]
})
_id 集群名字
# 查看集群状态
rs.status()
创建用户
- 创建管理员用户
# passwordPrompt()表示过会输入密码
admin=db.getSiblingDB("admin")
admin.createUser({
user:"root",
pwd:passwordPrompt(),
roles:[{role:"userAdminAnyDatabase",db:"admin"}]
})
# 需要密码
show dbs
# 登录
mongosh --port 27001 -u root -p
show dbs
- 创建集群管理员
db.getSiblingDB("admin").createUser({
user:"repl",
pwd:passwordPrompt(),
roles:[{"role":"clusterAdmin","db":"admin"}]
})
- 创建应用账号
mongosh --port 27001 -u root -p
db.getSiblingDB("martin").createUser({
user:"martin_rw",
pwd:passwordPrompt(),
roles:[{"role":"readWrite","db":"martin"}]
})
集群测试
- 验证同步
# 在primary主节点
mongosh --port 27001 -u martin_rw -p xxxx martin
# 写入操作
db.one.insertOne({name:'liu'})
# 查看从节点
mongosh --port 27001 -u martin_rw -p xxxx martin
# 从节点默认不能查询
db.one.find()
# 设置从节点可以查询数据
db.getMongo().setReadPref('secondaryPreferred')
# 再查询
db.one.find()
- 使用ChatGPT编写Go连接副本集的程序
帮忙写一个Go程序,操作MongoDB副本集,副本集的连接信息如下:
mongodb://martin_rw:xxx@192168.12.161:27001,192.168.12162:27001/martin?replicaSet=martin_rep
集群的名字是martin_repl
在martin这个库里面,每秒往集合write_test里写一行文档,每一行文档需要不一样
# 调整修改代码
# 运行代码
# 查看MongoDB数据
- 测试副本集的高可用
# 继续写入数据
# kill掉mongodb主节点
# 查看正在运行的代码
# 在从查看信息
mongosh --port 27001 -u martin_rw -p xxxx martin
rs.status()
# 在启动关闭的节点
mongod -f /data/mongodb27001/conf/mongod.conf
副本集常见管理操作
- 强制将某个主节点设置为从节点
# replSetDown 表示一旦这个主节点成功退出那么这个节点收到命令到120秒内不能再次成为主节点
# 在主节点执行
db.adminCommand({replSetDown:120})
rs.status()
- 副本集新增成员
mkdir -p /data/mongodb27002/{data,conf,run,logs}
# 修改配置文件
vim /data/mongodb27002/conf/mongod.conf
# 系统日志
systemLog:
# 文件类型
destination: file
# true 追加的方式
logAppend: true
# 路径
path: /data/mongodb27002/logs/mongod.log
# 存储相关的配置
storage:
dbPath: /data/mongodb27002/data
# 日志配置
journal:
enabled: true
# 进程管理相关的配置
processManagement:
fork: true
pidFilePath: /data/mongodb27002/run/mongod.pid
timeZoneInfo: /usr/share/zoneinfo
# 网络相关的配置
net:
port: 27002
# 0.0.0.0 对所有机器开放访问
bindIp: 0.0.0.0
# 集群相关配置
replication:
oplogSizeMB: 4096
# 副本集的名字,同一个副本集每一个成员replSetName要一样
replSetName: martin_repl
# 加密相关
security:
keyFile: /data/mongodb27002/conf/keyfile
# 复制密钥文件
cp /data/mongodb27001/conf/keyfile /data/mongodb27002/conf/
# 启动27002
mongod -f /data/mongodb27002/conf/mongod.conf
# 添加新的成员;使用集群管理账号
mongosh --port 27001 -u repl -p xxxx
rs.status()
# 添加新的节点
rs.add({host:"192.168.12.161:27001"})
rs.status()
- 副本集删除成员
rs.remove("192.168.12.161:27002")
rs.status()
一主两副本架构介绍
![](https://img.haomeiwen.com/i19961919/79c83111f470e7e7.jpg)
MongoDB分片集群
副本集满足不了需求就可以使用分片集群
- 什么时候考虑使用分片?
- 数据量过大
- 数据持续增长
- 副本集已经满足不了高并发写入的性能要求了
一般情况下副本集够用的情况还是强烈建议使用副本集,分片集群的主键跟多,维护更复杂
- 分片集群的特点
- 对应用透明
- 数据会自动平衡
- 动态扩容
分片集群的架构
![](https://img.haomeiwen.com/i19961919/95b9b1216657ed52.jpg)
部署Config Servers
- 增加Config Servers的配置文件
# 需要安装三个Config Servers
mkdir -p /data/mongodbconfig27020/{data,conf,run,logs}
vim /data/mongodbconfig27020/conf/mongod.conf
sharding:
clusterRole: configsvr
systemLog:
destination: file
logAppend: true
path: /data/mongodbconfig27020/logs/mongod.log
storage:
dbPath: /data/mongodbconfig27020/data
journal:
enabled: true
processManagement:
fork: true
pidFilePath: /data/mongodbconfig27020/run/mongod.pid
timeZoneInfo: /usr/share/zoneinfo
net:
port: 27020
bindIp: 0.0.0.0
replication:
oplogSizeMB: 4096
replSetName: config_repl
clusterRole 集群名字
replSetName 要配置 config_ 关键字开头
- 启动Config Servers
# 三台机器都要启动
mongod -f /data/mongodbconfig27020/conf/mongod.conf
- 创建集群
# 随便选一台Config Servers的机器登录
mongosh --port 27020
# 副本集创建
rs.initiate({
_id:"config_repl",
configsvr:true,
members:[
{_id: 0,host:'192.168.12.161:27020'},
{_id: 1,host:'192.168.12.162:27020'},
{_id: 2,host:'192.168.12.163:27020'}
]
})
rs.status()
启动MongoDB分片实例
分片实例用来存放数据的
- 增加分片实例的配置文件
# 三台机器都需要
mkdir -p /data/mongodbshard27021/{data,conf,run,logs}
mkdir -p /data/mongodbshard27022/{data,conf,run,logs}
vim /data/mongodbshard27021/conf/mongod.conf
sharding:
clusterRole: shardsvr
systemLog:
destination: file
logAppend: true
path: /data/mongodbconfig27021/logs/mongod.log
storage:
dbPath: /data/mongodbconfig27021/data
journal:
enabled: true
processManagement:
fork: true
pidFilePath: /data/mongodbconfig27021/run/mongod.pid
timeZoneInfo: /usr/share/zoneinfo
net:
port: 27021
bindIp: 0.0.0.0
replication:
oplogSizeMB: 4096
replSetName: shardsvr_repl_27021
# 第二份
vim /data/mongodbshard27022/conf/mongod.conf
sharding:
clusterRole: shardsvr
systemLog:
destination: file
logAppend: true
path: /data/mongodbconfig27022/logs/mongod.log
storage:
dbPath: /data/mongodbconfig27022/data
journal:
enabled: true
processManagement:
fork: true
pidFilePath: /data/mongodbconfig27022/run/mongod.pid
timeZoneInfo: /usr/share/zoneinfo
net:
port: 27022
bindIp: 0.0.0.0
replication:
oplogSizeMB: 4096
replSetName: shardsvr_repl_27022
- 启动MongoDB
mongod -f /data/mongodbshard27021/conf/mongod.conf
mongod -f /data/mongodbshard27022/conf/mongod.conf
# 启动后每台机器应该有三个实例
ps -ef | grep mogo
- 创建集群
# 在一台机器登录
mongosh --port 27021
# 创建集群
rs.initiate({
_id:"shardsvr_repl_27021",
members:[
{_id: 0,host:'192.168.12.161:27021'},
{_id: 1,host:'192.168.12.162:27021'},
{_id: 2,host:'192.168.12.163:27021'}
]
})
rs.status()
# 再换一个端口
mongosh --port 27022
# 添加集群
rs.initiate({
_id:"shardsvr_repl_27022",
members:[
{_id: 0,host:'192.168.12.161:27022'},
{_id: 1,host:'192.168.12.162:27022'},
{_id: 2,host:'192.168.12.163:27022'}
]
})
rs.status()
配置和启动mongos
- 增加mongos的配置文件
# 三台机器随便选一台
mkdir /data/mongos27017/{logs,conf,run} -p
vim /data/mongos27017/conf/mongos.conf
sharding:
configDB:config_repl/192.168.12.161:27020,192.168.12.162:27020,192.168.12.163:27020
systemLog:
destination: file
logAppend: true
path: /data/mongos27017/logs/mongos.log
processManagement:
fork: true
pidFilePath: /data/mongos27017/run/mongod.pid
net:
port: 27017
bindIp: 0.0.0.o
configDB : config_repl config Servers实例的名字,192.168.12.161:27020,192.168.12.162:27020,192.168.12.163:27020三台Config Servers的ip和端口
- 启动mongos
mongos --config /data/mongos27017/conf/mongos.conf
- 创建用户
mongosh --port 27017
# 创建管理员用户
admin = db.getSiblingDB("admin")
admin.createUser(
{
user:"root",
pwd: passwordPrompt(),
roles:[{role:"userAdminAnyDatabase",db:"admin"}]
}
)
# 重新登录
mongosh --port 27017 -u root -p
# 创建业务用户
db.getSiblingDB("admin").createUser(
{
user:"martin_rw",
pwd: passwordPrompt(),
roles:[{"role":"readWrite","db":"martin"}]
}
)
分片配置
- 将分片副本集添加到集群
# shardsvr_repl_27021 分片集群的名字,后面是分片集群的ip和端口
sh.addShard("shardsvr_repl_27021/192.168.12.161:27021,192.168.12.162:27021,192.168.12.163:27021")
sh.addShard("shardsvr_repl_27022/192.168.12.161:27022,192.168.12.162:27022,192.168.12.163:27022")
- 创建分片表
# 用业务用户账号登录
mogosh martin --port 27017 -u martin_wr -p
# 为martin这个库启动分片
sh.enableSharding("martin")
# 再对collection就行分片;martin.userinfo 库名+集合的名字;_id 分片的键/分片的字段;如果 martin.userinfo被drop掉就要重新配置分片规则
sh.shardCollection("martin.userinfo",{_id:"hsahed"})
# 查看分片详情
sh.status()
- 分片集群数据分布测试
# 循环往martin分片写入数据
for (var i=1; i <= 20; i++) db.userinfo.insertOne({userid:i,username:'a'});
db.userinfo.find()
# 只看第一个分片的数据
mongosh martin --port 27021
db.userinfo.find()
# 查看第二个分片的数据
mongosh martin --port 27022
db.userinfo.find()
分片集群高可用测试
- ChatGPT生成分片集群数据写入的程序
编写一个Go程序,连接MongoDB的mongos,
每秒往里面写入一行文档,
有用户密码,直接连接到业务库martin
每次写入成功或者失败,
都有带时间戳的日志信息
- 测试代码
# 运行代码后
show tables;
sb.shard_write_test.find()
sb.shard_write_test.countDocuments()
- 测试分片集群的高可用
# 分片集群 kill掉主节点
mongosh --port 27021
# 查看主节点
rs.status()
ps -ef|grep mongo
kill -9 25920
# 程序正常运行
MongoDB性能压测
环境准备
- 安装java
- 安装maven
- 下载安装压测工具YCSB
cd /usr/src/
wget https://github.com/brianfrankcooper/YCSB/releases/download/0.17.0/ycsb-mongodb-binding-0.17.0.tar.gz
tar zxvf ycsb-mongodb-binding-0.17.0.tar.gz
运行只读压测
- 修改配置文件
cd ycsb-mongodb-binding-0.17.0
# 连接primary节点
mongosh --port 27001 -u root -p
# 创建压测用户
db.getSiblingDB("ycsb").createUser({
user:"ycsb_rw",
pwd:passwordPrompt(),
roles:[{"role":"readWrite","db":"ycsb"}]
})
# 修改配置文件
vim workloads/workloada
# 新增配置
mongodb.url=mongodb://ycsb_rw:密码@192.168.12.161:2001/?authSource=ycsb
# 原有配置
# 表示要加载到数据库里面的记录数
recordcount=1000
# 表示要执行的操作数
operationcount=1000
# 工作负载
workload=size.ycsb.workloads.CoreWorkload
# 读的操作比例
readproportion=1
# update的操作比例;目前要压测只读需要修改为0
updateproportion=0
- 运行只读压测
# 加载数据
./bin/ycsb load mongodb -P workloads/workloada
# 压测
./bin/ycsb run mongodb -P workloads/workloada
- 压测结果分析
运行读写压测
- 编辑配置文件
vim workloads/workloada
# 修改
readproportion=0.5
updateproportion=0.5
- 运行读写压测
# 删除已经加载的压测数据
mongosh --port 27001 -u ycsb -p
show tables;
db.usertable.drop()
# 加载压测数据
./bin/ycsb load mongodb -P workloads/workloada
# 压测
./bin/ycsb run mongodb -P workloads/workloada
- 压测结果分析
MongoDB响应慢排查
准备
- 工具安装
mongodb4.4开始MongoDB工具和MongoDB server是分开发布的,需要单独部署mongo工具
cd /usr/src
# 以centos7.0为例
wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel70-x86_64-100.9.4.rpm
yum install mongodb-database-tools-rhel70-x86_64-100.9.4.rpm -y
- 增加监控权限
mongosh --port 27001 -u root -p
use admin
db.grantRolesToUser("root",["clusterMonitor"])
通过工具分析MongoDB的性能
- 使用mongostat获取负载分布
mongostat --uri="mongodb://root:密码@192.168.12.161:27001/?replicaSet=martin_repl&authSource=admin"
insert query update delete getmore command 最近一秒操作的次数
dirty :WiredTiger 脏数据,未刷盘的数据占总内存的比例
used :WiredTiger 内存使用率
flushes :WiredTiger 最近一秒刷到磁盘的次数
vsize 使用了多少虚拟内存
res 实际使用的内存大小
qrw 读写等待的队列长度
arw 执行读写操作的活跃客户端是否是短时间活跃连接数突增
net_in net_out 表示进出对的流量
conn 连接数
set 副本集的名字
repl 副本集的状态
time 当前时间
- 使用mongotop查看各个步骤花费的时间
mongotop --uri="mongodb://root:密码@192.168.12.161:27001/?replicaSet=martin_repl&authSource=admin"
MongoDB的备份和恢复
准备
- 启动之前部署的副本集
# 三台机器
ps -ef | grep 27001
mongod -f /data/mongodb27001/conf/mongod.conf
# 登录到集群查看信息
mongosh martin --port 27001 -u martin -p
rs.status()
- 写入测试数据
db.baktest.insetOne({name:'liu'})
- 备份工具安装
# 另一台机器安装
cd /usr/src/
wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel70-x86_64-100.9.4.rpm
yum install mongodb-database-tools-rhel70-x86_64-100.9.4.rpm -y
mongodump/mongorestore备份恢复
- 单实例备份和恢复
# 在secondary节点备份;创建备份文件夹
mkdir -p /data/mongodb/backup
cp /data/mongodb/backup
# 执行备份命令
mongodump -u martin_rw -p xxxx --host localhost:27001 --db martin --out ./mongobak
# 恢复
show tables;
# 清空集合
db.baktest.drop()
db.one.drop()
db.write_test.drop()
# 在primary节点恢复;创建恢复文件夹
mkdir /data/mongodb/backup
# secondary节点。将备份文件传输到primary节点
cd mongobak/
scp -r martin/ 192.168.12.161:/data/mongodb/backup
# 在primary节点
cd /data/mongodb/backup
# -d martin 表示要恢复到的db里
mongorestore --host 192.168.12.161:27001 -u martin_rw -p xxx -d martin /data/mongodb/backup/martin/
mongosh martin --port 27001 -u martin_rw -p
show tables;
- 副本集备份和恢复
cd /data/mongodb/backup/
# 连接集群的方式备份;只写primary和secondary节点的ip和端口;--readPreference=secondary 只会到secondary节点去备份,如果secondary都宕机就会报错,secondaryPreferred 如果所有secondary都宕机就回去primary节点备份
mongodump --host="martin_repl/192.168.12.161:27001,192.168.12.162:27001" --readPreference=secondaryPreferred -u martin_rw -p xxxx --db martin --out ./repl_mongobak
# 恢复和单实例一样
- 分片集群备份和恢复
mongodump --host="192.168.12.161:27017" --readPreference=secondaryPreferred -u martin_rw -p xxxx --db martin --out ./shard_mongobak
# 恢复一样
mongoexport/mongoimport备份恢复
- 单实例备份和恢复
# -d martin 备份的库;-c baktest 备份的集合;-o 输出文件
mongoexport --host localhost:27001 -u martin_rw -p xxxx -d martin -c baktest -o baktest.json
# 恢复;在primary节点,删除baktest集合,将备份文件baktest.json传输到当前节点机器
mongoimport --host localhost:27001 -u martin_rw -p xxxx -d martin -c baktest --file baktest.json
- 副本集的备份和恢复
# 备份
mongoexport --host="martin_repl/192.168.12.161:27001,192.168.12.162:27001" --readPreference=secondaryPreferred -u martin_rw -p xxxx -d martin -c baktest -o repl_baktest.json
# 恢复一样
- 分片集群备份和恢复
mongoexport --host="192.168.12.161:27017" --readPreference=secondaryPreferred -u martin_rw -p xxxx -d martin -c baktest -o shard_baktest.json
# 恢复一样
编写自动化备份脚本
- 通过ChatGPT来编写备份脚本
编写一个MongoDB副本集的备份脚本
备份文件夹是 /data/mongobackup
备份命令为: mongodump --host="martin_repl/192.168.12.161:27001,192.168.12.162:27001" --readPreference=secondary -u martin_rw -p xxxx --db martin --out ./repl_mongobak
备份的子文件夹以bak_开头
每次删除15天之前的备份
- 检查脚本
vim mongo_repl_backup.sh
chmod +x mongo_repl_backup.sh
- 测试脚本
MongoDB的数据安全
保证MongoDB数据安全的策略
- 身份认证
- 配置不同的用户
- 设置复杂的密码
- 权限控制
- 网络隔离
- 定期备份
MongoDB监控
MongoDB常见监控项
- 连接相关监控
# 登录副本集primary节点
mongosh --port 27001 -u root -p
# 如果执行不了就需要增加权限
db.serverStatus().connections
# 增加权限
use admin
db.grantRolesToUser("root",["clusterMonitor])
current: 18 当前连接数
available: 801 未使用但是可以用的连接数
totalCreated: 244 启动到现在总共创建的连接数
active: 5 活跃连接数
threaded: 18 客户端连接的线程数
- 内存相关监控
db.serverStatus().mem
bits:64 表示MongoDB运行实例的架构
resident:28 使用的屋里内存大小单位M
virtual:2964 使用虚拟内存大小
supported:true MongoDB进程所依赖的底层操作系统是否支持扩展的内存信息
- wiredTiger的Cache监控
db.serverStatus().wiredTiger.cache
- 锁相关信息
db.serverStatus().locks
- 命令执行统计
db.serverStatus().opcounters
- 指定业务库的监控
use martin
db.stats();
- 每个集合的使用统计监控
# 只能在admin执行
use admin
db.runCommand(
{
top:1
}
)
- 副本集监控
rs.status();