🏢 Uber 기술 스택 분석
우버가 매일 2,500만 건의 라이드를 실시간으로 매칭하는 기술 스택 심층 분석 - Go, Java, Node.js로 구축한 글로벌 실시간 마켓플레이스
🏢 Uber 기술 스택 분석
전 세계 10,000개 도시에서 매초 수천 건의 실시간 매칭을 처리하는 Uber의 기술 스택을 심층 분석합니다.
"Move the world, build the future" - 실시간 마켓플레이스의 기술적 도전
📊 회사 개요
서비스 규모
- 월간 활성 사용자: 1.3억 명
- 드라이버 & 배달원: 500만 명+
- 일일 트립: 2,500만 건
- 도시: 전 세계 10,000개+
- 서비스: Rides, Eats, Freight, Health
엔지니어링 조직
- 엔지니어: 3,000명+
- 기술 스택: 4,000+ 마이크로서비스
- 코드베이스: 수천만 줄
- 배포: 주당 4,000+ 배포
기술적 도전과제
- 실시간 매칭: 수요-공급 최적화
- 동적 가격: 서지 프라이싱 알고리즘
- 글로벌 확장: 다양한 규제와 시장
- 신뢰성: 24/7 가용성 필수
🏗️ 아키텍처 Overview
시스템 다이어그램
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Riders │────►│ Gateway │────►│ Dispatch │ │ App │ │ (Edge) │ │ System │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ │ │ DISCO │ │ Supply │ │ │ Matching │ │ Service │ │ └───────────┘ └───────────┘ │ │ │ ┌─────────────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ Drivers │◄──────│ Kafka │◄──────│ Pricing │ │ App │ │ Streams │ │ Service │ └─────────────┘ └───────────┘ └───────────┘ 핵심 설계 원칙
- Domain-Oriented Architecture: 비즈니스 도메인별 분리
- Layered Architecture: 플랫폼, 제품, 프레젠테이션 레이어
- Event-Driven: 이벤트 기반 통신
- Location-First: H3 기반 지리공간 인덱싱
- Real-Time Priority: 저지연 최적화
기술 진화
- 2009-2012: PHP 모놀리스
- 2013-2015: Python/Node.js 마이크로서비스 전환
- 2016-2018: Go 도입, Schemaless 개발
- 2019-2021: gRPC 마이그레이션
- 2022-현재: 플랫폼 통합 (Rides + Eats)
🧩 기술 스택 상세
Backend 기술
Go 서비스 예시
// 지리공간 매칭 서비스 package dispatch import ( "context" "github.com/uber/h3-go" "github.com/uber/ringpop-go" ) type DispatchService struct { supplyIndex *H3Index demandQueue *PriorityQueue ringpop *ringpop.Ringpop priceEngine PricingClient } func (s *DispatchService) FindOptimalMatch(ctx context.Context, req *RideRequest) (*Match, error) { // H3 셀 기반 근처 드라이버 검색 h3Cell := h3.GeoToH3(req.Pickup.Lat, req.Pickup.Lng, 9) nearbyDrivers := s.supplyIndex.GetDriversInRadius(h3Cell, 2000) // 2km // 동적 가격 계산 surge, err := s.priceEngine.CalculateSurge(ctx, &SurgeRequest{ H3Cell: h3Cell, Timestamp: time.Now(), SupplyCount: len(nearbyDrivers), DemandCount: s.demandQueue.GetDemandCount(h3Cell), }) // 최적 매칭 알고리즘 matches := []Match{} for _, driver := range nearbyDrivers { score := s.calculateMatchScore(req, driver, surge) if score > MinMatchThreshold { matches = append(matches, Match{ Driver: driver, Rider: req.RiderID, Score: score, ETA: driver.ETA, Fare: s.calculateFare(req, surge), }) } } // 최고 점수 매치 반환 sort.Slice(matches, func(i, j int) bool { return matches[i].Score > matches[j].Score }) if len(matches) > 0 { return &matches[0], nil } return nil, ErrNoMatchFound } 주요 백엔드 기술:
- 언어: Go (60%), Java (25%), Python (10%), Node.js (5%)
- RPC: gRPC, TChannel (레거시)
- API Gateway: Edge Gateway (자체 개발)
- 서비스 메시: Envoy Proxy
- 메시징: Apache Kafka, Celery
마이크로서비스 아키텍처
# 주요 도메인 서비스 services: # 핵심 비즈니스 - name: dispatch-service language: go dependencies: [supply, demand, pricing] - name: pricing-service language: java dependencies: [ml-platform, surge-engine] - name: payment-service language: java dependencies: [risk, fraud-detection] # 플랫폼 서비스 - name: user-platform language: java dependencies: [auth, profile, preferences] - name: geospatial-platform language: go dependencies: [h3-index, routing, maps] - name: ml-platform language: python dependencies: [feature-store, model-serving] Frontend 기술
모바일 앱 아키텍처
// iOS 라이더 앱 아키텍처 class RideRequestViewController: UIViewController { private let locationManager = LocationManager() private let networkClient = UberAPIClient() private let mapView = MapboxMapView() func requestRide() { // 실시간 위치 추적 locationManager.startUpdatingLocation { location in self.updatePickupLocation(location) } // 실시간 공급 상황 표시 networkClient.streamNearbyDrivers { drivers in self.mapView.updateDriverPositions(drivers) } // 요금 추정 networkClient.estimateFare( from: pickupLocation, to: destinationLocation ) { fare in self.showFareEstimate(fare) } } } 플랫폼별 기술:
- iOS: Swift, RIBs 아키텍처
- Android: Kotlin, MVP/MVVM
- Web: React, TypeScript, GraphQL
- Driver App: React Native (일부), Native
RIBs 아키텍처
// Router-Interactor-Builder 패턴 protocol RideRequestRouting: ViewableRouting { func routeToLocationPicker() func routeToPaymentSelection() func routeToRideStatus() } class RideRequestInteractor: PresentableInteractor<RideRequestPresentable> { weak var router: RideRequestRouting? private let rideService: RideService func requestRide(pickup: Location, destination: Location) { rideService.createRideRequest(pickup: pickup, destination: destination) .subscribe(onNext: { [weak self] rideStatus in self?.router?.routeToRideStatus() }) .disposed(by: disposeBag) } } Data & Infrastructure
데이터 아키텍처
-- Schemaless 데이터 모델 (MySQL 기반) CREATE TABLE entities ( entity_type VARCHAR(50), entity_id BINARY(16), attribute_name VARCHAR(100), attribute_value JSON, version BIGINT, updated_at TIMESTAMP, PRIMARY KEY (entity_type, entity_id, attribute_name, version) ); -- 예시: 라이드 데이터 INSERT INTO entities VALUES ('ride', UUID_TO_BIN('...'), 'status', '{"value": "completed"}', 1, NOW()), ('ride', UUID_TO_BIN('...'), 'fare', '{"amount": 25.50, "currency": "USD"}', 1, NOW()), ('ride', UUID_TO_BIN('...'), 'route', '{"distance": 10.5, "duration": 900}', 1, NOW()); 데이터 저장소:
- Schemaless: MySQL 기반 NoSQL (자체 개발)
- Docstore: 문서 저장소
- Apache Cassandra: 시계열 데이터
- HDFS: 데이터 레이크
- Redis: 캐싱, 세션
H3 지리공간 시스템
// Uber의 H3 육각형 그리드 시스템 type H3Index struct { resolution int index map[h3.H3Index]*Cell } type Cell struct { drivers []*Driver demand float64 surge float64 lastUpdate time.Time } func (idx *H3Index) UpdateSupply(lat, lng float64, driverID string) { cell := h3.GeoToH3(lat, lng, idx.resolution) idx.mu.Lock() defer idx.mu.Unlock() if idx.index[cell] == nil { idx.index[cell] = &Cell{} } idx.index[cell].drivers = append(idx.index[cell].drivers, &Driver{ ID: driverID, Location: geo.NewPoint(lat, lng), Status: "available", }) } ML & 데이터 사이언스
Michelangelo ML 플랫폼
# 수요 예측 모델 from michelangelo import Model, Feature, Pipeline class DemandForecastModel(Model): def __init__(self): self.features = [ Feature("h3_cell", type="categorical"), Feature("hour_of_day", type="numeric"), Feature("day_of_week", type="categorical"), Feature("weather", type="categorical"), Feature("events_nearby", type="numeric"), Feature("historical_demand", type="time_series"), ] def train(self, training_data): # XGBoost 모델 학습 self.model = XGBRegressor( n_estimators=1000, max_depth=8, learning_rate=0.01 ) X = self.prepare_features(training_data) y = training_data["demand_count"] self.model.fit(X, y) def predict(self, h3_cell, timestamp): features = self.extract_features(h3_cell, timestamp) return self.model.predict(features)[0] ML 사용 사례:
- 수요 예측: 15분 단위 예측
- 동적 가격: 실시간 서지 계산
- ETA 예측: 도착 시간 추정
- 사기 탐지: 실시간 위험 평가
- 경로 최적화: 최단 경로 계산
DevOps & Infrastructure
배포 파이프라인
# uDeploy 배포 설정 deployment: service: dispatch-service stages: - name: development clusters: [dev-us-west-2] canary_percentage: 0 - name: staging clusters: [staging-us-west-2] canary_percentage: 10 duration: 30m - name: production clusters: [prod-us-west-2, prod-eu-west-1, prod-ap-south-1] canary_percentage: 1 increment: 10 duration: 2h health_checks: - endpoint: /health interval: 10s threshold: 3 rollback: automatic: true error_rate_threshold: 0.1 latency_threshold_p99: 500ms DevOps 도구:
- uDeploy: 자체 배포 시스템
- Phabricator: 코드 리뷰 (현재 GitHub 이전 중)
- M3: 메트릭 시스템 (Prometheus 기반)
- Jaeger: 분산 트레이싱
- PagerDuty: 인시던트 관리
💡 핵심 기술 인사이트
1. DISCO (Dispatch Optimization)
# 실시간 매칭 최적화 class DISCOOptimizer: def optimize_batch(self, riders, drivers): # 이분 그래프 매칭 문제 graph = BipartiteGraph() for rider in riders: for driver in drivers: if self.is_matchable(rider, driver): weight = self.calculate_match_value(rider, driver) graph.add_edge(rider.id, driver.id, weight) # Hungarian 알고리즘으로 최적 매칭 matches = graph.maximum_weight_matching() return matches def calculate_match_value(self, rider, driver): # 다중 목표 최적화 pickup_time = self.estimate_pickup_time(rider, driver) driver_utilization = self.get_driver_utilization(driver) rider_wait_time = self.get_rider_wait_time(rider) # 가중치 조합 value = ( - 0.4 * pickup_time - 0.3 * rider_wait_time + 0.3 * driver_utilization ) return value 2. 서지 프라이싱
// 동적 가격 책정 엔진 type SurgePricingEngine struct { mlModel MLModel constraints PricingConstraints } func (e *SurgePricingEngine) CalculateSurge(ctx context.Context, cell h3.H3Index) float64 { // 실시간 수요-공급 비율 supply := e.getSupplyCount(cell) demand := e.getDemandCount(cell) ratio := float64(demand) / float64(supply) // ML 모델 예측 features := e.extractFeatures(cell) predictedDemand := e.mlModel.Predict(features) // 서지 계산 var surge float64 if ratio > 1.5 { surge = min( 1.0 + (ratio-1.5)*0.5, e.constraints.MaxSurge, ) } // 규제 준수 surge = e.applyLocalRegulations(cell, surge) return surge } 3. 글로벌 확장 플랫폼
// 다중 지역 구성 관리 @Component public class RegionalConfigService { private final Map<String, RegionalConfig> configs; @PostConstruct public void loadConfigs() { // 지역별 규제 및 기능 로드 configs = Map.of( "US", new RegionalConfig() .withTipping(true) .withUpfrontPricing(true) .withSurgeMultiplier(3.0), "EU", new RegionalConfig() .withGDPRCompliance(true) .withFixedPricing(true) .withSurgeMultiplier(2.0), "IN", new RegionalConfig() .withCashPayments(true) .withAutoRickshaw(true) .withSurgeMultiplier(2.5) ); } } 📈 성과 & 지표
기술적 성과
- 매칭 시간: 평균 15초 이내
- 시스템 가용성: 99.99%
- API 응답시간: P50 < 100ms, P99 < 500ms
- 배포 빈도: 일일 1,000+ 배포
- 서비스 수: 4,000+ 마이크로서비스
규모 지표
- 일일 트립: 2,500만 건
- 피크 시간 RPS: 500,000+
- 데이터 처리: 일일 수 PB
- ML 예측: 초당 수백만 건
🎓 Uber에서 배울 점
✅ 적용 가능한 패턴
- H3 지리공간 인덱싱: 효율적인 위치 기반 검색
- Schemaless 설계: 유연한 데이터 모델
- RIBs 아키텍처: 모바일 앱 구조화
- 배치 매칭: 효율성 극대화
- Circuit Breaker: 장애 격리
❌ 주의사항
- 복잡성 관리: 4000+ 서비스는 관리 어려움
- 기술 부채: 레거시 시스템 마이그레이션
- 조직 사일로: 팀 간 협업 어려움
- 비용: 대규모 인프라 운영비
📚 추천 리소스
🔮 미래 전망
현재 집중 분야
- 자율주행: ATG 기술 통합
- 멀티모달: 다양한 이동 수단 통합
- Uber Freight: B2B 물류 혁신
- 금융 서비스: Uber Money
- 슈퍼앱: 통합 플랫폼화
기술 투자 영역
- 실시간 ML: 더 정교한 예측
- 엣지 컴퓨팅: 저지연 처리
- 블록체인: 공급망 추적
- AR/VR: 향상된 사용자 경험
"우리는 단순히 차량을 호출하는 앱이 아닙니다. 우리는 도시의 OS를 만들고 있습니다."
- Uber Engineering
마지막 업데이트: 2025-01-28