MongoDB 数据结构

    文档存储使用 BSON, 便于扩展 ( Schemeless )
    BSON 支持多种数据类型,文档头部记录每个元素的 Size,读取时直接 Seek 到指定的点

    DB 模型设计上有两种模式:嵌套 Embedded / 引用 Reference

    引用结构在存储上可以减少冗余,但需要额外查询、且无法确保原子性。两种 Reference 设计

    • Manual Reference:即维护类似外键的 col_id
    • DBRef: { $ref: , $id: , $db: }

    MongoDB 索引

    建立索引前的查询通过全表扫描 ( COLLSCAN ),建立索引后通过索引查找 ( IXSCAN ) 然后读取 ( FETCH ),索引即主要为解决全表扫描带来的开销。MongoDB 采用B树的结构存储索引,加速索引中查询(等值查询 / 范围查询)、更新删除及排序操作。MongoDB 支持对文档中任意字段构建索引,索引类型有

    1. Single Field Index: 单字段索引,能加速对相应字段(文档或嵌套文档)的各种查询请求
    2. Compound Index: 针对多字段联合创建索引,先按第一个字段排序、第一个字段相同按第二个字段排序(字段索引间组成上下层的树形结构)
    3. Multikey Index: 针对数组创建的索引,为每个元素创建一个索引
    4. GeoSpatial Index: 地理位置索引,能高效定位坐标范围

    索引属性

    1. Unique Index: 唯一索引,确保相应字段不会重复,如 _id
    2. TTL Index: 指定文档的过期时间,当存储的文档带有过期时间属性时适用,如日志数据
    3. Partial Index: 部分索引,只对特定条件的文档建立索引
    4. Sparse Index: 稀疏索引,只对存在相应字段的文档建立索引

    索引分析

    # 查看索引大小
    db.collection.totalIndexSize()
    # 查看索引执行策略
    db.collection.find().explain()
    # 查看索引构建的元数据信息
    db.system.indexes.find()
    

    关于 _id: 生成规则 Timestamp(4) + Machine(3) + Pid(3) + Rand(3) 确保分布式的 UUID,可以由 ObjectId("xx").getTimestamp() 读取创建时间(即不需要类似 gmtCreated 字段)

    Morphia 注解:

    • @Indexed 定义单值索引
    • @Indexes 定义复合索引,类级别

    MongoDB 并发控制

    • 两段提交 2PC
    • 读写策略一致性:WriteConcern {w: 1} / ReadConcern (3.2+)

    MongoDB 视图 / 环形集合

    // …


    数据分析

    • Aggregation / MapReduce
    • ETL: 实现 UDF 将 DBObject 转储到 ODPS

    MongoDB 运维

    • 数据备份及恢复 mongodump / mongorestore
    • mongotop
    • Github - bobthecow/Genghis: MongoDB admin app

    ReplicaSet

    MongoDB 复制集 使用多个 Mongo 实例确保高可用,具备 Auto Failover / Auto Recovery

    • 主节点 Primary: 读写节点;主节点可能是动态的(如宕机后重新选主),连 RS 时不要直连主节点
    • 从节点 Secondary: 只读节点;同步主节点所有 OpLog(local DB 中 oplog.rs 表)并顺序执行
    • 投票节点 Arbiter: 无数据存储、且不会被投票升级为主,仅响应心跳和选主请求;顾名思义作用主要为选主仲裁上

    • 最小 ReplicaSet:一主两从,才能实现 FO. 如果两个从节点全挂,主节点降级、不能提供服务
    • 客户端如何连接 Rs:参考 Connection String URI,客户端可以自动检测主备关系并切换到新主
    • ReplicaSet 配置:推荐使用 YAML 定义配置,并开启安全认证

    Rs 问题排查及运维

    • 确认 ReplicaSet 是否故障
      • rs.status()
      • 查看日志中 Rs 相关的记录 tac mongo.log | grep '\bE REPL\b' | less
    • 如何重启 ReplicaSet
      • 从节点可直接重启
      • 主节点:首先逐个重启从节点,降级主 rs.stepDown(),重启之
    • DB 监控方案
      • 主备切换出现时,给出告警
      • 从节点宕机时,给出告警
      • 从节点 optimeDate 落后太多时,给出告警

    Sharding

    MongoDB 分片 使用场景在于存储容量或读写能力受单机限制(高并发读写)

    Mongos 为请求路由,ConfigSrv 存储集群元数据。参考文档 https://yq.aliyun.com/articles/60096

    如何确定 Mongos / Shard 数量(假设容量水位线和负载水位线 0.75)
    
    - 容量场景
        - numberOfShards = N / M / 0.75 (单个 Shard 存储能力为 M,存储总量 M)
        - numberOfMongos = 2+
    - 高并发场景
        - numberOfShards = Q / M / 0.75 (单个 Shard QPS 为 M,总 QPS 为 Q)
        - numberOfMongos = Q / Ms / 0.75(单个 Mongos QPS 为 Ms)
    

    云产品时代,开放给用户只是数据库连接接口,用户不需要关心 HA 和运维。


    Morphia 框架 / MongoDB CRUD

    // …