Spring Boot vs Ktor

포비·2025년 10월 8일

코틀린

목록 보기
5/7
post-thumbnail

들어가며

Kotlin으로 백엔드를 개발하려는 순간, 가장 먼저 마주하는 질문이 있습니다.

"Spring Boot를 쓸까, Ktor를 쓸까?"

이 글에서는 두 프레임워크를 다각도로 비교하고, 실제 코드 예제를 통해 어떤 것을 선택해야 하는지 알아보겠습니다.
요즘 전자정부표준프레임워크가 개편되니 마니 하길래 써봅니다.


1. 개요

Spring Boot

  • 개발사: Pivotal (현재 VMware)
  • 첫 릴리즈: 2014년
  • 언어: Java 기반, Kotlin 공식 지원
  • 철학: "Convention over Configuration"
  • 생태계: 매우 방대함
  • 사용 기업: Netflix, Uber, Airbnb, 대부분의 대기업

Ktor

  • 개발사: JetBrains
  • 첫 릴리즈: 2018년
  • 언어: Kotlin 네이티브
  • 철학: "Lightweight & Flexible"
  • 생태계: 성장 중
  • 사용 기업: JetBrains 내부, 스타트업 중심

2. 철학의 차이

Spring Boot: "모든 것이 준비되어 있다"

Spring Boot는 전통적인 엔터프라이즈 애플리케이션을 위해 설계되었습니다. 모든 기능이 이미 구현되어 있고, 설정만 하면 됩니다.

특징

  • Auto-configuration (자동 설정)
  • Starter dependencies (스타터 의존성)
  • Opinionated defaults (의견이 반영된 기본값)
  • Production-ready features (프로덕션 준비 기능들)

Ktor: "필요한 것만 골라 쓴다"

Ktor는 가볍고 유연한 프레임워크를 지향합니다. 필요한 기능만 선택적으로 추가할 수 있습니다.

특징

  • Minimalistic core (미니멀한 코어)
  • Feature-based (기능 기반 아키텍처)
  • Coroutines first (코루틴 우선)
  • DSL-based configuration (DSL 기반 설정)

3. Hello World 비교

Spring Boot

@SpringBootApplication
class Application

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}

@RestController
class HelloController {
    @GetMapping("/hello")
    fun hello(): String {
        return "Hello, Spring Boot!"
    }
}

Ktor

fun main() {
    embeddedServer(Netty, port = 8080) {
        routing {
            get("/hello") {
                call.respondText("Hello, Ktor!")
            }
        }
    }.start(wait = true)
}

첫인상

  • Spring Boot: 더 많은 보일러플레이트, 어노테이션 기반
  • Ktor: 더 간결한 코드, DSL 기반

4. REST API 비교

Spring Boot

@Entity
data class User(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,
    var name: String,
    var email: String
)

@Repository
interface UserRepository : JpaRepository<User, Long>

@Service
class UserService(private val userRepository: UserRepository) {
    fun createUser(request: CreateUserRequest): User {
        return userRepository.save(User(name = request.name, email = request.email))
    }
    
    fun getUser(id: Long): User? = userRepository.findById(id).orElse(null)
}

@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {
    @PostMapping
    fun createUser(@RequestBody request: CreateUserRequest): ResponseEntity<User> {
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.createUser(request))
    }
    
    @GetMapping("/{id}")
    fun getUser(@PathVariable id: Long): ResponseEntity<User> {
        return userService.getUser(id)?.let { ResponseEntity.ok(it) }
            ?: ResponseEntity.notFound().build()
    }
}

Ktor

data class User(val id: Long, val name: String, val email: String)

object UserRepository {
    private val users = mutableMapOf<Long, User>()
    private var nextId = 1L
    
    fun create(name: String, email: String): User {
        val user = User(nextId++, name, email)
        users[user.id] = user
        return user
    }
    
    fun findById(id: Long): User? = users[id]
}

