🏢 Spotify 기술 스택 분석

25 min read
spotifyjavapythonkubernetesgcpbigtablepubsubbeamtensorflowmicroservicesbackstagegolden-pathmlstreaming

스포티파이가 전 세계 5억 명에게 8,300만 곡을 스트리밍하는 기술 스택 심층 분석 - 마이크로서비스, 머신러닝, 그리고 음악 추천의 비밀

🏢 Spotify 기술 스택 분석

매일 10억 개 이상의 스트림을 처리하며 개인화된 음악 경험을 제공하는 Spotify의 기술 스택을 심층 분석합니다.
"Music for everyone" - 기술로 만드는 글로벌 음악 플랫폼


📊 회사 개요

서비스 규모

  • 월간 활성 사용자: 5.74억 명 (프리미엄 2.26억)
  • 콘텐츠: 1억+ 트랙, 500만+ 팟캐스트
  • 일일 스트림: 10억+ 재생
  • 서비스 지역: 184개 시장
  • 플레이리스트: 40억+ 사용자 생성

엔지니어링 조직

  • 엔지니어: 2,000명+ (전체 직원 9,000+)
  • Squad 모델: 자율적인 소규모 팀
  • Chapter & Guild: 기술 공유 조직
  • 오픈소스: 400+ 프로젝트

기술적 도전과제

  1. 개인화: 5억 명을 위한 맞춤 추천
  2. 저지연 스트리밍: 전 세계 실시간 음악 전송
  3. 콘텐츠 관리: 1억+ 트랙 메타데이터
  4. 크리에이터 도구: 아티스트 분석 플랫폼

🧩 기술 스택 상세

Backend 기술

마이크로서비스 아키텍처

// Spotify의 Apollo 프레임워크 기반 서비스 @Service public class PlaylistService { private final UserService userService; private final TrackService trackService; private final RecommendationService recommendationService; @RequestMapping("/playlists/{id}") public CompletableFuture<Playlist> getPlaylist( @PathVariable String id, @RequestContext Context context) { return userService.getUser(context.userId()) .thenCompose(user -> { // 병렬로 데이터 가져오기 CompletableFuture<PlaylistMetadata> metadata = getPlaylistMetadata(id); CompletableFuture<List<Track>> tracks = trackService.getTracks(id); CompletableFuture<List<Recommendation>> recommendations = recommendationService.getForPlaylist(id, user); return CompletableFuture.allOf(metadata, tracks, recommendations) .thenApply(v -> buildPlaylist( metadata.join(), tracks.join(), recommendations.join() )); }); } // Circuit breaker 패턴 @HystrixCommand( fallbackMethod = "getDefaultRecommendations", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") } ) private CompletableFuture<List<Track>> getPersonalizedTracks(String userId) { return mlService.getRecommendations(userId); } } 

Backend 기술 스택:

  • 언어: Java (60%), Python (25%), Go (10%), C++ (5%)
  • 프레임워크: Spring Boot, Apollo (자체), Flask
  • API: GraphQL Federation, REST
  • 메시징: Google Pub/Sub, Kafka (일부)
  • 서비스 메시: Kubernetes + Istio

데이터 파이프라인

# Apache Beam 기반 데이터 처리 import apache_beam as beam from apache_beam.options.pipeline_options import PipelineOptions class SpotifyStreamingPipeline: def __init__(self): self.pipeline_options = PipelineOptions([ '--runner=DataflowRunner', '--project=spotify-data', '--region=europe-west1', '--temp_location=gs://spotify-temp/dataflow', '--streaming' ]) def build_pipeline(self): with beam.Pipeline(options=self.pipeline_options) as p: # 실시간 스트림 이벤트 수집 events = (p | 'Read from Pub/Sub' >> beam.io.ReadFromPubSub( topic='projects/spotify-data/topics/play-events' ) | 'Parse JSON' >> beam.Map(json.loads) ) # 사용자별 집계 user_stats = (events | 'Extract User Data' >> beam.Map( lambda x: (x['user_id'], { 'track_id': x['track_id'], 'duration': x['duration'], 'timestamp': x['timestamp'] }) ) | 'Window' >> beam.WindowInto( beam.window.FixedWindows(60) # 1분 윈도우 ) | 'Group by User' >> beam.GroupByKey() | 'Calculate Stats' >> beam.Map(self.calculate_user_stats) ) # BigTable에 저장 user_stats | 'Write to Bigtable' >> beam.io.WriteToBigTable( project_id='spotify-data', instance_id='user-analytics', table_id='streaming_stats' ) # 추천 시스템 업데이트 user_stats | 'Update ML Features' >> beam.Map( self.update_recommendation_features ) 

