Skip to main content

MongoDB 存储引擎选择与使用

使用 MongoDB 已经有接近三年的时间, 期间自己遇到过的和别人遇到过的问题有很多, 这次整理一下, 希望对后来者能有一些帮助

存储引擎选择

在3.2之后, MongoDB 能选择的存储引擎有三个, 包括官方维护的 mmapv1, wiredtiger 和 facebook 维护的 rocksdb

mmapv1

在2.x 系列中, 能选择的存储引擎只有mmapv1, 这个存储引擎以内存映射为基础, 稳定, 无异常挂掉等情况, 在使用的时候注意以下几点即可:

  • 内存限制: 无, 随着数据的增长, 实例会消耗掉机器所有内存, 不推荐单机多实例
  • 磁盘消耗:
    1. 删除文档, 删除集合均不释放存储到操作系统
    2. 删除文档的空间会被下次写入利用
    3. insert 文档预留的空间只有在 update 增大文档大小时可能有用, 在无 update 以及update 不增大文档大小时关闭空间预留, 参数: padding && padding factor
    4. 因以上几个问题导致的磁盘碎片可以通过 repair 回收, repair 消耗大量资源与至少与数据相等的磁盘空间, 需要离线进行
    5. 删除数据库空间被释放到操作系统
  • 性能: 在数据+索引超过内存大小时会有明显下降, 其他取决于使用场景
  • 磁盘: 随机读写, 推荐使用 ssd 磁盘
  • 稳定性: 良好

wiredtiger

3.0新接入的引擎, 一般情况下性能好于 mmap, 使用时需要注意以下几点:

  • 内存限制: 有参数可以限制存储引擎的内存使用, 无法限制总的数据库内存使用(大多数情况下已经足够)
  • 磁盘消耗: 支持数据压缩, 在存储文本数据时比例可以达到 75% 或者更高, 带来部分额外 cpu 消耗
  • 性能: 官方测试5倍以上性能提升, 没有测过, 供参考
  • 磁盘: 目前没有开放 lsm 方式, 推荐使用 ssd 磁盘
  • 稳定性: 存在挂掉的情况

rocksdb

rocksdb 是 facebook 开发的存储引擎, 底层使用 leveldb, 在 mongodb 开放存储 api 之后, facebook 利用 rocksdb 实现了mongodb 的 api
在功能上, 使用 rocksdb 存储引擎与其他引擎没有区别, 在性能上, rocksdb 存储引擎有自己独特的地方

  • 磁盘: rocksdb 对磁盘的使用均为顺序读写, 在 ssd 与旋转磁盘上性能相近, 推荐使用旋转磁盘
  • 性能: 在旋转磁盘上, rocksdb 引擎有其他两种引擎不可比拟的写入性能, 同时, 读取性能较差, 非常适合写>>读的数据, 如非活跃用户数据, 日志数据等
  • 内存限制: 存储引擎提供了丰富的参数控制
  • 稳定性: 良好

架构选择与注意事项

MongoDB 提供了非常完整, 出色的数据库架构, 包括单机模式, 复制集模式和集群模式

单机模式

在任何情况下都不应在线上数据库使用此模式, 仅推荐在测试环境下使用

复制集模式

MongoDB 的复制集做得非常出色, 多台单机组成复制集之后, 可以自动完成数据同步, 主从节点自动选举, 坏节点屏蔽等逻辑, 并且可以方便得进行节点的添加与删除

复制集模式是单机模式的增强版本, 但是基于以下几点, 不推荐将复制集直接暴露给用户使用:

  • 复制集模式无法对容量进行扩展(对于一个线上使用的数据库, 特别是存储用户数据的数据库来说, 前期的容量估计往往是不靠谱的), 在容量达到单机磁盘瓶颈时, 进行分片需要客户端修改相应的配置, 提高了后期的运维复杂程度
  • 需要向客户端提供多个有效的节点信息(虽然只提供一个有效的节点信息是可行的, 但是在这个节点挂掉之后, 客户端重启之后将不能工作), 略显复杂

