Python에서 Java/Kotlin으로의 마이그레이션 사례 분석

Novelike·2025년 4월 16일
1

Tech

목록 보기
1/8
post-thumbnail

최근 몇 년간 대규모 기술 기업들 사이에서 백엔드 언어를 Python에서 Java나 Kotlin으로 전환하는 사례가 늘고 있습니다. 초기 스타트업 단계에서는 개발 생산성이 높은 Python으로 서비스를 구축하는 경우가 많지만, 사용자와 트래픽이 폭증함에 따라 성능과 안정성 문제에 직면하게 됩니다. 이에 따라 성능이 뛰어나고 정적 타이핑을 지원하는 언어(예: Java, Kotlin)로 핵심 시스템을 재구축하거나 마이그레이션하는 결정을 내리는 것입니다. 아래에서는 DoorDash, Uber 등의 구체적인 사례를 중심으로, 마이그레이션 배경, 대상 시스템, 전략, 효과 등을 분석합니다.

DoorDash – Python/Django 모놀리스를 Kotlin 마이크로서비스로 전환

DoorDash는 미국의 대표적인 음식 배달 서비스로, 초창기 백엔드가 Python 2와 Django 기반 모놀리식 구조로 구축되었습니다. 이 모놀리식 코드베이스는 DoorDash 서비스의 급성장과 복잡도 증가를 감당하기 어려워졌습니다. 배포할 때 업데이트해야 하는 노드 수가 너무 많아 배포 시간이 길어졌고, 버그가 발생했을 때 어떤 커밋이 문제인지 이분 탐색(bisecting)으로 찾는 작업도 점점 어려워졌습니다 (Migrating From Python to Kotlin for Our Backend Services) (DoorDash's Migration from Python to Kotlin). 더욱이 Python 2와 Django의 버전이 노후화되어 보안 지원 종료(EOL)를 앞두고 있었던 점도 큰 부담이었습니다 (Migrating From Python to Kotlin for Our Backend Services). 이러한 이유들로 DoorDash 엔지니어들은 모놀리스를 해체(microservices)하고 새로운 기술 스택으로 이전하기로 결정했습니다 (Migrating From Python to Kotlin for Our Backend Services) (DoorDash's Migration from Python to Kotlin).

마이그레이션 대상은 음식 주문 및 배달 관련 핵심 로직 전체로, 기존의 단일 Django 애플리케이션을 여러 마이크로서비스로 분리하는 작업이었습니다. DoorDash는 백엔드에 하나의 언어만 사용하는 일원화 전략을 택했는데, 한 가지 언어로 통일하면:

어떤 언어를 채택할지 결정하기 위해 DoorDash 팀은 여러 후보 언어를 비교했습니다. 새 언어에 요구된 핵심 조건은 다음과 같았습니다 (Migrating From Python to Kotlin for Our Backend Services):

  • 멀티코어 CPU를 효율적으로 활용할 수 있고 확장성이 있을 것 (Python의 GIL 제한 극복)
  • 모니터링 및 관찰성이 용이할 것
  • 풍부한 라이브러리 생태계를 가져 업무 로직 구현에 집중할 수 있을 것
  • 엔지니어 생산성을 높여줄 것 (개발 편의성과 디버깅 용이성)
  • 대규모 서비스에서 검증된 안정성을 제공할 것
  • 미래에도 지속적으로 성장 가능하고 유지보수될 것 (커뮤니티와 업데이트 활성도)

이 기준으로 C++이나 Ruby, PHP, Scala 등도 검토했으나, 성능 확장성이나 인력 확장성(headcount growth) 측면에서 한계를 보여 최종 후보에서 제외되었습니다 (Migrating From Python to Kotlin for Our Backend Services). 최종 후보군에는 Kotlin, Java, Go, Rust, Python 3가 올랐고, 각 언어의 장단점을 면밀히 비교했습니다 (Migrating From Python to Kotlin for Our Backend Services).