fun Application.configureRouting() {
    routing {
        route("/api/users") {
            post {
                val request = call.receive<CreateUserRequest>()
                val user = UserRepository.create(request.name, request.email)
                call.respond(HttpStatusCode.Created, user)
            }
            
            get("/{id}") {
                val id = call.parameters["id"]?.toLongOrNull()
                    ?: return@get call.respond(HttpStatusCode.BadRequest)
                
                val user = UserRepository.findById(id)
                    ?: return@get call.respond(HttpStatusCode.NotFound)
                
                call.respond(user)
            }
        }
    }
}

차이점

  • Spring Boot: 레이어가 명확히 분리됨 (Controller → Service → Repository)
  • Ktor: 더 플랫한 구조, 자유로운 구성

5. 비동기 처리

Spring Boot (Coroutines)

@Service
class UserService(private val externalApiClient: ExternalApiClient) {
    suspend fun getUserWithDetails(id: Long): UserDetails = coroutineScope {
        val user = async { userRepository.findById(id) }
        val orders = async { externalApiClient.getOrders(id) }
        val reviews = async { externalApiClient.getReviews(id) }
        
        UserDetails(user.await(), orders.await(), reviews.await())
    }
}

Ktor (Coroutines 네이티브)

suspend fun getUserWithDetails(id: Long): UserDetails = coroutineScope {
    val user = async { userRepository.findById(id) }
    val orders = async { externalApiClient.getOrders(id) }
    val reviews = async { externalApiClient.getReviews(id) }
    
    UserDetails(user.await(), orders.await(), reviews.await())
}

차이점

  • Spring Boot: Coroutines를 지원하지만 추가 설정 필요
  • Ktor: Coroutines가 기본 내장, 자연스러운 통합

6. 성능 비교

메모리 사용량

Spring Boot

  • 시작 시: 200-300MB
  • 많은 자동 설정과 빈 초기화
  • 큰 애플리케이션에 적합

Ktor

  • 시작 시: 50-100MB
  • 필요한 것만 로드
  • 마이크로서비스에 적합

시작 시간

Spring Boot

  • 일반적으로 2-5초
  • 많은 자동 설정 처리

Ktor

  • 일반적으로 1초 미만
  • 가벼운 초기화

처리 속도

벤치마크 결과 Ktor가 약간 더 빠르지만, 실제 애플리케이션에서는 데이터베이스와 외부 API가 병목이므로 프레임워크 성능 차이는 미미합니다.


7. 생태계와 커뮤니티

Spring Boot

장점

  • 거대한 생태계
  • Spring Data, Spring Security, Spring Cloud 등
  • 수많은 튜토리얼과 Q&A
  • 대부분의 라이브러리가 Spring 통합 지원
  • 엔터프라이즈 지원

관련 프로젝트

  • Spring Data JPA/MongoDB/Redis
  • Spring Security
  • Spring Cloud (마이크로서비스)
  • Spring Batch
  • Spring Integration

Ktor

장점

  • Kotlin 네이티브, 자연스러운 코드
  • 점점 성장하는 커뮤니티
  • JetBrains의 지원

단점

  • 생태계가 작음
  • 엔터프라이즈 기능 부족
  • 튜토리얼과 예제가 상대적으로 적음

8. 장단점 정리

Spring Boot

장점

  • 거대한 생태계와 커뮤니티
  • 엔터프라이즈급 기능들
  • 자동 설정으로 빠른 시작
  • 많은 레퍼런스와 튜토리얼
  • 대부분의 회사에서 사용
  • 취업 시장에서 유리
  • Spring Data, Spring Security 등 강력한 도구들

단점

  • 무겁고 느린 시작 시간
  • 많은 메모리 사용
  • 마법 같은 동작으로 디버깅 어려움
  • Kotlin보다는 Java 중심
  • 배워야 할 것이 많음

Ktor

장점

  • 가볍고 빠름
  • Kotlin 네이티브, 자연스러운 코드
  • Coroutines 완벽 통합
  • 명확하고 이해하기 쉬운 구조
  • 필요한 것만 추가
  • 빠른 개발 사이클

단점

  • 작은 생태계
  • 엔터프라이즈 기능 부족
  • 적은 레퍼런스
  • 모든 것을 직접 구성해야 함
  • 취업 시장에서 불리
  • 팀원 교육이 어려울 수 있음

