What optimizations for not hitting connection limit in serverless functions?

Hi,

When using serverless functions (lambda), what would be the best practices to ensure not hitting the connection limit?

We currently hit the limit yesterday because of high traffic and our functions being scaled. We have tried to “cache” the mongodb connection, but as serverless goes, it cannot ensure that the cached connection being available for all functions.

We also try to refactor some functions to just open the connection, query some data and then close the connection again, but seeing functions being scaled I can only assume that we will hit the limit again.

We host the functions on Vercel.

Can anyone give any insights or tips how they maybe have handled this or made some optimization to control the connections?

Hi @Mikkel_Damm,

Welcome to MongoDB community!

How do you set your MongoDB drivers on Lambda? Does each lambda has its own connection pool?

Do you limit those connection pools and how?

In general since AWS lambda is like any other server from Atlas perspective it needs to enforce the connection limit on lambda side.

For this reason we encourage customers to explore realm functions and webhooks as realm optimized to not exceed cluster connection with smart internal connection pooling.

Best
Pavel

1 Like

Hi @Mikkel_Damm,

Have you read our best practices guide for Lambda to Atlas:

Especially make sure you set reasonable connection pool limit and do define the MongoDB client connection to the MongoDB server outside the AWS Lambda handler function.

Thanks,
Pavel

Hi @Pavel_Duchovny,

I read the article some time ago and have tried all the practices from that but they only seem to help in a small scale when traffic is more linear.

I have also tried to set the MongoDB connection to outside the handler to reuse the connection, but that only seems to help when there is not so much traffic/load. You can see my connection handler here below:

let cached: Db | null = null;
let cachedClient: MongoClient | null = null;

export const connectDb = async () => {

    if (cached) {
        return cached;
    }

    if (!cachedClient) {
        cachedClient = await MongoClient.connect(process.env.MONGODB as string, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
        });
    }

    cached = cachedClient.db();
    return cached as Db;
}

I also tried to tweak the options sent to the connect method (like poolSize etc.) but that doesn’t seem to help either.

Right now we have made a hotfix by opening the connection and closing it in every endpoint/lambda that we have. But at high peaks we still see some increase in connections.

Currently we are looking at MongoDB Realm but it comes with some not so good tradeoffs. Either we to take our 30+ endpoints and move to Realm functions, OR connect to Realm via the above method and use that for all queries.

Moving all endpoints to Realm functions is a lot of work and would break our monorepo setup.
So currently we are connecting to Realm in the connect method, but our queries is take 3-4x times as long to return the data. And the regions for endpoints, db & realm is the same.

  • So is it bad to open and close the connection in each request? If not, then how can we ensure its really closed afterwards?

  • Is there some optimizations to Realm that i’m missing since our realm.collection('games).find({}) take 4x times as long as db.collection('games').find({}) ?

  • Would you recommend MongoDB for our serverless lambda functions or would it make better sense to use an other database?

Hi @Mikkel_Damm,

Have you considered using http webhooks and call them from your client/lambda code.

https://docs.mongodb.com/realm/services/configure/service-webhooks/

This will allow you to write microservices to fetch your data.

Btw are you query all data or is this for the sake of the test. I would recommend comparing actual application queries.

Best
Pavel

I could potentially use webhooks in Realm and then call them from my lambda functions yes, but that would require me to refactor almost every lambda function to call a webhook. Furthermore I would need to either create webhooks specifically for the intended usecase, or make general webhooks for quering/inserting/updating that could be reused by multiple lambda’s.

If I do the above, then would it decrease my performance in query time?

I have tried to fetch a large collection of documents (like scan) and that took 4 seconds.
But i’m trying with a real case where I have a lambda that gets all documents from a collection - there is only 2 documents and with 5 properties each / very small documents - and that takes around 400 ms.

The same query directly with the normal mongodb driver takes 24 ms.

So i’m wondering if I have setup something wrong with my Realm? Or is that just a penalty of using Realm where data needs to go over HTTP?

Hi @Mikkel_Damm,

I would recommend contacting our support or cloud chat for specific application benchmarking or performance issues.

I would be happy to discuss the architecture can you please share your realm application link?

Best
Pavel

Hey Pavel,

I also have this connection issue while running functions from the Realm UI. I wonder if that smart connection pooling actually works in realm functions.

I even implemented the session start and close for all my request actions inside my functions and the number of connections is still bumping when i run functions multiple times. I didn’t find any other solution in your docs.

Why do i have this issue? How can i fix it?