DoorDash 팀은 Python 3도 고려했지만, Python은 여전히 런타임 속도가 느리고 (Migrating From Python to Kotlin for Our Backend Services), Global Interpreter Lock(GIL)으로 멀티코어 활용에 제약이 있으며 (Migrating From Python to Kotlin for Our Backend Services), 정적 타입 체크 부재로 대규모 코드베이스에서 런타임 에러를 잡기 어려운 문제가 있다고 평가했습니다 (Migrating From Python to Kotlin for Our Backend Services). 또 Kafka와의 연동 등 특정 분야에서는 라이브러리 지원이 미흡하거나 지연되는 경우도 겪었습니다 (Migrating From Python to Kotlin for Our Backend Services). 반면 KotlinJVM의 방대한 라이브러리 생태계를 활용하면서도 Java보다 간결한 문법과 null-safety 등을 제공하여 개발 생산성을 높여주고, gRPC, HTTP, Kafka, Cassandra, SQL 등 DoorDash가 필요로 한 기술 스택에 대한 1급 지원을 갖추고 있었습니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). 또한 Kotlin은 비동기 코루틴(coroutine)자바에 없는 동시성 프리미티브를 갖추고 있어 고성능 서비스 개발에 유리하다고 판단했습니다 (Migrating From Python to Kotlin for Our Backend Services).

결국 DoorDash는 “더 나은 Java”로 불릴 만한 Kotlin을 새로운 백엔드 주력 언어로 선택했습니다 (Migrating From Python to Kotlin for Our Backend Services). 2020년경부터 Python/Django 모놀리스를 단계적으로 분해하여 Kotlin 기반 마이크로서비스로 전환했고, 서비스 간 통신에는 gRPC, 비동기 메시징에는 Kafka를 도입하며 아키텍처를 현대화했습니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). 또한 LINE이 주도하는 Armeria 프레임워크를 Kotlin과 함께 활용하여 고성능 gRPC 서버를 구현, Python 기반 스택을 성공적으로 대체하였습니다 (Armeria를 소개합니다).

이관 전략으로는 우선 신규 마이크로서비스의 골격(framework)을 표준화하고, Kotlin 도입에 따른 사내 교육베스트 프랙티스 정립에 공을 들였습니다. 대부분의 DoorDash 백엔드 엔지니어들이 Python에 익숙했기에 Kotlin 학습曲선이 존재했지만, 시니어 엔지니어들이 Kotlin 가이드와 코드 스닙핏 예시를 작성하고, 점심 시간에 러닝 세션을 열어 언어 사용법과 IDE 활용법(IntelliJ)을 전파했습니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). 코루틴 등 비동기 패턴의 모범 사례를 공유하고, Kotlin 고유의 함수형 스타일과 불변성 패턴에 익숙해지도록 내부 공유 채널을 통해 지속적으로 질의응답을 했습니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). 이런 노력으로 엔지니어링 조직 전반에 Kotlin 역량을 갖춘 인력 풀을 빠르게 구축할 수 있었습니다 (Migrating From Python to Kotlin for Our Backend Services).

DoorDash의 마이그레이션 결과, 백엔드는 수백 개의 Kotlin 마이크로서비스로 재편되어 서비스별 독립적 배포와 확장이 가능해졌습니다. 배포 속도가 빨라지고 위험성이 낮아졌으며, 한 서비스의 문제로 전체 시스템이 영향을 받는 일이 줄었습니다. 또한 정적 타입 언어의 장점으로 인해 많은 버그가 컴파일 단계에서 발견되고, null 안정성 등의 기능으로 NPE 같은 런타임 에러가 예방되는 효과를 보았습니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). 엔지니어들은 Kotlin의 간결한 문법 덕분에 코드 가독성과 유지보수성이 향상되었다고 보고했고, 새로운 모니터링/메트릭 체계도 Kotlin에 맞춰 개선되어 운영 관리 효율이 높아졌습니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). DoorDash 사례에서 볼 수 있듯이, 성능과 확장성, 개발 생산성을 고루 고려한 선택으로 Python의 한계를 극복하고 향후 성장에 대비한 탄탄한 플랫폼을 마련한 것이 핵심 교훈입니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services).