9. MSA (마이크로서비스 아키텍처) 관점

Spring Boot for MSA

Spring Cloud 생태계

Spring은 마이크로서비스를 위한 완벽한 생태계를 제공합니다.

// Service Discovery (Eureka)
@EnableEurekaClient
@SpringBootApplication
class UserServiceApplication

// API Gateway (Spring Cloud Gateway)
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/api/users/**

// Config Server
@EnableConfigServer
@SpringBootApplication
class ConfigServerApplication

// Circuit Breaker (Resilience4j)
@CircuitBreaker(name = "orderService", fallbackMethod = "fallbackGetOrders")
fun getOrders(userId: Long): List<Order> {
    return orderServiceClient.getOrders(userId)
}

Spring Cloud 기능

  • Service Discovery (Eureka, Consul)
  • API Gateway (Spring Cloud Gateway)
  • Config Server (중앙 설정 관리)
  • Circuit Breaker (Resilience4j)
  • Distributed Tracing (Sleuth, Zipkin)
  • Message Bus (Spring Cloud Stream)

장점

  • 모든 것이 통합되어 있음
  • 검증된 솔루션
  • 대규모 MSA에 적합

단점

  • 각 서비스가 무거움 (200MB+)
  • 복잡한 설정
  • 높은 학습 곡선

Ktor for MSA

경량 마이크로서비스

Ktor는 작고 빠른 마이크로서비스를 만드는 데 최적화되어 있습니다.

// 서비스 A
fun main() {
    embeddedServer(Netty, port = 8081) {
        routing {
            get("/api/users/{id}") {
                val id = call.parameters["id"]?.toLongOrNull()
                    ?: return@get call.respond(HttpStatusCode.BadRequest)
                call.respond(userService.getUser(id))
            }
        }
    }.start(wait = true)
}

// 서비스 B
fun main() {
    embeddedServer(Netty, port = 8082) {
        val client = HttpClient(CIO)
        
        routing {
            get("/api/orders") {
                // 서비스 A 호출
                val users = client.get("http://user-service:8081/api/users")
                call.respond(processOrders(users))
            }
        }
    }.start(wait = true)
}

Ktor + 외부 도구 조합

  • Service Discovery: Consul, etcd
  • API Gateway: Kong, Nginx
  • Config: Kubernetes ConfigMap
  • Monitoring: Prometheus, Grafana
  • Tracing: Jaeger

장점

  • 매우 가벼움 (50MB)
  • 빠른 시작 시간 (1초 미만)
  • 컨테이너 친화적
  • 독립적인 배포

단점

  • 직접 통합해야 함
  • 일관성 유지가 어려움
  • 모니터링/추적 설정 복잡

MSA에서의 추천

대규모 엔터프라이즈 MSA (수십~수백 개 서비스)
Spring Boot + Spring Cloud

이유:

  • 통합된 솔루션으로 관리 용이
  • 표준화된 패턴
  • 팀 온보딩 쉬움
  • 엔터프라이즈 지원

중소규모 MSA (수개~수십 개 서비스)
Ktor + Kubernetes

이유:

  • 리소스 효율적
  • 빠른 배포
  • Kubernetes가 대부분의 MSA 기능 제공
  • 컨테이너 밀도 높음

하이브리드 접근

  • API Gateway, Core Services: Spring Boot
  • Internal Services, Workers: Ktor

10. 현대적인 관점에서의 비교

클라우드 네이티브

Ktor가 유리한 점

  • 가벼운 컨테이너 이미지 (50MB vs 200MB)
  • 빠른 시작 시간 (1초 vs 5초)
  • 낮은 메모리 사용량
  • Serverless/FaaS에 적합

Spring Boot의 대응

  • GraalVM Native Image
  • Spring Native
  • 하지만 여전히 Ktor보다는 무거움

컨테이너 효율성

Ktor

FROM openjdk:11-jre-slim
COPY build/libs/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 최종 이미지: ~100MB
# 시작 시간: <1초
# 메모리: ~50MB

Spring Boot

FROM openjdk:11-jre-slim
COPY build/libs/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 최종 이미지: ~200MB
# 시작 시간: 3-5초
# 메모리: ~200MB

컨테이너 밀도

  • 같은 서버에 Ktor 서비스 2배 더 많이 실행 가능
  • 비용 절감 효과

Kubernetes 환경

Ktor의 장점

  • 빠른 Pod 시작 (Auto-scaling에 유리)
  • 낮은 리소스 요청 (더 많은 복제본)
  • Readiness/Liveness Probe 빠른 응답

Spring Boot Actuator

  • 강력한 Health Check
  • Metrics 자동 노출
  • 하지만 무거움

개발 트렌드

2025년 현재 트렌드

  • Kotlin 채택률 증가
  • 마이크로서비스 보편화
  • Serverless 확산
  • 비용 최적화 중요도 증가

이런 트렌드는 Ktor에 유리하게 작용하고 있습니다.


11. 실제 사용 사례

Spring Boot가 적합한 경우

사례 1: 대기업 금융 시스템

  • 복잡한 보안 요구사항 (Spring Security)
  • 배치 처리 (Spring Batch)
  • 레거시 시스템 통합
  • 감사 로그, 트랜잭션 관리
  • 규제 준수

사례 2: 전통적인 모놀리식구조

  • 여러 도메인이 하나의 애플리케이션
  • JPA로 복잡한 관계 매핑
  • 팀 규모 10명 이상

Ktor가 적합한 경우

사례 1: 스타트업 MVP

  • 빠른 개발 속도
  • 작은 팀 (1-5명)
  • 간단한 REST API
  • 비용 최적화

사례 2: 내부 마이크로서비스

  • 특정 기능만 수행
  • 빠른 응답 시간 필요
  • 단순한 비즈니스 로직
  • 예: 이미지 리사이징 서비스, 알림 서비스

사례 3: Real-time 서비스

  • WebSocket 중심
  • Server-Sent Events
  • 낮은 지연시간 필요

12. 학습 로드맵

Spring Boot 학습 순서

1단계: Spring 기초

  • IoC, DI 개념
  • Bean 라이프사이클
  • Configuration

2단계: Spring Boot 핵심

  • Auto-configuration
  • Starter 사용법
  • Properties 관리

3단계: 데이터 접근

  • Spring Data JPA
  • Repository 패턴
  • Transaction 관리

4단계: 보안

  • Spring Security
  • JWT 인증
  • OAuth2

5단계: MSA

  • Spring Cloud
  • Service Discovery
  • API Gateway

예상 학습 기간: 3-6개월

Ktor 학습 순서

1단계: Kotlin 기초

  • Coroutines
  • Extension Functions
  • DSL

2단계: Ktor 핵심

  • Routing
  • Features
  • Content Negotiation

3단계: 데이터베이스

  • Exposed
  • 또는 직접 JDBC/R2DBC

4단계: 인증

  • JWT 직접 구현
  • 또는 라이브러리 사용

예상 학습 기간: 1-2개월


13. 취업 시장 관점

한국 시장 (2025년 기준)

Spring Boot

  • 채용 공고의 약 80%
  • 대기업, 중견기업 대부분
  • 높은 연봉...?

Ktor

  • 채용 공고의 약 5% 미만
  • 주로 스타트업
  • Kotlin을 강조하는 회사
  • 사실 아예 없음

글로벌 시장

Spring Boot

  • 여전히 주류
  • 엔터프라이즈 시장 장악

Ktor

  • 점진적 증가
  • 특히 유럽 스타트업

커리어 전략

안정적인 커리어
→ Spring Boot 마스터

차별화 전략
→ Spring Boot + Ktor 모두 경험

스타트업 지향
→ Ktor 집중하고 Ktor 어필 겁나 해야함


14. 개인적인 견해

현실적인 선택

제가 실무에서 경험한 바로는, 현재 시점에서 Spring Boot가 여전히 더 현실적인 선택입니다.

이유

1. 생태계의 힘
실무에서는 단순히 REST API만 만드는 게 아닙니다. 보안, 배치 처리, 스케줄링, 모니터링, 로깅 등 수많은 요구사항이 있습니다. Spring Boot는 이 모든 것을 기본 제공하거나 쉽게 통합할 수 있습니다.

2. 팀 협업
혼자 개발하는 것이 아니라 팀으로 일합니다. Spring Boot는 표준화된 구조를 제공하므로 팀원 간 코드 이해가 쉽고, 신입 개발자 온보딩도 수월합니다.

3. 레퍼런스의 중요성
문제가 생겼을 때 검색하면 대부분 해결책이 나옵니다. Ktor는 아직 레퍼런스가 부족해서 시행착오가 많습니다.

4. 취업 시장
현실적으로 대부분의 회사가 Spring을 사용합니다. Ktor만 할 줄 안다면 선택지가 매우 좁아집니다.

하지만 Ktor의 미래는 밝다

1. Kotlin의 성장
Kotlin이 점점 더 많이 채택되면서 Ktor도 함께 성장하고 있습니다.

2. 클라우드 네이티브 시대
컨테이너, 서버리스 환경에서 Ktor의 가벼움은 큰 장점입니다. 비용 측면에서도 유리합니다.

3. 마이크로서비스
작고 빠른 서비스가 필요한 MSA 환경에서 Ktor는 이상적입니다.

나의 추천

초보자라면
→ Spring Boot부터 시작하세요. 취업에도 유리하고, 엔터프라이즈 개발의 전반을 배울 수 있습니다.

Spring Boot를 이미 잘한다면
→ Ktor를 배워보세요. Kotlin을 더 깊게 이해할 수 있고, 차별화 포인트가 됩니다.

스타트업에서 새 프로젝트를 시작한다면
→ Ktor를 고려해보세요. 빠른 개발과 낮은 운영 비용이 장점입니다.

대기업 또는 레거시 시스템이라면
→ Spring Boot가 안전한 선택입니다.

이상적인 시나리오

개인적으로는 하이브리드 접근을 선호합니다.

API Gateway: Spring Boot + Spring Cloud Gateway
Core Business Services: Spring Boot
Internal Microservices: Ktor
Background Workers: Ktor
Real-time Services: Ktor

이렇게 하면 각 프레임워크의 장점을 살릴 수 있습니다.
어차피 MSA가 유행이니 MSA를 잘 써먹어야지요.


15. 최종 결론

Spring Boot를 선택하세요

  • 대규모 엔터프라이즈 애플리케이션
  • 팀 규모가 큰 경우
  • 취업/이직을 고려하는 경우
  • 안정성이 최우선인 경우
  • 복잡한 비즈니스 로직이 많은 경우

Ktor를 선택하세요

  • 마이크로서비스 (특히 내부 서비스)
  • 스타트업 MVP
  • 비용 최적화가 중요한 경우
  • Kotlin을 사랑하는 경우
  • 빠른 개발 속도가 필요한 경우

개인적 결론

2025년 현재는, Spring Boot가 여전히 더 현실적이고 안전한 선택입니다.

하지만 Ktor는 특정 영역에서 명확한 장점이 있고, 점점 성장하고 있습니다.

가장 좋은 전략은 Spring Boot를 메인으로 하되, Ktor도 이해하고 있는 것입니다.

둘 다 경험해보고, 상황에 맞게 선택할 수 있는 능력을 갖추는 것이 최선입니다.


참고 자료

Spring Boot

Ktor

커뮤니티

  • Spring: Stack Overflow, Reddit r/SpringBoot
  • Ktor: Kotlin Slack #ktor, Reddit r/Kotlin
    나도 Ktor한번도 안해봄 그래서 코드는 다 배껴온거임 ㅅㄱ
profile
백이되고 싶은 곰입니다.

2개의 댓글

comment-user-thumbnail
2025년 10월 8일

Ktor을 보니 파이썬의 serverless 프레임워크가 생각납니다.

언어 상관없이 서비스를 작은 규모로 개발하는 것이 트렌드이며, 향후에는 시장을 점유하게 될 것 같네요.

1개의 답글