vapor / fluent-mongo-driver

MongoDB support for Fluent built on MongoKittten.
MIT License
25 stars 11 forks source link

MongoDB driver taking extremely long to query #39

Closed lawrencebensaid closed 8 months ago

lawrencebensaid commented 3 years ago

I am working on a Vapor REST API with a MongoDB instance as Database. We already created most of this API in NodeJS but for reasons I won't go into now we want to rewrite the codebase in Swift/Vapor.

We created a few models and controllers and we just got things set up. Now here's the problem:

It looks like the MongoDB connection is not working as expected. When doing a HTTP request the MongoDB query takes about a minute to return a result. The thing is, we are using the same MongoDB as with the NodeJS API and there the response was instant.

Steps to reproduce

To reproduce just setup a Vapor app with MongoDB driver. Also set up a MongoDB instance. I set up mine in Docker. I tried running with both Xcode and the Vapor CLI

Group.swift

import Fluent
import Vapor

final class Group: Model, Content {

    static let schema = "groups"

    @ID(key: .id) var id: UUID?
    @Field(key: "group_code") var code: String
    @Field(key: "group_name") var name: String

    init() { }

    init(id: UUID? = nil, code: String, name: String) {
        self.id = id
        self.code = code
        self.name = name
    }

}

Environment

0xTim commented 3 years ago

@lawrencebensaid which MongoDB integration are you using, the Fluent one? What does your query look like and what does your code/models look like? Additionally, which version of Swift are you using and are you compiling with release or debug mode? Is there any in the logs if you set it to verbose mode?

lawrencebensaid commented 3 years ago

So I figured out what is going on here. It looks like its not the query that is taking long but rather the authentication with the MongoDB instance. So the wait is only the first time a mongo request is fired because that is when the authentication takes place it looks like. Too bad Vapor can't like reload because this adds a lot of time to the development of our newly created project :/

0xTim commented 3 years ago

Migrating to the MongoDB repository as this is where the error is. @Joannis is a minute expected for authentication?

Joannis commented 3 years ago

Hello @lawrencebensaid and @0xTim, the MongoDB driver's main weak point at the moment is the authentication on DEBUG configurations. This implementation can and should be optimised more for development for sure, although 1 minute is like an incredibly slo. On my macbook it takes about 10 seconds during debug builds.

Joannis commented 3 years ago

@lawrencebensaid I'm assuming your server is using either SCRAM-SHA-1 or (more likely) SCRAM-SHA-256 for authentication, is this correct?

Joannis commented 3 years ago

After digging around a bit I can definitely see where the gap between debug and release builds are coming from. Swift is unable to optimise even the most basic bits of code on debug. For example:

for i in 0..<80 { .. }

This bit of code shouldn't be slow, ever. Swift (on release) knows you're just trying to write the following code in a simple way:

var i = 0
while i < 80 {
  ..
  i += 1
}

But what Swift seems to do is:

var range = Range(uncheckedBounds: (lower: 0, upper: 80))
var iterator = range.makeIterator()

while let i = iterator.next() {
  ..
}

Since it's quite a critical piece of code, not by any means high level, I've managed to optimise this specific use case manually in the driver for a gain of ~10% less time. But that's about as much as I'm able to do, because Swift seems to generate pretty ridiculous instructions for the PBKDF2 implementations and the hashes. With some tinkering I think I can get it down another 25% from here, but if you're experiencing 1 minute authentication times I realistically won't be able to get it under 30 seconds unless you compile for release.

@gwynne how does Postgres handle this? It also uses PBKDF2 for SCRAM, right?

Joannis commented 8 months ago

This was fixed in a PBKDF2 PR by Gwynne