Uber – 서비스 규모 확대에 따른 Python 단계적 퇴출과 Java/Go 표준화

Uber는 초창기 몇 년 동안 Python과 Node.js로 작성된 모놀리스/마이크로서비스 혼합 구조를 운영했습니다. 예를 들어, 예전 Uber의 백엔드 구조를 보면 “디스패치(Dispatch)”라 불리던 매칭 엔진은 Node.js로, API 서버Python (Twisted/Flask 기반)으로 구현되어 두 개의 거대한 서비스(monolith)가 핵심을 이루었습니다 (Brief History of Scaling Uber). 이처럼 이질적인 이중 모놀리스는 성장 초기에 빠른 개발을 도왔지만, 서비스가 전세계로 확장되고 기능이 복잡해지면서 병목과 유지보수 문제가 심각해졌습니다. Uber 엔지니어링은 2014년경부터 대대적인 아키텍처 재편을 시작하여, 수백 개의 마이크로서비스로 기능을 분리하고 기술 스택 표준화에 나섰습니다 (Brief History of Scaling Uber).

Uber는 수년간의 경험을 통해 백엔드에서는 정적 타입 언어가 필요하다는 교훈을 얻었습니다. 동적 언어인 Python과 Node.js는 개발 속도는 빠르지만 대규모 시스템에서 성능 한계와 타입 오류 문제를 일으켜, Uber는 이를 공식적으로 사용 중단(deprecate)하고 대신 Java와 Go를 주력 백엔드 언어로 채택했습니다 (Brief History of Scaling Uber). Uber의 수석 아키텍트는 “타입 안정성과 높은 성능(type-safety and better performance)을 얻기 위해” Java/Go 위주로 재구축했고, Python과 JavaScript는 백엔드용으로는 지양했다고 밝힙니다 (Brief History of Scaling Uber). 이를 통해 잡다한 언어로 나뉘었던 12,000여 개의 코드 저장소를 핵심 언어 중심으로 정리함으로써, 엔지니어 간 협업을 원활하게 하고 공통 아키텍처 패턴을 적용하기 쉬워졌습니다 (Brief History of Scaling Uber). 한마디로, Uber는 조직적 복잡성을 줄이고 기술 스택을 정돈하여 개발자 생산성시스템 신뢰성을 함께 높이고자 한 것입니다.

구체적인 마이그레이션 대상은 Uber의 실시간 물류 시스템 전반입니다. 매칭 및 디스패치 서비스, 모바일 API 게이트웨이, 데이터 저장소 계층, 결제 및 지원 서비스 등 핵심 컴포넌트들을 순차적으로 재작성하거나 신규 개발했습니다 (Brief History of Scaling Uber) (Brief History of Scaling Uber). 예컨대, 한때 Node.js로 구현되었던 실시간 API 게이트웨이(RTAPI)는 노후화로 인해 2020년에 Edge Gateway란 새로운 시스템으로 교체되었는데, 이 때 기존 JavaScript 코드 대신 Uber 표준에 맞는 Java/Go 기반 계층으로 재구축되었습니다 (Brief History of Scaling Uber) (Brief History of Scaling Uber). 또한 매칭/디스패치 엔진도 차량 종류와 예약, 배차 최적화 등 새로운 요구사항을 반영할 수 있도록 2021년에 아예 Fulfillment Platform을 새로 설계했으며, 이 역시 높은 일관성, 수평 확장성, 낮은 지연시간을 목표로 NewSQL 데이터베이스와 정적 언어 서비스 조합으로 작성되었습니다 (Brief History of Scaling Uber) (Brief History of Scaling Uber). (공개 자료에 구체적인 언어가 명시되진 않았지만, Uber 내부 표준을 고려하면 Java 또는 Go로 구현되었을 가능성이 높습니다.)

