TIL

Kotlin RPC

What is RPC?

local vs rpc

항목 Local Procedure Call (LPC) Remote Procedure Call (RPC)
호출 위치 동일한 프로세스 또는 같은 시스템 내에서 호출됨 네트워크를 통해 다른 시스템(원격 서버)에서 호출됨
통신 방식 메모리 내 함수 호출로 직접 실행 네트워크를 통한 메시지 기반 통신 사용
속도 매우 빠름 (메모리 접근 수준) 상대적으로 느림 (네트워크 지연 발생 가능)
복잡성 단순하고 추가 설정 필요 없음 네트워크 설정, 데이터 직렬화/역직렬화 등 복잡성 존재
의존성 네트워크와 무관 네트워크 상태 및 연결에 의존
오류 처리 로컬 오류만 처리 네트워크 오류, 타임아웃 등 추가적인 오류 처리 필요

RPC struture

Service Stub → RPC Client ←transport→ RPC Server ← Service Implementation

RPC technologies

Kotlinx.rpc

kotlinx.rpc 예제

Service Declration

import kotlinx.rpc.RemoteService
import kotlinx.rpc.annotations.Rpc
import kotlinx.serialization.Serializable

@Rpc
interface OrderPlacement : RemoteService {
	suspend fun placeOrder(orderLines: List<OrderLine>): OrderId
	
	@Serializable
	data class OrderLine(val beverageName: String, val quantity: Int)
}

Service Implementation

// OrderPlacement 구현
class NoOpOrderPlacementProcessor(
	override val coroutineContext: CoroutineContext
) : OrderPlacement {
    override suspend fun placeOrder(orderLines: List<OrderPlacement.OrderLine>): OrderId {
        log.info { "Placing order with $orderLines lines" }
        return OrderId(Uuid.random().toString())
    }
}
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.routing.*
import kotlinx.rpc.krpc.ktor.server.Krpc
import kotlinx.rpc.krpc.ktor.server.rpc
import kotlinx.rpc.krpc.serialization.json.json
import kotlinx.serialization.json.Json

fun main() {
    embeddedServer(Netty, port = SERVER_PORT, host = SERVER_HOST) {
        install(Krpc)
        routing {
            rpc("/order") {
                rpcConfig {
                    serialization { json(Json) }
                }
                registerService<OrderPlacement> { ctx ->
                    NoOpOrderPlacementProcessor(ctx)
                }
            }
        }
    }.start(wait = true)
}

Service Stup

val httpClient = HttpClient {
	install(WebSockets)
	install(Krpc)
}
val stup = httpClient.rpc {
	url {
		host = "localhost"
		port = 8080
		encodedPath = "/order"
	}
	rpcConfig {
		serialization { json() }
	}
}.withService<OrderPlacement>()

val orderLines = listOf(OrderPlacement.OrderLine(beverageName = "ESPRESSO", quantity = 1))
val orderId = stup.placeOrder(orderLines)

Features and Philosophy of kotlinx.rpc

Limitations and future challenges


References