另外, 使用复制集时需要注意:

  • 由于主从选举为多数投票, 复制集的总节点数目为奇数比较合适, 不足的节点可以由仲裁节点补齐
  • 仲裁节点虽然不消耗资源, 但是为减少同时故障的发生概率, 不适合同机部署
  • oplog 用来做主从之间数据的同步, 需要设置合适的大小, 后期修改比较复杂, 可以参见
  • 主从延迟: 在复制集中, 有很多情况会导致从库的同步速度无法跟上主库的写入速度, 如果出现主从延迟过高(超过10s 一般不正常), 需要检查:
  • 复制集有多种写入参数(w, j)和读取参数(read preference) 可以控制, 如果使用不当, 会出现疑似数据丢失, 数据不一致等多种情况, 具体可自行 google 每种参数的具体作用

集群模式

集群是 MongoDB 做得非常棒的地方之一, 集群由代理服务器, 数据服务器和配置服务器组成, 对于客户端, 仅提供代理(mongos)信息即可, 与使用单机数据库基本无差异, 对于数据端, 可以简便快捷得进行扩容缩容等操作, 推荐即使前期只有一个分片, 也要按照合适的策略将存储集群化, 方便后期扩容

集群模式使用时要注意以下几点:

  • 片键: MongoDB 使用片键对数据进行分片, 片键的选择非常关键, 通常集群出现的绝大多数问题都与片键的不合理选择有关系, 总体来说, 片键的选择 至少 需要使得目前与之后的数据尽可能平均地分布在所有后端机器上, 具体的策略可以自行 google, 片键选取不合理的例子有有:
    • 自增片键, 新增数据都在同一个分片上, 数据不均衡, 且自动均衡运行频繁, 影响集群性能
    • 基数较少的 key 做片键, 会导致数据块过大, 均衡困难, 扩容困难
    • 与查询无关的 key 做片键, 会导致所有查询在所有后端同时进行, 制约集群性能并增大 mongos 压力
  • 扩容: 由于数据的删除不能及时反映到磁盘容量的节省上, 因此扩容应尽早进行, 在磁盘容量达到99%时, 除了等待磁盘写满服务 down 掉之外, 没有什么好的办法, 因此, 可以设定在磁盘使用超过50%或者按照增长率计算剩余可用时间不足三个月时就进行扩容
  • 功能: 部分聚合运算无法在集群模式下进行
  • 数据重复: 失败的数据均衡会导致部分数据被重复存储, 详情可 googlemongodb 孤立文档, 这种重复会导致 count 数量错误等副作用

部署运维

官方提供的 Ops manager 是很好的工具, 可以完成集群搭建, 部署, 升级, 监控, 备份等大多数操作(使用需要企业版授权), 有需要的可以自行下载试用

监控上, 需要注意的关键数据有:

  • 响应时间: 关注平均响应时间, 关注慢查询
  • 磁盘占用: 注意是否需要扩容
  • mongostat 的所有参数, 异常与否可参考官方文档
  • 节点状态: 监控是否出现状态错误的节点, 防止单点出现

除此之外, 运维需要注意以下几点:

  • 查询与计算分离: 增删改查与聚合运算所需要的时间和资源不在一个数量级, 同一个集群不应该同时提供两种服务, 可以将集群分为在线集群与离线集群, 将功能进行区分
  • 慢查询: 默认情况下, 客户端的断开不会导致运行中的查询终止, 因此在存在慢查询的使用场景中, 会导致慢查询累积导致节点性能越来越差, 在2.6版本之前, 可以通过扫描所有节点的 currentOp, 杀死运行时间长的查询解决, 在2.6版本之后, 推荐所有客户端指定查询超时参数

有其他问题可以在中文社区讨论区提问 提问区

打赏
微信扫一扫支付
微信logo微信扫一扫, 打赏作者吧~