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

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

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

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

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

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

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

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

10 ответов


основной коммиттер для node-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. Взгляните на него.


Если у вас есть Express.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() когда ему нужно соединение DB.

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;
}