Uber의 데이터 파이프라인 사례도 흥미로운데, 워크플로우 스케줄러로 오픈소스 Airflow(Python 기반)를 사용하던 것을 Piper라는 자체 시스템으로 대체하면서 핵심 컴포넌트를 Python에서 Java로 마이그레이션했습니다 (Managing Uber's Data Workflows at Scale | Uber Blog). Piper 초기 버전은 Airflow와 유사하게 동작했지만, 스케줄러가 단일 장애점(SPOF)인 문제와 다중 언어 지원 한계 등이 드러났습니다. Uber는 이를 개선하기 위해 Airflow의 Python DSL은 그대로 유지하되, 백엔드 아키텍처를 분리하여 Python 코드를 직접 로드하지 않아도 되도록 메타데이터만 추출하는 방식을 도입했습니다 (Managing Uber's Data Workflows at Scale | Uber Blog) (Managing Uber's Data Workflows at Scale | Uber Blog). 그런 다음, 스케줄러와 작업 실행기(executor)를 아예 Java로 다시 작성하여, JVM 기반의 고성능 스레드 모델을 활용하도록 만들었습니다 (Managing Uber's Data Workflows at Scale | Uber Blog). 표준화된 Uber 인프라(Mesos 기반 컨테이너 환경)에 맞춰 Java로 구현함으로써 스케줄링 지연을 단축하고 시스템 효율을 높였고 (Managing Uber's Data Workflows at Scale | Uber Blog), 언어 통일 덕분에 Go/Java로 짜인 Uber 마이크로서비스 생태계와도 자연스럽게 연계되었습니다 (Managing Uber's Data Workflows at Scale | Uber Blog). 결과적으로 Piper는 멀티 액티브 스케줄러 구조로 발전해 단일 장애점을 제거하고 노드 추가로 선형 확장이 가능해져, 현재 Uber 내부 수많은 데이터 워크플로우를 안정적으로 처리하고 있습니다 (Managing Uber's Data Workflows at Scale | Uber Blog) (Managing Uber's Data Workflows at Scale | Uber Blog).

Uber의 마이그레이션 과정에서 조직 문화도 변화했습니다. 여러 언어를 병용하면 언어별로 다른 툴체인과 라이브러리를 관리해야 하고, 팀간 코드 공유나 인력 이동 시 추가 학습 비용이 발생합니다. Uber는 이를 해소하기 위해 백엔드 엔지니어링 조직의 언어를 합리적으로 제한했으며, Java/Go 기반의 공통 프레임워크, RPC 인터페이스(Thrift), 모니터링, 로깅 라이브러리 등을 구축해두고 모든 서비스가 이를 따르도록 했습니다 (Brief History of Scaling Uber) (Brief History of Scaling Uber). 그 결과 Uber와 같은 초대형 조직에서도 일관된 개발 패턴이 유지되어, 1000명 이상의 엔지니어가 협업해도 코드 품질과 서비스 안정성을 담보할 수 있게 되었습니다 (Brief History of Scaling Uber) (Brief History of Scaling Uber). 성능 면에서도, 자바 기반으로 전환한 컴포넌트들은 Python 대비 멤모리 관리 효율CPU 멀티스레딩 측면에서 우위를 가져, 서비스 지연시간 감소와 처리량(QPS) 향상 등의 효과를 보았습니다. (예를 들어, Uber는 차량 위치 조회 등 초당 수십만 QPS가 필요한 서비스에 Go/Java를 도입하여 안정적으로 운영하고 있습니다 (Brief History of Scaling Uber) (How We Built Uber Engineering’s Highest Query per Second Service Using Go | Uber Blog).)

