Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch mongodb databases with sharedb #56

Closed
kapeskittu opened this issue May 1, 2018 · 8 comments
Closed

Switch mongodb databases with sharedb #56

kapeskittu opened this issue May 1, 2018 · 8 comments

Comments

@kapeskittu
Copy link

kapeskittu commented May 1, 2018

How can i switch between multiple mongodbs using sharedb?

We are trying to implement a multi tenant application where transactions should be performed only to the database of country from where user belongs to. We maintaing one database for one country on same mongo server. How does this work with sharedb?

@kanwarkakkar
Copy link

@kapeskittu I am facing the same issue, is there any resolution?

@ericyhwang
Copy link
Contributor

The ShareDB server doesn't directly support reading/writing to different databases, depending on information in the client messages.

I think you could indirectly achieve that by instantiating one ShareDB Backend per database and then registering incoming client connections to the appropriate Backend instance. That'd be faster and cleaner than having to introspect every single message, too.

A quick illustration based off the Counter example:

const backendMap = new Map();
for (const mongoConfig of mongoConfigs) {
  const db = new ShareDBMongo(mongoConfig.url);
  const backend = new ShareDB({db});
  backendMap.set(mongoConfig.countryCode, backend);
}

  // Register WebSocket connection with appropriate Share Backend for the country
  wss.on('connection', function(ws, req) {
    var stream = new WebSocketJSONStream(ws);
    const countryCode = getUserCountryCode(req.getHeader('Cookie'));  // However you determine country
    const backend = backendMap.get(countryCode);
    if (backend) {
      backend.listen(stream);
    } else {
      // error handling
    }
  });

@kapeskittu
Copy link
Author

kapeskittu commented Apr 3, 2019 via email

@kanwarkakkar
Copy link

@ericyhwang isn't shareDb providing multiple DB support?
using

racer.createBackend({
        db: mongo,
        pubsub: pubsub,
        extraDbs: options.extraDbs
      })
    })

While creating racer backend connections?

@alecgibson
Copy link
Contributor

Closing due to inactivity.

@ihsanciftci
Copy link

ihsanciftci commented Aug 31, 2022

Hello. (Sorry for resurrecting an old issue.)
@ericyhwang

a) If we use url for db parameter, sharedb creates new client for each database. That will be a performance penalty. For that reason you suggest to use case b)
b) If we use function for db parameter, sharedb uses our client to create/open the database.

When we implement according to b) case, for 1000 databases, there will be over 5000 connections that is causing mondodb server to be killed.

**
Is it possible to implement sharedb according to c) case?

c) If sharedb were using our db instance (instead of creating the Db instance from our given client), it would be possible to use the same connection pool for entire application.

Does my suggestion sound nice?
**

Mongodb documents about connection pooling:
https://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connection-pooling

"To reduce the number of connection pools created by your application, we recommend calling MongoClient.connect once and reusing the database variable returned by the callback:"

@alecgibson
Copy link
Contributor

@ihsanciftci my first question is why are you running and connecting to 1000 databases? That sounds like a lot.

My second question is if you need to have that many databases, is connecting to them from a single server a sensible and scalable approach? This sounds like you may need to run more backends?

To your question, providing a DB instance might work, but would have at least these issues:

  • maintaining backwards compatibility with older mongodb versions could be tricky
  • I can't quite remember, but this might also cause issues with creating a client for query polling?

At any rate, if this is an issue you want to persue, you're better off opening a new issue please.

@ihsanciftci
Copy link

ihsanciftci commented Sep 1, 2022

Thanks for your reply. @alecgibson
I'm not good at NodeJS but I tried the case (c).
There may be better options.

    if (isLegacyMongoClient(client)) {
        self.mongo = self._mongoClient = client;
    }
    else if(client.s) {
        self.mongo = client;
        self._mongoClient = client.s.client;
        self._dbInstance = true;
    }
    else {
        self.mongo = client.db();
        self._mongoClient = client;
    }
ShareDbMongo.prototype.close = function(callback) {
  if (!callback) {
    callback = function(err) {
      if (err) throw err;
    };
  }
  var self = this;
  this.getDbs(function(err) {
    // Ignore "already closed"
    if (err && err.code === 5101) return callback();
    if (err) return callback(err);
    self.closed = true;
    if(!self._dbInstance) {
      self._mongoClient.close(function(err) {
        if (err) return callback(err);
        if (!self._mongoPollClient) return callback();
        self._mongoPollClient.close(callback);
      });
    }

  });
};

I'm creating 4000 sharedb instances at a rate of 20 instances/seconds, in that case mongodb creates 150 connections.
So the above code looks like running correctly.

my first question is why are you running and connecting to 1000 databases? That sounds like a lot.
In fact, this is one of approaches for a multi-tenant system. Another one is using prefix for collections.
One db per tenant approach provides better isolation over collection approach: less complex security operations etc.

I think mongodb and sharedb can handle over ten thousand databases. I think it depends on websocket performance.

This sounds like you may need to run more backends?

Yes. For example if my one backend handles 10 thousands sharedb instances. 10 server scales to 100 000 sharedb instances.

One MongoDB connection pool can work across multiple databases over a mongodb server. I think this is a modern connection pool.
On the other hand, Postgres community does not have such a connection pool. Each database connection has a separate connection pool. This makes implementing "one database per tenant" approach very hard.

I think ShareDB missed that part of connection reusing. This will enable using Sharedb in SaaS.

  • I can't quite remember, but this might also cause issues with creating a client for query polling?

I did not try the query polling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants