# 配置
# 配置文件
- 旧版 MongoDB 的配置文件采用 ini 格式,从 2.6 版开始推荐采用 YAML 格式,分为 storage、systemLog、net 等多个大类。
# 示例
mongod.conf 配置文件示例:
net:
port: 27017
bindIp: 0.0.0.0
# bindIp: localhost,10.0.0.1,/tmp/mongod.sock # 可以绑定多个 IP 供客户端访问
# processManagement:
# fork: false # 是否作为 daemon 进程运行
# pidFilePath: /var/run/mongod.pid
security:
authorization: enabled # 是否对客户端启用 RBAC 认证,默认为 disabled
# clusterAuthMode: keyFile # 集群各节点之间的认证方式
storage:
dbPath: /var/lib/mongo # 存储数据的目录。默认在同一个目录下存放所有数据库的各个集合的数据文件 collection-xx.wt 和 index-xx.wt
# directoryPerDB: false # 是否在 dbPath 下为每个数据库分别创建一个目录来存放数据文件。在 MongoDB 首次运行之后,不方便修改该配置参数
# journal:
# enabled: true # 是否启用 WiredTiger 预写日志,从而在 mongo 异常重启时自动恢复数据文件,默认为 true
# engine: wiredTiger # 采用的存储引擎
# wiredTiger: # wiredTiger 存储引擎的配置
# engineConfig:
# cacheSizeGB: 2 # 内部缓存的最大体积,单位为 GB 。默认为 (RAM-1GB)*50% ,至少为 0.25GB
# collectionConfig:
# blockCompressor: snappy # 将集合数据存储到磁盘时的压缩算法
systemLog: # 服务器日志
# verbosity: 0 # 日志级别,取值范围为 0 ~ 5 ,对应 INFO ~ DEBUG
destination: file # 日志的输出方向,可以为 file 或 syslog 。默认输出到 stdout
path: /var/log/mongo/mongod.log
logAppend: true # mongo 重启后,是否将日志以追加方式写到之前的日志文件。默认为 false ,会备份之前你的日志文件,并创建新的日志文件
operationProfiling: # 慢查询日志
mode: slowOp # 工作模式,默认为 off
# slowOpThresholdMs: 100
# slowOpSampleRate: 1 # 慢查询的采样率,取值范围为 0~1 。对于副本集的从节点,采样率总是 1
# 慢日志
- 慢日志的几种模式:
off # 不记录 slowOp # 只记录耗时超过 slowOpThresholdMs 阈值的操作 all # 记录所有数据库操作
- 慢日志会记录到两个位置:
- 当前 db 的系统集合 system.profile 。该集合为 capped 类型,size 为 1024^2 。
- 日志文件 mongod.log 。
- 相关命令:
db.system.profile.find().limit(10).sort({ts:-1}).pretty() // 查看最近的 10 个慢查询 db.system.profile.find({millis:{$gt:10}}).pretty() // 查看耗时超过 10 毫秒的慢查询 db.system.profile.find({ts:{$gt: new ISODate('2022-01-01T00:00:00Z'), $lt: new ISODate('2022-01-02T00:00:00Z')}}).pretty() // 查看指定时间范围的慢查询
# 存储引擎
- In-Memory
- 存储在内存中。
- 该引擎仅企业版可用。
- MMAPv1
- MongoDB v3.2 之前的默认引擎。
- WiredTiger
- MongoDB v3.2 开始的默认引擎。
- 与 MMAPv1 相比:
- MMAPv1 基于 MMAP 技术读写磁盘文件,而 WiredTiger 以普通方式读写磁盘文件。
- MMAPv1 在磁盘存储数据时不支持压缩,而 WiredTiger 默认会进行压缩,主要分为两种数据:
- 文档数据通过 snappy 算法压缩之后,存储到磁盘文件 collection-xx.wt 中,从而大幅减少占用的磁盘空间。
- 索引数据通过前缀压缩之后,存储到磁盘文件 index-xx.wt 中,从而小幅减少占用的磁盘空间。
前缀压缩是指,在一个 page 中存储多条索引数据时,如果它们索引键的前缀相同,则只存储一份前缀。
- MMAPv1 数据库锁的最小单位为 collection ,而 WiredTiger 最小锁单位为 document 。
- 默认基于 B+ tree 存储数据并进行索引。
- 也可改用 LSM Tree ,增加写入速度,降低读取速度。
- 从 MongoDB v3.6 开始,WiredTiger 每隔一定时间会将内存中的写操作数据存储到磁盘(而不是每发生一次写操作就立即存储),建立一个快照,称为检查点(checkpoint)。
- 在两个 checkpoint 之间,采用 journal 预写日志来临时记录数据库的所有写操作,相当于增量备份。
- 如果 mongod 异常退出,重启时会自动回滚到上一个 checkpoint ,并使用预写日志来恢复数据。
- 默认每隔 60s ,或累计写入 2G 预写日志时,就创建一个新的 checkpoint ,并删除旧的 checkpoint 、预写日志。
- 删除集合中的文档时,这部分磁盘空间不会立即释放,而是留给该集合以后写入新文档。
- 缺点:标记为 deleted 的磁盘空间如果一直未写入新文档,则造成了浪费。而且按块读取文件数据时,deleted 空间会跟正常文档混合在一起被读取,浪费内存空间。
- 为了清理 deleted 空间,可以删除整个集合,这会删除磁盘中的数据文件 collection-xx.wt 和 index-xx.wt ,立即释放磁盘空间。
- 为了清理 deleted 空间,可以将原集合 copy 到一个新集合,然后将原集合 drop ,最后将新集合 rename 为原集合。
- 为了清理 deleted 空间,可以执行
db.runCommand({compact:'<collection>'})
。- 它的原理是将集合的数据拷贝一份,重新写入磁盘,然后重建索引,因此需要事先留出一倍空闲的磁盘空间。
- 在 MongoDB v4.4 之前,执行 compact 命令时,会阻塞当前数据库的所有 CRUD 操作。从 MongoDB v4.4 开始,只会阻塞当前集合的 drop()、createIndex()、dropIndex() 操作。
- 在副本集中,Secondary 节点并不会同步该命令,因此需要到每个节点执行该命令。
- 对比 Mongo 与 ES 的磁盘清理策略:
- Mongo WiredTiger 删除文档之后,这部分磁盘空间不会立即释放,但随时可用于写入新文档,因此磁盘文件是可变的,不能统计 deleted 文档数。
- ES 删除文档之后,这部分磁盘空间不会立即释放,而是等到下一次合并磁盘文件时才清理。在合并之前,磁盘文件是不变的,因此可以统计 deleted 文档数。
# 访问控制
# 身份认证
- MongoDB 默认没有启用身份认证,可按以下步骤启用:
- 进入 MongoDB 终端,创建一个管理员用户:
use admin db.createUser( { user: 'root', pwd: '******', roles: [{role: 'root', db: 'admin'}] } )
- 退出 MongoDB 终端,执行
mongod --auth
重启 MongoDB 服务器,启用身份认证。
- 进入 MongoDB 终端,创建一个管理员用户:
- 如果已启用身份认证,但是不知道管理员账号,则可以先用
mongod ---noauth
重启服务器,再创建管理员账号。 - 如果已启用身份认证,则启动客户端时,需要传入用户名、密码,并指定用于验证该用户的数据库。例如
mongo mongodb://127.0.0.1:27017?authSource=admin -u root -p ******
。- 默认采用当前连接的数据库作为验证数据库,检查该用户在该数据库中是否有效。如果不存在该用户名,或密码错误,则报错:
Authentication failed
- 可以先启动客户端,再进行密码认证:
mongo 127.0.0.1:27017/admin db.auth('root', '******')
- 默认采用当前连接的数据库作为验证数据库,检查该用户在该数据库中是否有效。如果不存在该用户名,或密码错误,则报错:
# 管理用户
- MongoDB 支持启用基于角色的访问控制(RBAC)。
- 在 admin 数据库的 system.users 集合中存储了所有用户的信息,包括用户名、密钥、所属数据库、分配的角色。
- 每个用户登录时,除了输入密码,还需要指定所属的数据库进行身份认证。
- root 用户登录时,只能指定 admin 数据库进行身份认证。
- 普通数据库定义了以下角色:
- read :可以读取数据库
- readWrite :可以读写数据库
- dbAdmin :可以管理数据库
- userAdmin :可以管理用户
- admin 数据库定义了以下角色:
- readAnyDatabase
- readWriteAnyDatabase
- dbAdminAnyDatabase
- userAdminAnyDatabase
- clusterAdmin :可以管理副本集
- root :超级管理员,拥有所有权限
- 例:
// 显示当前数据库的所有用户 show users // 创建一个用户 db.createUser({user: 'user1', pwd: '******', roles: [{role: 'readWrite', db: 'db1'}]}) // 删除用户 db.dropUser('user1') // 给用户分配权限 db.grantRolesToUser('user1', [{role: 'readWrite', db: 'db1'}, [{role: 'read', db: 'db2'}]) // 删除用户的权限 db.revokeRolesFromUser('user1', [{role: 'readWrite', db: 'db1'}])