요약하면 Uber 사례에서는 “성장을 막는 요소 제거”가 키워드입니다. Python의 GIL 및 동적 타이핑이 빚는 한계를 인지하고,果断하게 주요 백엔드 기술 스택을 정적 타입 언어로 재편함으로써 성능과 개발 속도 사이의 균형을 맞춘 것입니다. Uber의 극단적인 스케일에서는 미세한 비효율도 큰 비용으로 직결되기에, 언어 선택부터 아키텍처까지 철저히 스케일을 견딜 수 있도록 최적화했다고 볼 수 있습니다 (Brief History of Scaling Uber).

Spotify – Python에서 Java 및 다중언어 인프라로의 변화

Spotify는 음악 스트리밍 분야의 거대 기업으로, 초기에는 Python을 광범위하게 사용한 대표 사례입니다. Spotify의 많은 백엔드 서비스가 한때 Python (특히 Django 및 Twisted 프레임워크)을 기반으로 구현되었고, 데이터 파이프라인도 자체 개발한 Luigi라는 Python 기반 배치 작업 오케스트레이션 툴로 관리되었습니다 (Luigi for Data Orchestration: Building Blocks, Capabilities, Setup) (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). Python 덕분에 빠르게 서비스를 출시하고 실험할 수 있었지만, 사용자가 수억 명 단위로 늘어나자 대응 처리량 향상과 시스템 최적화가 중요 과제가 되었습니다. 이에 Spotify는 성능과 유지보수성 측면에서 Java 등의 정적 언어 활용을 점차 확대했습니다. 실제 Spotify 엔지니어의 언급에 따르면, “Java는 우리가 더 높은 성능을 내기 쉽게 해준다. Python으로 15백만 유료 사용자 규모에서 성능을 끌어올리는 것은 완전히 다른 문제”라고 하며, Python 코드 최적화의 어려움을 토로했습니다 (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium). 반면 JVM(Java 가상머신)은 매우 빠르고 검증된 플랫폼이라서, 대용량 트래픽 처리에 유리하고 엔터프라이즈급 안정성을 보장한다는 점을 강조했습니다 (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium). 이처럼 Spotify 백엔드의 주력 언어는 점진적으로 Java로 옮겨갔고, 새로운 서비스 개발 시에도 JVM 계열 언어(예: Scala, Kotlin, Clojure 등)가 적극 도입되었습니다 (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium). Java 자체에 대해 호불호는 있을 수 있어도, “모든 경험 있는 프로그래머들이 큰 학습 없이도 바로 투입될 수 있는 익숙한 언어”라는 점에서 대규모 엔지니어 채용과 협업에 유리하다는 현실적인 이유도 있었습니다 (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium). (실제로 Spotify는 성숙한 조직으로 성장하며 전통적인 Java 엔지니어들도 다수 합류하게 되었고, Python만 고집할 이유가 줄어들었습니다.)

특히 데이터 분석/머신러닝 파이프라인 분야에서의 변화가 두드러집니다. Spotify는 한때 거의 모든 배치 작업을 Luigi(Python)로 스케줄링 했지만, 파이프라인 수가 2만 개 이상으로 폭증하고 300여 개 팀이 각기 파이프라인을 운영하게 되면서 Luigi의 한계를 느꼈습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). Luigi는 Python 기반이라 Python 외 언어로 작성된 작업(예: Scala/Spark 작업이나 Java Hadoop 잡 등)을 직접 지원하지 못했고, 그래서 별도로 Java로 된 오케스트레이션 시스템(Flo라는 프레임워크)도 병행해서 써야 했습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). 한 회사에서 두 가지 워크플로 엔진(Python용, Java용)을 유지보수해야 하니 동일한 기능을 중복 개발해야 하고 운영 복잡도가 크게 증가했습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). 또한 Luigi 자체도 클라이언트 사이드 프레임워크라 확장성과 관측성이 제한되고, 여러 언어로 구성된 현대적인 파이프라인 요구를 충족시키기 어려웠습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows).

