MongoDB 多租户设计面临意外的插入时间慢

MongoDB multi-tenant design faces unexpected slow insertion time

提问人:Md.Reyad Hossain 提问时间:11/15/2023 最后编辑:Md.Reyad Hossain 更新时间:11/16/2023 访问量:53

问:

我们一直在为我们的业务开发多租户模型,并使用MongoDB为我们的客户处理数据,我们的客户基本上是一些组织,他们的用户使用该系统。

现在,我们有一个单一的应用层(单一应用部署),用于控制或连接到单个集群中的多个数据库。数据库连接的变化发生在应用程序(使用 Node.js 和 Mongoose 构建)层。每个数据库都包含相同的集合,例如 db-00 和 db-01 将具有相同数量的集合,例如用户、business_units、预订、doucment_management、库存......等。

对于进入服务器的每个请求,将执行以下代码以将用户请求连接到相应的数据中心:

const MONGO_URI = < only the cluster url with user and password no /db attached here >
let databaseCluster = {};
const connect = (db) => {
  mongoose.plugin(forceRunValidators);
  return mongoose.createConnection(
    process.env.MONGO_URI + `/${db}?retryWrites=true&w=majority`,
    {
      useNewUrlParser: true,
      useCreateIndex: true,
      useFindAndModify: false,
      useUnifiedTopology: true,
      autoIndex: true,
    }
  );
};

// this function si called once the server starts in the server js file
exports.connectToCluster = () =>
  new Promise(async (resolve, reject) => {
    try {
      let adminConnection = await connect(process.env.ADMIN_DB);
      let tenants = await Tetants(adminConnection).find({});
      databaseCluster = adminConnection;
      console.log("MongoDB admin Connected");
      tenantsMap = tenants;
      resolve("Tenants cached successfully.");
      console.log("Tenants cached successfully");
    } catch (err) {
      console.error(err);
      reject(err);
      // Exit process with failure
      process.exit(1);
    }
  });

exports.getConnectionByTenant = (tenantName) => {
  let connection = null;
  connection = databaseCluster.useDb(tenantName, { useCache: true });
  return connection;
};

每当编译模型时,示例代码如下所示:

const connection = getConnectionByTenant("my_tenant");
const ModelBuilder = (connection) => connection.model("collection_name",modelSchema);
const Model = ModelBuilder(connection);

最后,在数据访问层中,它被用作普通代码,如下所示:

// insert operation
const DataObject = new Model({
  property_1:"some_value",
  ...
}) 
await dataObject.save();

// find operation
const data = await Model.findOne({});

该系统在本地和 Atlas 集群中也能正常工作。它按预期连接到不同的数据库。但是我们遇到了一个有线问题。

问题陈述

当只插入单个数据库时,数据库变得非常慢,例如,假设我们有db_1db_2 db_3插入操作在db_3中变得非常慢,即使几乎没有数据并且插入一个项目大约需要 40 秒。当我们重新启动服务器时,问题会转移到不同的数据库(如db_2,db_3变得正常。我们已经确认,这个问题只发生在一个数据库上,无论我们拥有多少数据库。除了特定的数据库外,所有其他数据库都运行良好。

调查

我也尝试使用以下命令监视mongodb shell中的插入操作,但结果不是很有用。

db.currentOp({
  "op": "insert"
}, true);

它始终以空数组的形式返回。inprog

{ inprog: [],
  ok: 1,
  '$clusterTime': 
   { clusterTime: Timestamp(1, 1700042646),
     signature: 
      { hash: BinData(0, "z5Pv/28gd21JtFpYB0bpQBk+NTc="),
        keyId: NumberLong("7244587175163985926") } },
  operationTime: Timestamp(1, 1700042646) }

谁能在这个问题上提供帮助。

雷亚德

node.js mongodb 猫鼬

评论


答:

0赞 TanThien 11/16/2023 #1

我认为问题来自.useDb 将使用相同的连接池切换到不同的数据库。当您不配置连接池时,问题就在这里,默认情况下是,您的请求需要从许多数据库中保存到许多集合中,这会导致切换速度缓慢和超过 5 个连接。useDb5

最好创建与另一个数据库的不同连接。

function makeNewConnection(uri) {
    const db = mongoose.createConnection(uri, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        serverSelectionTimeoutMS: 300000
    });

    db.on('error', function (error) {
        console.log(`MongoDB :: connection ${this.name} ${JSON.stringify(error)}`);
        db.close().catch(() => console.log(`MongoDB :: failed to close connection ${this.name}`));
    });

    db.on('connected', function () {
        mongoose.set('debug', function (col, method, query, doc) {
            console.log(`MongoDB :: ${this.conn.name} ${col}.${method}(${JSON.stringify(query)},${JSON.stringify(doc)})`);
        });
        console.log(`MongoDB :: connected ${this.name}`);
    });

    db.on('disconnected', function () {
        console.log(`MongoDB :: disconnected ${this.name}`);
    });

    return db;
}

const connection1 = makeNewConnection(mongoConfig.uriConnection1);
const connection2 = makeNewConnection(mongoConfig.uriConnection2);

评论

0赞 Md.Reyad Hossain 11/18/2023
我理解您的解决方案,但如果有 1000 个数据库,服务器不会不知所措吗?内存会是什么样子,因为从这个角度来看,我必须将我的数据库保存在一个对象中并像这样访问它们?MongoDB是否会接受这些连接,因为从文档中可以看出,连接仅限于M10集群的1500个。dbconnections.dbconn_1
0赞 TanThien 11/19/2023
如果将文档大量插入到 1000 数据库(不是 find 或 findAndUpdate),则它受 IOPS 限制,因此内存不是问题。关于连接,必须通过创建对象模型来避免泄漏连接database connection singleton