# 配置

# 配置文件

  • 旧版 MongoDB 的配置文件采用 ini 格式,从 2.6 版开始推荐采用 YAML 格式,分为 storage、systemLog、net 等多个大类。

# 示例

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       # 不记录
    all       # 记录所有数据库操作
    slowOp    # 只记录执行时长超过 slowOpThresholdMs 阈值的操作
    
    • 慢查询日志会记录到当前 db 的 system.profile 集合里,该集合的最大容量为 1MB 。

# 存储引擎

  • In-Memory
    • 存储在内存中。
    • 该引擎仅企业版可用。
  • MMAPv1
    • MongoDB v3.2 之前的默认引擎。
  • WiredTiger
    • MongoDB v3.2 开始的默认引擎。
    • 与 MMAPv1 相比:
      • MMAPv1 基于 MMAP 技术读写磁盘文件。而 WiredTiger 以普通方式读写磁盘文件。
      • MMAPv1 不支持压缩磁盘文件。而 WiredTiger 默认会将数据压缩之后再存储到磁盘的数据文件 collection-xx.wt 中,因此占用磁盘空间大幅减少。
      • MMAPv1 数据库锁的最小单位为 collection 。而 WiredTiger 最小锁单位为 document 。
    • 默认基于 B+ tree 存储数据并进行索引。
      • 也可改用 LSM Tree ,增加写入速度,降低读取速度。
    • 从 MongoDB v3.6 开始,WiredTiger 每隔一定时间会将内存中的写操作数据存储到磁盘(而不是发生一次写操作就立即存储),建立一个快照,称为检查点(checkpoint)。
      • 在两个 checkpoint 之间,采用 journal 预写日志来临时记录数据库的所有写操作,相当于增量备份。
      • 如果 mongod 异常退出,重启时会自动回滚到上一个 checkpoint ,并使用预写日志来恢复数据。
      • 默认每隔 60s ,或累计写入 2G 预写日志时,就创建一个新的 checkpoint ,并删除旧的 checkpoint 、预写日志。
    • 删除集合中的文档时,只是给该文档及其索引条目加上 deleted 标记,并不会实际释放磁盘空间,而是留给该集合以后写入新文档。
      • 缺点:deleted 的空间如果一直未写入新文档,则浪费了磁盘空间。而且按块读取文件数据时,deleted 文档容易跟正常文档混合在一起被读取,浪费内存空间。
      • 直接删除集合时,才会实际释放磁盘空间、删除所有 index 。
      • 为了清理磁盘空间,可以将原集合 copy 到一个新集合,然后将原集合 drop ,最后将新集合 rename 为原集合。
      • 可以执行 db.runCommand({compact:'<collection>'}) ,整理一个集合的碎片空间。
        • 它的原理是将集合的数据拷贝一份,重新写入磁盘,然后重建索引,因此需要事先留出一倍空闲的磁盘空间。
        • 在 MongoDB v4.4 之前,执行 compact 命令时,会阻塞当前数据库的所有 CRUD 操作。从 MongoDB v4.4 开始,只会阻塞当前集合的 drop()、createIndex()、dropIndex() 操作。
        • 在副本集中,Secondary 节点并不会同步该命令,因此需要到每个节点执行该命令。

# 访问控制

# 身份认证

  • MongoDB 默认没有启用身份认证,可按以下步骤启用:
    1. 进入 MongoDB 终端,创建一个管理员用户:
      use admin
      db.createUser(
        {
          user: 'root',
          pwd: '******',
          roles: [{role: 'root', db: 'admin'}]
        }
      )
      
    2. 退出 MongoDB 终端,执行 mongod --auth 重启 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 集合中存储了所有用户的信息,包括用户名、密钥、所属数据库、分配的角色。
    • 每个用户登录时,除了输入密码,还需要指定所属的数据库进行身份认证。
  • 普通数据库定义了以下角色:
    • read :可以读取数据库
    • readWrite :可以读写数据库
    • dbAdmin :可以管理数据库
    • userAdmin :可以管理用户
  • admin 数据库定义了以下角色:
    • readAnyDatabase
    • readWriteAnyDatabase
    • dbAdminAnyDatabase
    • userAdminAnyDatabase
    • clusterAdmin :可以管理副本集
    • root :超级管理员,拥有所有权限
      • root 用户登录时依然只能指定 admin 数据库进行验证。
  • 例:
    // 显示当前数据库的所有用户
    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'}])