Frontend 기술

Web Player (React)

// Spotify Web Player 컴포넌트 import { useEffect, useState } from "react"; import { useSpotifySDK } from "@spotify/web-api-sdk"; interface PlayerProps { trackUri: string; onTrackEnd: () => void; } export function SpotifyPlayer({ trackUri, onTrackEnd }: PlayerProps) { const [player, setPlayer] = useState<Spotify.Player | null>(null); const [deviceId, setDeviceId] = useState<string>(""); const sdk = useSpotifySDK(); useEffect(() => { // Web Playback SDK 초기화 const script = document.createElement("script"); script.src = "https://sdk.scdn.co/spotify-player.js"; script.async = true; document.body.appendChild(script); window.onSpotifyWebPlaybackSDKReady = () => { const player = new Spotify.Player({ name: "Spotify Web Player", getOAuthToken: (cb) => { sdk.getAccessToken().then(cb); }, volume: 0.5, }); // 이벤트 리스너 player.addListener("ready", ({ device_id }) => { console.log("Ready with Device ID", device_id); setDeviceId(device_id); }); player.addListener("player_state_changed", (state) => { if (state.position === 0 && state.paused) { onTrackEnd(); } // 재생 통계 전송 sendPlaybackAnalytics({ track_id: state.track_window.current_track.id, position: state.position, duration: state.duration, context: state.context, }); }); player.connect(); setPlayer(player); }; return () => { player?.disconnect(); }; }, []); const play = async () => { await sdk.player.play({ device_id: deviceId, uris: [trackUri], }); }; return ( <div className="player-container"> <AudioVisualizer /> <PlayerControls onPlay={play} onPause={() => player?.pause()} onNext={() => player?.nextTrack()} /> <VolumeControl onChange={(volume) => player?.setVolume(volume)} /> </div> ); } 

Frontend 기술:

  • Web: React, TypeScript, Redux
  • Mobile: Native (Swift/Kotlin) + React Native (일부)
  • Desktop: Electron + CEF (Chromium Embedded)
  • TV/콘솔: C++ 커스텀 플레이어
  • 빌드: Webpack, Bazel

Data & ML Infrastructure

추천 시스템

# Spotify의 추천 엔진 (간소화) class CollaborativeFilteringModel: def __init__(self): self.user_embeddings = None self.item_embeddings = None self.model = self._build_model() def _build_model(self): # Two-tower 모델 user_input = keras.Input(shape=(USER_FEATURES,)) item_input = keras.Input(shape=(ITEM_FEATURES,)) # User tower user_tower = keras.Sequential([ keras.layers.Dense(256, activation='relu'), keras.layers.Dropout(0.2), keras.layers.Dense(128, activation='relu'), keras.layers.Dense(64) ]) # Item tower item_tower = keras.Sequential([ keras.layers.Dense(256, activation='relu'), keras.layers.Dropout(0.2), keras.layers.Dense(128, activation='relu'), keras.layers.Dense(64) ]) user_embedding = user_tower(user_input) item_embedding = item_tower(item_input) # Dot product for similarity similarity = keras.layers.Dot(axes=1)([user_embedding, item_embedding]) model = keras.Model( inputs=[user_input, item_input], outputs=similarity ) return model def get_recommendations(self, user_id, context): # 사용자 특성 추출 user_features = self.extract_user_features(user_id) # 컨텍스트 고려 (시간, 장소, 기기) context_features = self.extract_context_features(context) # 후보 생성 candidates = self.retrieve_candidates(user_features) # 순위 매기기 scores = self.model.predict([ np.repeat(user_features, len(candidates)), candidates ]) # 다양성 추가 diversified = self.apply_diversity(candidates, scores) return diversified[:100] # Top 100 

Feature Store

