MongoDB 更新插入在锁定时不会更新

mongodb upsert doesn't update if locked

本文关键字:更新 定时 插入 MongoDB 锁定      更新时间:2023-10-16

我有一个用C++编写的应用程序,有16个线程,从wireshark/tshark的输出中读取。Wireshark/tshark剖析pcap文件,这些文件gsm_map信令捕获。

Mongodb 是 2.6.7

我的文档所需的结构是这样的:

注意"数据包"是一个数组,稍后会很明显为什么。

对于所有不了解TCAP的人来说,TCAP层是面向事务的,这意味着所有数据包都包括:

  • 事务状态:开始/继续/结束
  • 源交易 ID (otid)
  • 目标交易 ID (dtid)

例如,您可能会看到一个包含 3 个数据包的事务,查看 TCAP 层大致是这样的

两个数据包,一个"

开始",一个"结束"。

{
    "_id" : ObjectId("54ccd186b8ea19c89ee8f231"),
    "deleted" : "0",
    "packet" : {
        "datetime" : ISODate("2015-01-31T12:58:11.939Z"),
        "signallingType" : "M2PA",
        "opc" : "326",
        "dpc" : "6406",
        "transState" : "begin",
        "otid" : "M2PA0400435B",
        "dtid" : "",
        "sccpCalling" : "523332075100",
        "sccpCalled" : "523331466304",
        "operation" : "mo-forwardSM (46)",
        ...
    }
}
/* 1 */
{
    "_id" : ObjectId("54ccd1a1b8ea19c89ee8f7c5"),
    "deleted" : "0",
    "packet" : {
        "datetime" : ISODate("2015-01-31T12:58:16.788Z"),
        "signallingType" : "M2PA",
        "opc" : "6407",
        "dpc" : "326",
        "transState" : "end",
        "otid" : "",
        "dtid" : "M2PA0400435B",
        "sccpCalling" : "523331466304",
        "sccpCalled" : "523332075100",
        "operation" : "Not Found",
        ...
    }
}

由于网络体系结构,我们在两 (2) 个点中进行跟踪,并且流量在这两个点之间平衡。这意味着有时我们在"开始"之前看到"继续"或"结束"。相反,我们可能会在"开始"或"结束"之前看到"继续"。简而言之,交易不是有序的。

此外,多个端点之间在"交谈",事务 ID 可能会重复,2 个端点可能同时使用相同的 tid,其他 2 个端点,尽管这不会一直发生,但它确实会发生。

由于后面的原因,我还需要使用 SCCP 层的"呼叫"和"呼叫"全局标题(如电话号码)。

请记住,我不知道给定数据包的去向,所以这就是我正在做的事情:

  • 每当我收到一个新数据包时,我都必须找到该事务是否已存在于 mongodb 中,我正在使用 upsert 来执行此操作。
    • 我通过在现有数据包的 otid 或 dtid 中搜索当前数据包的数据包 otid 或 dtid 来做到这一点
    • 如果是:将新数据包推送到现有文档中。
    • 如果没有:使用数据包创建一个新文档。

例如,这是一个"结束"的更新插入,应该找到一个"开始":

db.runCommand(
  {
    update: "packets",
    updates: 
      [ 
          { q: 
                  { $and: 
                      [ 
                          { 
                              $or: [ 
                                  { "packet.otid": 
                                      { $in: [ "M2PA042e3918" ] } 
                                  }, 
                                  { "packet.dtid": 
                                      { $in: [ "M2PA042e3918" ] } 
                                  } 
                              ] 
                          }, 
                          { 
                              $or: [ 
                                  { "packet.sccpCalling": 
                                      { $in: [ "523332075151", "523331466305" ] }
                                  }, 
                                  { "packet.sccpCalled": 
                                      { $in: [ "523332075151", "523331466305" ] }
                                  } 
                              ] 
                          } 
                      ] 
                  }, 
              { 
                  $setOnInsert: { 
                      "unique-id": "422984b6-6688-4782-9ba1-852a9fc6db3b", deleted: "0" 
                  }, 
                  $push: { 
                      packet: { 
                          datetime: new Date(1422371239182), 
                          opc: "327", dpc: "6407", 
                          transState: "end", 
                          otid: "", dtid: "M2PA042e3918", sccpCalling: "523332075151", ...  }
                  } 
              }, 
              upsert: true 
          } 
    ], 
    writeConcern: { j: "1" }
  }
)

现在,所有这些都有效,直到我将其投入生产。

似乎数据包正在快速发展,我看到很多:

"客户端光标::静态收益无法解锁递归锁的 B/c"警告我读到我们可以忽略此警告,但我发现我的更新插入不会更新文档!看起来有一个锁,mongodb忘记了更新。如果我将更新插入更改为简单的插入,则不会丢失任何数据包

我也读到这与没有使用索引有关,我有以下索引:

"3" : {
    "v" : 1,
    "key" : {
        "packet.otid" : 1,
        "packet.dtid" : 1,
        "packet.sccpCalling" : 1,
        "packet.sccpCalled" : 1
    },
    "name" : "packet.otid_1_packet.dtid_1_packet.sccpCalling_1_packet.sccpCalled_1",
    "ns" : "tracer.packets"

所以总结一下:

1.- 如果此索引不正确,有人可以帮我创建正确的索引吗?2.- 如果 mongo 找到锁,它不会更新文档是正常的吗?

谢谢和问候!

大卫

为什么要将所有数据包存储在一个数组中?通常在这种情况下,最好将每个数据包单独制作为文档;如果没有有关您的用例的更多信息(或者,也许,对您正在使用的所有这些首字母缩略词有更多的了解:D),就很难说更多。您的更新将成为插入项,您无需执行更新查询。相反,数据包上的其他一些元数据会将相关数据包连接在一起,以便您可以重建事务或需要执行的任何操作。

更直接地解决您的问题,我会使用数组字段tids来存储[otid, dtid],并使用数组字段sccps来存储[sccpCalling, sccpCalled],这将使您的更新查询看起来像

{ "tids" : { "$in" : ["M2PA042e3918"] }, "sccps" : { "$in" : [ "523332075151", "523331466305" ] } }

并适合索引{ "tids" : 1, "sccps" : 1 }