Как управлять соединениями MongoDB в узле.веб-приложение js?


Я использую node-mongodb-native драйвер с MongoDB для написания веб-сайта.

У меня есть несколько вопросов о том, как управлять соединениями:

  1. достаточно ли использовать только одно соединение MongoDB для всех запросов? Есть ли проблемы с производительностью? Если нет, можно ли настроить глобальное соединение для использования во всем приложении?

  2. Если нет, то хорошо ли, если я открою новое соединение при поступлении запроса и закрою его, когда обрабатывается запрос? Дорого ли открывать и закрывать соединение?

  3. должен ли я использовать глобальный пул соединений? Я слышал, что у драйвера есть собственный пул соединений. Это хороший выбор?

  4. Если я использую пул соединений, сколько соединений должно быть использовано?

  5. есть ли другие вещи, которые я должен заметить?

10 216

10 ответов:

основной коммиттер для узла-mongodb-native говорит:

вы открываете do MongoClient.подключение один раз, когда ваше приложение загружается и повторно использовать объект БД. Это не одноэлементный пул соединений каждый .соединять создает новый пул соединений.

Итак, чтобы ответить на ваш вопрос напрямую, повторно используйте объект db, который является результатом MongoClient.связываться.)( Это дает вам объединение, и обеспечит заметное увеличение скорости по сравнению с открытие / закрытие соединений при каждом действии БД.

откройте новое соединение, когда узел.приложение js запускается и повторно использует существующий db подключение объекта:

/server.js

import express from 'express';
import Promise from 'bluebird';
import logger from 'winston';
import { MongoClient } from 'mongodb';
import config from './config';
import usersRestApi from './api/users';

const app = express();

app.use('/api/users', usersRestApi);

app.get('/', (req, res) => {
  res.send('Hello World');
});

// Create a MongoDB connection pool and start the application
// after the database connection is ready
MongoClient.connect(config.database.url, { promiseLibrary: Promise }, (err, db) => {
  if (err) {
    logger.warn(`Failed to connect to the database. ${err.stack}`);
  }
  app.locals.db = db;
  app.listen(config.port, () => {
    logger.info(`Node.js app is listening at http://localhost:${config.port}`);
  });
});

/api/users.js

import { Router } from 'express';
import { ObjectID } from 'mongodb';

const router = new Router();

router.get('/:id', async (req, res, next) => {
  try {
    const db = req.app.locals.db;
    const id = new ObjectID(req.params.id);
    const user = await db.collection('user').findOne({ _id: id }, {
      email: 1,
      firstName: 1,
      lastName: 1
    });

    if (user) {
      user.id = req.params.id;
      res.send(user);
    } else {
      res.sendStatus(404);
    }
  } catch (err) {
    next(err);
  }
});

export default router;

источник: как открыть соединения с базой данных в узле.js / Express App

вот код, который будет управлять вашими соединениями MongoDB.

var MongoClient = require('mongodb').MongoClient;
var url = require("../config.json")["MongoDBURL"]

var option = {
  db:{
    numberOfRetries : 5
  },
  server: {
    auto_reconnect: true,
    poolSize : 40,
    socketOptions: {
        connectTimeoutMS: 500
    }
  },
  replSet: {},
  mongos: {}
};

function MongoPool(){}

var p_db;

function initPool(cb){
  MongoClient.connect(url, option, function(err, db) {
    if (err) throw err;

    p_db = db;
    if(cb && typeof(cb) == 'function')
        cb(p_db);
  });
  return MongoPool;
}

MongoPool.initPool = initPool;

function getInstance(cb){
  if(!p_db){
    initPool(cb)
  }
  else{
    if(cb && typeof(cb) == 'function')
      cb(p_db);
  }
}
MongoPool.getInstance = getInstance;

module.exports = MongoPool;

при запуске сервера, вызов initPool

require("mongo-pool").initPool();

затем в любом другом модуле вы можете сделать следующее:

var MongoPool = require("mongo-pool");
MongoPool.getInstance(function (db){
    // Query your MongoDB database.
});

это основано на документация MongoDB. Взгляните на него.

Если у вас есть экспресс.JS, вы можете использовать express-mongo-db для кэширования и совместного использования соединения MongoDB между запросами без пула (поскольку принятый ответ говорит, что это правильный способ совместного использования соединения).

Если нет-вы можете посмотреть его исходный код и использовать его в другой структуре.

управление пулами соединений mongo в одном автономном модуле. Такой подход дает два преимущества. Во-первых, он сохраняет ваш код модульным и легче тестировать. Во-вторых, вы не вынуждены смешивать подключение к базе данных в объекте запроса, который не является местом для объекта подключения к базе данных. (Учитывая природу JavaScript, я бы счел очень опасным смешивать что-либо с объектом, построенным с помощью кода библиотеки). Так что вам нужно только рассмотреть модуль, который экспортирует два метода. connect = () => Promise и get = () => dbConnectionObject.

С таким модулем вы можете сначала подключиться к базе данных

// runs in boot.js or what ever file your application starts with
const db = require('./myAwesomeDbModule');
db.connect()
    .then(() => console.log('database connected'))
    .then(() => bootMyApplication())
    .catch((e) => {
        console.error(e);
        // Always hard exit on a database connection error
        process.exit(1);
    });

когда в полете ваше приложение может просто позвонить get() когда ему нужно подключение к БД.

const db = require('./myAwesomeDbModule');
db.get().find(...)... // I have excluded code here to keep the example  simple

если вы настроите свой модуль БД таким же образом, как показано ниже, у вас не только будет способ гарантировать, что ваше приложение не будет загружаться, если у вас нет подключения к базе данных, у вас также есть глобальный способ доступа к пулу соединений с базой данных, который будет ошибка, если у вас нет подключения.

// myAwesomeDbModule.js
let connection = null;

module.exports.connect = () => new Promise((resolve, reject) => {
    MongoClient.connect(url, option, function(err, db) {
        if (err) { reject(err); return; };
        resolve(db);
        connection = db;
    });
});

module.exports.get = () => {
    if(!connection) {
        throw new Error('Call connect first!');
    }

    return connection;
}

Я использую generic-pool с подключениями redis в своем приложении-я очень рекомендую его. Его общий и я определенно знаю, что он работает с mysql, поэтому я не думаю, что у вас будут какие-либо проблемы с ним и mongo

https://github.com/coopernurse/node-pool

http://mongoosejs.com/docs/api.html

проверьте источник Мангуста. Они открывают соединение и привязывают его к объекту модели, поэтому, когда требуется объект модели, соединение выполняется с БД. Драйвер заботится о пуле соединений.

вы должны создать соединение как сервис, а затем использовать его при необходимости.

// db.service.js
import { MongoClient } from "mongodb";
import database from "../config/database";

const dbService = {
  db: undefined,
  connect: callback => {
    MongoClient.connect(database.uri, function(err, data) {
      if (err) {
        MongoClient.close();
        callback(err);
      }
      dbService.db = data;
      console.log("Connected to database");
      callback(null);
    });
  }
};

export default dbService;

Мои приложения.образец Яш

// App Start
dbService.connect(err => {
  if (err) {
    console.log("Error: ", err);
    process.exit(1);
  }

  server.listen(config.port, () => {
    console.log(`Api runnning at ${config.port}`);
  });
});

и использовать его везде, где вы хотите с

import dbService from "db.service.js"
const db = dbService.db

я реализовал ниже код в моем проекте для реализации пула соединений в моем коде, чтобы он создал минимальное соединение в моем проекте и повторно использовал доступное соединение

/* Mongo.js*/

var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/yourdatabasename"; 
var assert = require('assert');

var connection=[];
// Create the database connection
establishConnection = function(callback){

                MongoClient.connect(url, { poolSize: 10 },function(err, db) {
                    assert.equal(null, err);

                        connection = db
                        if(typeof callback === 'function' && callback())
                            callback(connection)

                    }

                )



}

function getconnection(){
    return connection
}

module.exports = {

    establishConnection:establishConnection,
    getconnection:getconnection
}

/*app.js*/
// establish one connection with all other routes will use.
var db = require('./routes/mongo')

db.establishConnection();

//you can also call with callback if you wanna create any collection at starting
/*
db.establishConnection(function(conn){
  conn.createCollection("collectionName", function(err, res) {
    if (err) throw err;
    console.log("Collection created!");
  });
};
*/

// anyother route.js

var db = require('./mongo')

router.get('/', function(req, res, next) {
    var connection = db.getconnection()
    res.send("Hello");

});

лучший подход к реализации пула соединений заключается в том, что вы должны создать одну переменную глобального массива, которая содержит имя БД с объектом соединения, возвращенным MongoClient, а затем повторно использовать это соединение всякий раз, когда вам нужно связаться с базой данных.

  1. на сервере.js определяет var global.dbconnections = [];

  2. создать службу именования connectionService.js. Он будет иметь 2 метода getConnection и createConnection. Поэтому, когда пользователь будет звонить метод getconnection(), это позволит найти деталь в глобальной связи переменным и обратным соединением деталей, если уже существует, то он будет звонить параметр "createconnection" () и обратного соединения деталей.

  3. вызовите эту службу, используя db_name, и она вернет объект соединения, если у него уже есть другое, он создаст новое соединение и вернет его вам.

надеюсь, что это помогает :)

вот connectionService.код js:

var mongo = require('mongoskin');
var mongodb = require('mongodb');
var Q = require('q');
var service = {};
service.getConnection = getConnection ;
module.exports = service;

function getConnection(appDB){
    var deferred = Q.defer();
    var connectionDetails=global.dbconnections.find(item=>item.appDB==appDB)

    if(connectionDetails){deferred.resolve(connectionDetails.connection);
    }else{createConnection(appDB).then(function(connectionDetails){
            deferred.resolve(connectionDetails);})
    }
    return deferred.promise;
}

function createConnection(appDB){
    var deferred = Q.defer();
    mongodb.MongoClient.connect(connectionServer + appDB, (err,database)=> 
    {
        if(err) deferred.reject(err.name + ': ' + err.message);
        global.dbconnections.push({appDB: appDB,  connection: database});
        deferred.resolve(database);
    })
     return deferred.promise;
}