// Spotify의 Feature Store (Feathr 기반) object FeatureStore { case class UserFeatures( userId: String, totalListeningTime: Long, topGenres: Seq[String], topArtists: Seq[String], listeningPatterns: Map[Int, Float], // hour -> probability devicePreferences: Map[String, Float], lastUpdated: Timestamp ) case class TrackFeatures( trackId: String, audioFeatures: AudioFeatures, popularity: Float, releaseDate: Date, genres: Seq[String], collaborativeSignal: Float, contentSignal: Float ) case class AudioFeatures( danceability: Float, energy: Float, key: Int, loudness: Float, mode: Int, speechiness: Float, acousticness: Float, instrumentalness: Float, liveness: Float, valence: Float, tempo: Float, duration: Int ) def getUserFeatures(userId: String): Future[UserFeatures] = { // BigTable에서 특성 조회 bigtableClient.get(s"user_features:$userId").map { row => UserFeatures( userId = userId, totalListeningTime = row.getLong("total_time"), topGenres = row.getList("genres"), topArtists = row.getList("artists"), listeningPatterns = row.getMap("patterns"), devicePreferences = row.getMap("devices"), lastUpdated = row.getTimestamp("updated") ) } } } 

데이터 인프라:

  • 데이터 레이크: Google Cloud Storage
  • 실시간 처리: Google Pub/Sub + Dataflow
  • 배치 처리: Apache Beam, Scio (Scala)
  • 데이터베이스: Bigtable, Spanner, PostgreSQL
  • 분석: BigQuery, Databricks
  • ML 플랫폼: Kubeflow, TensorFlow Extended

Infrastructure & DevOps

Backstage 플랫폼

# Backstage 서비스 카탈로그 apiVersion: backstage.io/v1alpha1 kind: Component metadata: name: playlist-service description: Manages user playlists and collaborative playlists tags: - java - backend - tier1 annotations: github.com/project-slug: spotify/playlist-service backstage.io/techdocs-ref: dir:. spotify.com/squad-owner: playlist-experience spec: type: service lifecycle: production owner: playlist-squad system: playlist-platform dependsOn: - resource:playlist-db - component:track-service - component:user-service providesApis: - playlist-api 

Golden Path

# Spotify의 Golden Path CLI $ spotify create service playlist-service --lang java --type rest ✓ Created service scaffold ✓ Set up GitHub repository ✓ Configured CI/CD pipelines ✓ Created Kubernetes manifests ✓ Registered in Backstage ✓ Set up monitoring dashboards ✓ Created runbooks Your service is ready! Local development: cd playlist-service && ./gradlew bootRun Deploy to staging: git push origin main 

인프라 기술:

  • 클라우드: Google Cloud Platform (주력)
  • 컨테이너: Kubernetes (자체 관리)
  • CI/CD: Jenkins + Spinnaker
  • 모니터링: Prometheus + Grafana
  • 로깅: ELK Stack
  • 개발자 포털: Backstage

💡 핵심 기술 인사이트

1. Squad 모델 & 자율성

// Squad의 자율적 서비스 운영 interface SquadOwnership { squad: string; mission: string; services: string[]; kpis: { metric: string; target: number; current: number; }[]; dependencies: { upstream: string[]; downstream: string[]; }; } // 예시: Playlist Squad const playlistSquad: SquadOwnership = { squad: "playlist-experience", mission: "Enable users to organize and discover music through playlists", services: [ "playlist-service", "collaborative-playlist-service", "playlist-recommendation-service", ], kpis: [ { metric: "playlist_creation_rate", target: 1000000, current: 1200000 }, { metric: "collaborative_playlist_mau", target: 50000000, current: 62000000, }, { metric: "p99_latency_ms", target: 200, current: 187 }, ], dependencies: { upstream: ["user-service", "track-service", "ml-platform"], downstream: ["mobile-app", "web-player", "home-feed"], }, }; 

2. 음악 추천 알고리즘

