ktorio / ktor

Framework for quickly creating connected applications in Kotlin with minimal effort
https://ktor.io
Apache License 2.0
12.79k stars 1.04k forks source link

Recommend pattern for microservice communication #1627

Open Aditya94A opened 4 years ago

Aditya94A commented 4 years ago

I have multiple ktor-based microservices, (a central API gateway, payments, notifications, user+auth etc.) all communicating with each other via retrofit API services.

Which means, more often than not, all that my "core service" (which receives API calls from outsides) just forwards it on to the relevant microservice:

    get("path") {
        val q1 = queryParam["q2"]
        val q2 = queryParam["q3"]
        val response = Service.payments.createOrder(user.id, q1, q2)
        call.respondWithResponse(response)
    }

Client calls GET "path", it reaches my core service, but all it does is forward it on to the payments microservice (which is just a retrofit API service). This comes at the cost of unnecessarily unbundling then rebundling query parameters and POST bodies and this also means that the Gson converter is hit three times for the same call. Once, the core service, when it sends off a request to microservice, then when it reaches the microservice, then once again, when it unbundles the response.

Btw, the respondWithResponse() is a little helper method I created to help ferry these retrofit requests back and forth within microservices.

suspend inline fun <reified T> ApplicationCall.respondWithResponse(response: Response<T>): String? {
    return if (response.isSuccessful) {
        val json = response.body()!!.toJson()
        respondWithJson(json)
        json
    } else {
        val body = response.errorBody()?.string()
        if (body == null)
            respondWithError()
        else
            respondWithErrorJson(body)
        null
    }
}

Given the inefficiencies in this way doing this (as I described above), what's the recommended pattern of inter-microservice communication with ktor.

Ideally, what I want is a way to simply "proxy" or tunnel select requests from my central Core service off to the microservice, so there's no unnecessary heavy lifting done by core service.

Is there a way to do this? Or is there some other recommended way to accomplish what I'm trying to do here?

muliyul commented 4 years ago

What you describe is: "blindly* proxy the request onward from the first byte" to be super efficient. Obviously doable in Ktor, I wonder if that's really what you're after.

It seems that an API gateway might fit your needs, but the gateway is a concept and can be implemented in any language/framework you wish (it is a more general case of proxying allowing filtering, authentication etc).

Check out Kuma and Istio as a start.