이런 배경에서 Spotify는 2020년대에 들어 Luigi를 대체할 차세대 워크플로 플랫폼으로 Lyft가 오픈소스화한 Flyte를 도입하기로 결정했습니다 (DATA Pill #023 - we are moving to GitHub, CFO's are ... - LinkedIn). Flyte는 Airflow나 Luigi와 달리 Kubernetes 기반의 분산 오케스트레이션 플랫폼으로, 프로토콜 버퍼 gRPC 인터페이스로 언어 불문 백엔드와 통신하기 때문에 다양한 언어로 SDK 구현이 가능합니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). 덕분에 한 파이프라인에서 Python 작업과 Java/Scala 작업을 혼합하여 사용할 수 있고, 새로운 기능도 한 번만 개발하면 여러 언어에 공통으로 제공될 수 있습니다. Spotify가 겪었던 Luigi의 문제점 (업데이트 전파 어려움, 의존성 충돌, 파이프라인 내부 가시성 부족, 확장 한계 등)도 Flyte 도입으로 상당 부분 해결되었습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows) (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows) (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). 특히 “Luigi는 Python만 지원하고, Spotify는 Java 작업이 빈번히 필요하다”는 가장 큰 애로사항을 Flyte가 없애주었고 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows), 모든 작업을 컨테이너화하여 격리함으로써 라이브러리 충돌 없이 확장할 수 있게 했습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows).

현재 Spotify는 수천 개의 워크플로우를 Flyte로 이관 완료했고, 최종적으로 회사 내 전부 20,000개 이상의 데이터 파이프라인을 완전히 Flyte 기반으로 옮기는 것이 목표입니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows). Luigi는 더 이상 적극 유지보수되지 않으며, Spotify 내부에서도 사실상 사용을 줄이고 있는 추세입니다 (Luigi for Data Orchestration: Building Blocks, Capabilities, Setup). 백엔드 서비스 측면에서도, 새로 만드는 대규모 서비스는 Python보다는 JVM 계열 언어를 주로 선택하고 있어 언어 스택이 다변화되었습니다. 다만 Python 자체도 완전히 퇴출된 것은 아니어서, 여전히 데이터 사이언스, 자동화 스크립트, 프로토타이핑 등에는 Python을 활용하고 있습니다 (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium). 즉, Spotify의 접근법은 핵심 트래픽 경로에는 최적화된 언어를 쓰고, Python은 적재적소에 활용하는 것으로 볼 수 있습니다.

Spotify 사례의 핵심 포인트는 “필요에 따라 옳은 도구를 선택”하는 유연성입니다. 서비스 초기에는 Python의 민첩성을 활용했고, 성장 후에는 Java의 성능과 견고함을 받아들여 리팩토링했으며, 데이터 분야에서는 새로운 오픈소스 솔루션(Flyte)을 도입해 다중 언어 요구사항과 확장성 문제를 해결했습니다. 이를 통해 개발 생산성과 운영 효율의 균형을 맞추면서도, 파이프라인 신뢰성성능을 크게 향상시켰습니다. 예컨대 Flyte 도입 후에는 하나의 워크플로우 업데이트를 위해 1000개 리포지토리에 일일이 PR을 올릴 필요 없이 중앙에서 기능을 개량할 수 있게 되었고 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows), 파이프라인 실행 환경도 표준화되어 작업 실패나 지연이 감소했다고 합니다. Spotify처럼 점진적으로 핵심 시스템을 재구축하는 접근은, 서비스 가동 중단 없이 서서히 새로운 스택으로 이전해야 하는 현실적인 기업 환경에서 특히 유용한 전략입니다.

그 외: 마이그레이션을 고려하거나 대안으로 선택한 사례