# Spotify의 하이브리드 추천 시스템 class HybridRecommendationEngine: def __init__(self): self.collaborative_filter = CollaborativeFiltering() self.content_based = ContentBasedFiltering() self.nlp_engine = NLPEngine() self.contextual_bandit = ContextualBandit() def generate_discover_weekly(self, user_id): # 1. 협업 필터링 (유사 사용자 기반) collaborative_tracks = self.collaborative_filter.get_recommendations( user_id, method='matrix_factorization', n_tracks=1000 ) # 2. 콘텐츠 기반 필터링 (음악적 특성) user_taste_profile = self.get_user_taste_profile(user_id) content_tracks = self.content_based.find_similar_tracks( user_taste_profile, audio_features=['energy', 'valence', 'danceability'], n_tracks=1000 ) # 3. NLP 기반 추천 (가사, 리뷰 분석) nlp_tracks = self.nlp_engine.get_semantic_recommendations( user_id, sources=['lyrics', 'reviews', 'social_media'], n_tracks=500 ) # 4. 앙상블 & 다양성 최적화 candidate_pool = self.merge_recommendations([ (collaborative_tracks, 0.4), (content_tracks, 0.3), (nlp_tracks, 0.3) ]) # 5. Contextual Bandit으로 최종 선택 final_playlist = self.contextual_bandit.select_tracks( candidate_pool, context={ 'day_of_week': datetime.now().weekday(), 'time_of_day': datetime.now().hour, 'user_activity': self.get_recent_activity(user_id), 'global_trends': self.get_trending_tracks() }, n_tracks=30 ) return self.ensure_diversity(final_playlist) 

3. 실시간 오디오 분석

// C++ 기반 오디오 특성 추출 class AudioAnalyzer { private: std::unique_ptr<FFTProcessor> fft; std::unique_ptr<ChromaExtractor> chroma; std::unique_ptr<RhythmAnalyzer> rhythm; public: AudioFeatures analyzeTrack(const AudioBuffer& buffer) { AudioFeatures features; // 스펙트럼 분석 auto spectrum = fft->process(buffer); features.spectralCentroid = calculateSpectralCentroid(spectrum); features.spectralRolloff = calculateSpectralRolloff(spectrum, 0.85); // 크로마 벡터 (화성 분석) auto chromaVector = chroma->extract(buffer); features.key = estimateKey(chromaVector); features.mode = estimateMode(chromaVector); // 리듬 특성 auto tempogram = rhythm->extractTempogram(buffer); features.tempo = estimateTempo(tempogram); features.timeSignature = estimateTimeSignature(tempogram); // 고급 특성 features.danceability = calculateDanceability(features.tempo, features.energy, features.rhythm_strength); features.energy = calculateEnergy(spectrum); features.valence = estimateValence(chromaVector, features.tempo); // 음성/악기 분리 auto separated = separateSources(buffer); features.instrumentalness = calculateInstrumentalness(separated); features.speechiness = calculateSpeechiness(separated); return features; } }; 

4. Backstage 개발자 경험

# 개발자 생산성 도구 apiVersion: scaffolder.backstage.io/v1beta3 kind: Template metadata: name: spotify-microservice title: Spotify Microservice description: Create a new microservice following Spotify standards spec: owner: platform-team type: service parameters: - title: Service Details required: - name - description - squad properties: name: title: Name type: string pattern: "^[a-z0-9-]+$" description: title: Description type: string squad: title: Squad Owner type: string enum: ${squads} - title: Technical Choices properties: language: title: Programming Language type: string enum: ["java", "python", "go", "typescript"] database: title: Database type: string enum: ["bigtable", "spanner", "postgresql", "none"] messaging: title: Messaging type: string enum: ["pubsub", "kafka", "none"] steps: - id: fetch name: Fetch Skeleton action: fetch:template input: url: ./skeleton/${{ parameters.language }} - id: publish name: Publish to GitHub action: publish:github input: repoUrl: github.com?owner=spotify&repo=${{ parameters.name }} - id: register name: Register in Backstage action: catalog:register - id: setup-ci name: Setup CI/CD action: jenkins:create-job 

📈 성과 & 지표

기술적 성과

  • API 응답시간: P50 < 50ms, P99 < 200ms
  • 가용성: 99.95% (연간 다운타임 < 4.5시간)
  • 배포 빈도: 일일 2,000+ 배포
  • 추천 정확도: 30% 향상 (2020년 대비)
  • 스트리밍 품질: 320kbps (Premium)

비즈니스 영향

  • 사용자 참여: 평균 일일 사용 2.5시간
  • Discover Weekly: 40% 사용자가 매주 청취
  • 개인화 효과: 추천 트랙 80%+ 긍정 반응
  • 개발자 생산성: Golden Path로 50% 시간 단축

🎓 Spotify에서 배울 점

