【问题标题】:Mongo db Write orderMongodb 写命令
【发布时间】:2019-11-22 04:14:39
【问题描述】:

这篇文章会很长,如果你是mongo神,无论如何你都想帮助我,我从心底里感谢你。我尽量做到详尽,收集我收集的所有数据。

我在我的 MongoDD 数据库中遇到了一些奇怪的行为,我正在质疑 mongodb 的写入顺序。

我记录了仅在执行时发生的错误,这让我认为我们这里有时间问题,但是请求太慢了,我不明白它是如何在糟糕的情况下发生的

起点:

  • 所有的 ObjectIds 都是 mongo 自动提供的,我从来没有设置它们在我身边
  • 此 objectId 已编入索引(显然)且是唯一的
  • 我使用这些请求 ID 中的时间戳来查询数据库,使用此请求:
    db.getCollection('eventStore').find({
      '_id': {
        '$gt': ObjectId("5d285c784460c502cc66ff9b"),
        '$lte': ObjectId("5d285cf7856cda0266215c77")
      }
    })
  • 此请求的结果随后会使用基本的 Node.js 客户端可能性进行流式传输:
    collection.find({
        '_id': {
          ...(lower ? { '$gt': lower } : {}),
          '$lte': higher
        }
      }).sort({ _id: 1 }).stream({
        transform: (element) => {
          logger.info(`Exiting Get events by range::${JSON.stringify(lower)}::${JSON.stringify(higher)}`)
          logger.info(`Parse event::${JSON.stringify(element)}}`)
          return // PARSED EVENT
        }
      })
  • 此时,我知道.sort({ _id: 1 }) 可能没用,但我还是把它留在这里,以防万一。
  • 请求过程很慢:我查询上限以获取 eventStore 的偏移量,然后是视图的偏移量,然后查询存储以获取这些边界之间的所有事件。
  • mongo 数据样本:
    /* 1 */
    {
        "_id" : ObjectId("5d285cf77f6482027108c15c"),
        "events" : [ 
            // Some events
        ]
    }

    /* 2 */
    {
        "_id" : ObjectId("5d285cf77f6482027108c15d"),
        "events" : [
            // Some events
        ]
    }

    /* 3 */
    {
        "_id" : ObjectId("5d285cf7856cda0266215c77"),
        "events" : [ 
            // Some events
        ]
    }

预期的 Mongo 行为:

  • Mongo 是自行分配 ID,所以我希望当 ID ObjectId("5d285cf7856cda0266215c77") 存储在基础中,所有具有较旧时间戳的 ID 都已安全地存储在基础中。 ==> 无后退
  • ObjectId 中编码的时间戳(当它由 mongo 自己给出时)是它写入并保存在数据库中的时间戳,而不是 Mongo 接收的时间戳。

实际行为(记录在记录器的函数中):

  • 在记录器的函数中只看到了第一个和最后一个 _id
    {"message":"Exiting Get events by range::\"5d285c784460c502cc66ff9b\"::\"5d285cf7856cda0266215c77\"","level":"info","timestamp":"2019-07-12 10:12:07"} 
    {"message":"Parse event::{\"_id\":\"5d285cf77f6482027108c15c\",\"events\":[ // Data ]}}","level":"info","timestamp":"2019-07-12 10:12:07"} 
    {"message":"Exiting Get events by range::\"5d285c784460c502cc66ff9b\"::\"5d285cf7856cda0266215c77\"","level":"info","timestamp":"2019-07-12 10:12:07"} 
    {"message":"Parse event::{\"_id\":\"5d285cf7856cda0266215c77\",\"events\":[ // Data ]}}","level":"info","timestamp":"2019-07-12 10:12:07"}

  • 看起来:
    1. 或者事件 _id: ObjectId("5d285cf77f6482027108c15d") 在调用时不在基数中,但旧的 _id: ObjectId("5d285cf7856cda0266215c77") 是。
    2. 或者我的请求或流在调用时无效(但现在,返回正确答案)
    3. 还有别的吗?

【问题讨论】:

    标签: javascript mongodb


    【解决方案1】:

    Mongo 会自行分配 Id,因此我希望当 ID ObjectId("5d285cf7856cda0266215c77") 存储在 base 中时,所有具有较旧时间戳的 ID 都已安全地存储在 base 中。 ==> 无后退

    Mongo _idsObjectIds 分别是:

    • 一个 4 字节的值,表示自 Unix 纪元以来的秒数,
    • 一个 5 字节的随机值,并且
    • 一个 3 字节的计数器,从一个随机值开始。

    这些通常在应用程序驱动程序代码中生成(在向 mongo 发送数据的服务器上)。

    这意味着:

    1. 网络延迟可能会产生乱序记录
    2. 存在时钟漂移的应用服务器可能会创建乱序记录
    3. 5 字节随机值不一定会在同一秒内向前移动(这可能会创建乱序记录,即使 mongo 正在分配 _ids)
    4. NTP 更新可能会创建乱序记录(即使在 mongo 上——它在更新时钟时也不会造成任何拖尾)
    5. 闰秒可以创建乱序记录

    如果您查看共享的 _id,5d285cf77f6482027108c15d5d285cf7856cda0266215c77 (5d285cf7) 的前 4 个字节(8 个字符)都共享相同的时间戳,因为它们发生在纪元。

    【讨论】:

    • 是的,我注意到两个 _id 在时间上都很接近。但是,我主要关心的是:在基地查询我的事件存储 ID 的顶部和我的视图 ID 的顶部所花费的时间期间,基地似乎没有设法存储发生的事件同一秒。但是,是的,如果ID是在驱动端生成的,就可以这样。我的选择是什么? mongo 有 mongo 自己生成的增量 ID 吗?
    • tutorialspoint.com/mongodb/mongodb_autoincrement_sequence 这样的东西会很棒,但我需要增量和其余部分之间的原子性,我需要它作为服务器端。 IE。我确实需要确保在写入 ID 4 时,ID 1 2 和 3 已存储在数据库中并可访问。
    • 只是检查一下,您是否使用forceServerObjectId 选项(至少在节点中——不确定它在驱动程序中是什么)?对于服务器创建的 _id,您必须处理所有服务器上的网络延迟和时钟漂移
    • 不,我不知道这是一个选项。谢谢你,我会试试的。我只有 1 个 mongo 服务器,并且有许多 Node 进程访问它。如果它是由 mongo 创建的,它至少现在应该能满足我的需求,对吗? (我不知道如果 mongo 在一台服务器上运行,我怎么会有延迟和时钟漂移,但我可能会遗漏一些东西)
    • 听起来应该可以!如果您担心获得每一个事件(比如审计/财务/类似的事情),理论上您仍然需要担心 mongo 服务器上的 NTP 更新会向后移动时间、闰秒和故障转移。但是,实际上,你应该没问题
    猜你喜欢
    • 1970-01-01
    • 2021-08-29
    • 2017-02-26
    • 2021-11-01
    • 2012-08-25
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多