앞선 사례들 외에도, 여러 기업들이 Python의 한계를 극복하기 위해 다양한 노력을 기울여왔습니다. 모든 회사가 반드시 Java/Kotlin으로 옮겨가는 것은 아니지만, “성능 문제를 해결한다”는 공통 목표 아래 여러 대안을 채택하고 있습니다:

  • Instagram (Meta) – 세계 최대 규모의 Django(Python) 웹서비스를 운영하면서도, 핵심 서버를 다른 언어로 갈아엎지 않고 Python 자체를 최적화하는 방향을 택한 사례입니다. Instagram은 Facebook 인프라에 편입된 후 PyPy JIT 도입, C++ 확장, 캐싱 레이어, asyncio 활용 등으로 Python 환경을 튜닝하여 수억 사용자 규모를 지원했습니다. 또한 Pyre 같은 정적 타입 분석기를 도입해 Python 코드의 타입 안정성을 강화함으로써 대규모 코드베이스의 품질 관리에 활용했습니다. 이처럼 하드웨어를 수평 확장하고 언어 런타임을 개선함으로써, 완전한 재작성 없이도 어느 정도 문제를 완화한 경우입니다.

  • Dropbox – 초창기부터 Python으로 개발된 파일 호스팅 서비스로, 한때 Python 성능을 높이기 위해 자체 JIT 컴파일러(Pyston)를 개발할 정도로 Python에 투자를 했습니다. 이후 일부 백엔드 컴포넌트(예: 동기화 엔진 등)는 Go와 Rust로 다시 작성하여 성능을 향상시켰지만, 여전히 웹 서버 로직 상당 부분은 Python으로 남아 있습니다. Dropbox 사례는 Python을 완전히 버리지 않고 필요한 부분만 치환하는 하이브리드 접근으로 볼 수 있습니다.

  • Lyft – Uber 경쟁사인 Lyft 역시 초기에는 PHP/Python 등으로 모놀리스를 구축했으나, 빠르게 Go 언어 기반의 마이크로서비스로 전환하여 성능 문제를 해결했습니다. 특히 Lyft는 앞서 언급한 Flyte 플랫폼을 직접 개발하여 내부 데이터 파이프라인 관리를 개선했는데, 이는 곧 Spotify 등이 채택하는 등 업계 표준화에 기여했습니다. Lyft의 경우 Java 대신 Go를 선택했지만, “정적 타입 + 멀티스레드”라는 큰 흐름은 Uber와 유사합니다.

  • Sentry – 실시간 오류 모니터링 서비스인 Sentry는 원래 Python(Django)로 구현되어 있었으나, 급증하는 이벤트 양을 처리하기 위해 데이터 수집 파이프라인을 Rust로 재작성했습니다. Python 기반의 Celery 워커를 Rust로 대체한 결과, 쓰루풋이 향상되고 서버 비용이 크게 절감된 사례로 알려져 있습니다. 비록 Java/Kotlin은 아니지만, 성능 병목 부분만 정적 언어로 치환하여 효과를 본 예시입니다.

이 밖에도 금융권 등 엔터프라이즈 분야에서 Python 프로토타입을 Java로 재구현하는 일은 오래전부터 빈번했습니다. 은행이나 결제 시스템에서는 안정성과 타입 안정성 요구사항이 높아, 초기 실험단계 이후 검증된 JVM 생태계로 옮기는 것이 일반적입니다. 클라우드 인프라 분야에서도 Terraform 같은 도구의 Python SDK 부분을 성능상 이유로 Go로 바꾸는 등, 동적 언어에서 정적 언어로의 전환은 계속 일어나고 있습니다.

결론: 왜 그리고 어떻게 언어를 바꾸는가

요약하면, Python에서 Java/Kotlin으로의 마이그레이션은 주로 성능, 확장성, 안정성, 그리고 개발 운영 측면의 이점 때문에 이루어집니다. Python은 개발이 빠르고 배우기 쉬워 초기 혁신에 적합하지만, 글로벌 규모 트래픽이나 복잡한 시스템을 장기간 유지해야 하는 상황에서는 동적 타이핑으로 인한 오류, GIL로 인한 멀티코어 활용 한계, 인터프리터 성능 등이 걸림돌이 될 수 있습니다 (Migrating From Python to Kotlin for Our Backend Services). 반면 Java나 Kotlin은 JIT 컴파일과 최적화된 VM으로 높은 성능을 내고, 엄격한 타입체계로 대형 코드를 관리하기 좋으며, 풍부한 라이브러리와 툴로 지원됩니다 (Migrating From Python to Kotlin for Our Backend Services) (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium). 이러한 언어 생태계의 성숙도는 엔지니어 채용과 교육 측면에서도 장점이 되어, 대규모 조직 운영에 유리합니다 (Why are IT systems in big enterprises usually built using Java, instead of Python or JavaScript? | by Mattias Petter Johansson | Medium).