✅ 적용 가능한 패턴

  1. Squad 모델: 자율적 팀 운영
  2. Golden Path: 표준화된 개발 경로
  3. Backstage: 개발자 포털 플랫폼
  4. Feature Store: ML 특성 관리
  5. 하이브리드 추천: 다양한 알고리즘 앙상블

❌ 주의사항

  1. 복잡한 조직 구조: Squad 모델은 문화가 중요
  2. 높은 자율성: 표준화와 균형 필요
  3. 기술 다양성: 너무 많은 언어/프레임워크
  4. 데이터 규모: 대규모 인프라 필요

📚 추천 리소스


🔮 미래 전망

현재 집중 분야

  1. AI DJ: 개인화된 라디오 경험
  2. 팟캐스트 기술: 음성 콘텐츠 혁신
  3. 라이브 오디오: 실시간 방송 플랫폼
  4. 자동차 경험: 차량용 최적화
  5. 창작자 도구: 아티스트 분석 플랫폼

기술 투자 영역

  • 생성형 AI: 음악 생성, 리믹스
  • 공간 오디오: 3D 사운드 경험
  • 블록체인: 로열티 분배 투명성
  • 엣지 컴퓨팅: 오프라인 최적화
  • 그린 컴퓨팅: 탄소 중립 스트리밍

"우리는 세계 최고의 오디오 플랫폼이 되기 위해 기술의 한계를 계속 넓혀가고 있습니다."

  • Spotify Engineering

마지막 업데이트: 2025-01-28

┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Clients │────►│ Backend │────►│ ML Platform│ │(Mobile/Web) │ │ for FE(BFF)│ │ (Kubeflow) │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ │ │ API Gateway│ │ Feature │ │ │ (Nginx) │ │ Store │ │ └───────────┘ └───────────┘ │ │ │ └────────────────────┤ │ ┌─────▼─────┐ ┌─────▼─────┐ │Microservices│ │ Data Lake │ │(100s of them)│ │ (GCS) │ └───────────┘ └───────────┘ 

핵심 설계 원칙

  1. Autonomous Teams: Squad 모델로 독립적 개발
  2. Golden Path: 표준화된 개발 경로
  3. Data-Driven: 모든 결정은 데이터 기반
  4. Fail Fast: 빠른 실험과 학습
  5. Platform Thinking: 내부 플랫폼 우선

기술 진화

  • 2006-2008: Python 모놀리스
  • 2009-2012: 마이크로서비스 전환
  • 2013-2016: 자체 인프라 → 클라우드
  • 2017-2020: ML 플랫폼 구축
  • 2021-현재: Backstage, Golden Path

Found this helpful? Share it with others!
Tweet

🔗 Related Content

You might also be interested in these articles

🏢 company

🏢 Canva 기술 스택 분석

캔바가 1억 명 이상의 사용자에게 쉽고 강력한 디자인 도구를 제공하는 기술 스택 심층 분석 - Java, TypeScript, AWS로 구축한 대규모 디자인 플랫폼

32 min read
canva, java+10
Read more
🏢 company

🏢 Netflix 기술 스택 분석

넷플릭스가 전 세계 2.4억 사용자에게 스트리밍 서비스를 제공하는 기술 스택 심층 분석 - 마이크로서비스, AWS, Chaos Engineering의 교과서

9 min read
netflix, microservices+11
Read more
🏢 company

🏢 Airbnb 기술 스택 분석

에어비앤비가 전 세계 400만 개의 숙소를 연결하는 글로벌 마켓플레이스 기술 스택 심층 분석 - Ruby on Rails에서 Service-Oriented Architecture로의 진화

24 min read
airbnb, ruby+12
Read more
🏢 company

🏢 배달의민족 기술 스택 분석

배달의민족이 한국 배달 문화를 혁신하며 동남아로 확장한 기술 스택 심층 분석 - Java, Spring, Kotlin으로 구축한 O2O 플랫폼

51 min read
baemin, woowa+10
Read more
🏢 company

🏢 카카오 기술 스택 분석

카카오가 5천만 한국인의 일상을 연결하는 기술 스택 심층 분석 - Java, Kotlin, MySQL로 구축한 국민 메신저부터 슈퍼앱까지

32 min read
kakao, java+9
Read more

Found this helpful?

Help us improve this content by contributing on GitHub or sharing your feedback with the community.