🏢 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