DoorDashUber모놀리식 Python 시스템의 한계를 체감하고 각각 Kotlin과 Java를 택함으로써 성과를 보았습니다. DoorDash한 언어로의 통일 전략을 통해 엔지니어링 효율과 시스템 신뢰성을 높였고 (Migrating From Python to Kotlin for Our Backend Services), Uber핵심 서비스를 재작성하고 언어를 표준화하여 성능 문제를 극복했으며 조직적 복잡성을 줄였습니다 (Brief History of Scaling Uber). Spotify분야별로 적합한 언어를 선택하는 전략으로, 백엔드 스트리밍 서비스는 Java로 최적화하고, 데이터 파이프라인 플랫폼은 다중 언어 지원 솔루션으로 전환하여 유연성과 확장성을 확보했습니다 (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows) (Why Spotify moved from Luigi to Flyte to power their 20,000+ daily workflows).

교훈적으로, 이러한 마이그레이션은 단기간에 끝나는 프로젝트가 아니라 단계적이고 신중한 재구축이라는 점입니다. 기존 시스템을 운영하면서 새로운 시스템을 병행 개발하고, 기능을 하나씩 이전하며, 엔지니어들의 기술 스택 전환을 지원하는 등 점진적 전략이 주로 쓰입니다 (Migrating From Python to Kotlin for Our Backend Services) (Migrating From Python to Kotlin for Our Backend Services). 마이그레이션 이후에는 성능 향상은 물론, 개발 문화의 개선(공동 작업 증진, 코드 품질 향상), 운영 효율 증대(배포 속도 향상, 장애 영향 범위 축소) 등의 효과가 보고되고 있습니다 (DoorDash's Migration from Python to Kotlin) (DoorDash's Migration from Python to Kotlin). 반면, 언어 전환의 비용도 적지 않기에 (재개발 시간, 신규 버그 도입 가능성, 이행 기간 중 복잡성), 각 기업은 자신들의 규모와 필요에 따라 결정하고 있습니다. 일부는 Python을 지속 최적화하며 사용하고, 일부는 핵심 모듈만 치환하고, 일부는 아예 전면적인 재작성을 선택하는 등 그 형태는 다양합니다.

결국 “Right tool for the right job (적재적소에 맞는 도구)”라는 소프트웨어 공학의 격언처럼, 기업들은 Python과 Java/Kotlin의 특성을 잘 비교하여 자신들의 서비스 특성에 가장 이득이 되는 방향으로 진화하고 있습니다. 성능과 확장성이 최우선인 서비스는 검증된 정적 언어로 옮겨가고 (Brief History of Scaling Uber), 유연한 실험과 프로토타이핑이 중요한 영역에서는 여전히 Python이 활용되는 식입니다 (Migrating From Python to Kotlin for Our Backend Services). 중요한 것은 마이그레이션 자체보다는 그 밑바탕에 있는 문제 인식과 해결 노력이며, 언어 전환은 그러한 노력의 한 수단이라는 점입니다. 앞으로도 서비스 규모나 요구사항 변화에 따라 언어 스택을 재평가하는 움직임은 지속될 것이고, 현대의 마이크로서비스 환경에서는 여러 언어의 공존과 역할 분담도 자연스러운 현상으로 자리잡을 것입니다.


본 포스트는 ChatGPT 4.5와 심층 리서치 기능을 활용하여 작성되었습니다.

참고 자료:

profile
주니어 개발자

0개의 댓글