1P by GN⁺ 3시간전 | ★ favorite | 댓글과 토론
  • 우버는 초당 수억 건의 RPC를 처리하는 수천 개의 마이크로서비스 환경에서, 글로벌 속도 제한기(Global Rate Limiter, GRL) 를 구축해 통합된 과부하 보호 체계를 확립
  • GRL은 클라이언트-애그리게이터-컨트롤러로 구성된 3계층 피드백 루프 아키텍처로, 로컬에서 요청을 판단하면서도 수 초 내 글로벌 조율 가능
  • 초기 토큰 버킷 방식에서 확률적 드롭 모델로 전환하여 공정성과 확장성 문제를 해결하고, 핫 경로의 지연 시간을 최소화
  • Redis 기반 제한기 대비 P99.5 지연 시간이 최대 90% 개선되었으며, 15배 트래픽 급증과 DDoS 공격도 서비스 저하 없이 흡수
  • Rate Limit Configurator(RLC) 가 과거 트래픽 패턴을 분석해 자동으로 한도를 갱신함으로써, 정적 설정에서 자가 조정 시스템으로 진화

기존 속도 제한의 문제점

  • Uber의 초기 마이크로서비스 환경에서는 각 팀이 비즈니스 로직, 커스텀 미들웨어, Redis 기반 카운터 등으로 각자 스로틀링을 구현
  • 이로 인해 비일관적인 설정, Redis 기반 지연 시간 추가, 한도 변경 시 서버 재배포 필요, 문서화되지 않은 제한기로 인한 인시던트 대응 어려움 등의 문제 발생
  • 소규모 서비스 상당수는 아예 속도 제한 없이 운영되었고, 각 제한기가 메트릭과 오류를 다르게 보고해 통합 관찰성 확보 불가
  • Redis를 중앙 집중형 카운터로 사용하는 방식은 수십만 호스트, 초당 수억 건, 다중 리전 환경에서 허용 불가능한 지연 시간과 리전 간 일관성 문제 초래
    • 샤딩과 복제를 적용해도 수백 개의 Redis 클러스터가 필요하며, 새로운 장애 모드 추가
  • 카운터의 주기적 동기화 방식도 네트워크 오버헤드는 줄이지만 데이터 비신선도와 급격한 트래픽 스파이크 대응 지연으로 배제
  • 최종적으로 로컬 프록시가 집계된 부하 기반으로 판단하는 완전 분산 아키텍처만이 저지연과 글로벌 확장성을 동시에 달성할 수 있다는 결론

통합 인프라 레벨 제한기 비전

  • 해결책은 Uber의 서비스 메시(서비스 간 RPC 트래픽을 위한 인프라 계층)에 속도 제한을 내장하는 것
  • 이 계층에 제한기를 임베딩함으로써 호출자의 언어나 프레임워크에 무관하게 모든 요청을 목적지 도달 전에 검사·평가 가능
  • 목표: 코드 변경 없이 팀이 호출자별·프로시저별 쿼터를 설정할 수 있는 통합 속도 제한 서비스 제공
  • 초당 수억 건의 요청, 수만 개의 서비스 쌍, 다중 지리적 리전의 호스트 플릿에 걸쳐 최소한의 지연 시간 추가로 확장 필요

GRL 아키텍처: 3계층 피드백 루프

  • GRL의 핵심은 3계층 피드백 루프 구조
    • Rate-limit 클라이언트 (서비스 메시 데이터 플레인): 애그리게이터로부터 받은 지시에 따라 로컬에서 요청별 판단 수행, 호스트별 초당 요청 수를 존 레벨 애그리게이터에 보고
    • 애그리게이터 (존별): 동일 존 내 모든 클라이언트의 메트릭을 수집, 존 레벨 사용량을 계산해 컨트롤러로 전송
    • 컨트롤러 (리전별, 글로벌): 존 데이터를 집계해 글로벌 활용률을 판단, 업데이트된 드롭 비율 지시를 애그리게이터와 클라이언트로 역전파
  • 이 계층적 집계로 핫 경로의 저지연(판단이 로컬) 유지와 수 초 내 글로벌 조율 동시 달성
  • 컨트롤 플레인 장애 시 클라이언트는 페일 오픈 방식으로 동작, 트래픽을 계속 통과시켜 자가 유발 장애 방지

속도 제한 로직 진화

  • 초기 토큰 버킷 방식

    • 초기에는 네트워크 데이터 플레인의 각 프록시에서 토큰 버킷 알고리듬 적용
    • 각 프록시가 로컬 요청 수를 추적하고 시간에 따라 토큰을 보충, 사용 가능한 토큰 수에 따라 요청 허용/거부
    • 토큰 보충률은 프록시의 로컬 부하와 글로벌 한도의 비율로 계산: ratio × limitRPS
    • 버스트 트래픽 대응을 위해 미사용 토큰을 순환 버퍼에 저장, 기본 10초(최대 20초까지 설정 가능) 동안 유지
    • 프로덕션에서 공정성과 확장성 문제 노출: 호출자 수가 한도를 초과하면 용량의 공정 분배 불가, 개별 호스트의 버스트 트래픽이 글로벌 한도 이하에서도 조기 드롭 발생
  • Drop-by-Ratio 도입

    • 집계된 글로벌 부하가 설정 한도를 초과하면 클라이언트가 확률적으로 요청의 일정 비율을 드롭
    • 예: 호출자의 집계 RPS가 한도의 1.5배이면 모든 인스턴스에서 약 33% 드롭, 공식: drop_ratio = (actual_rps - limit_rps) / actual_rps
    • 컨트롤 플레인이 수 초마다 업데이트하는 글로벌 드롭 신호로, 초과 트래픽을 모든 호출자 인스턴스에 균등 스로틀링
    • 수백~수천 개의 호출자 인스턴스를 가진 대규모 게이트웨이형 서비스에서 특히 효과적
  • 통합 확률적 모델로 전환

    • GRL 성숙과 함께 토큰 버킷을 완전 폐기하고 컨트롤 플레인 기반 확률적 드롭 모델로 단일화
    • 두 알고리듬 동시 운영이 설정 복잡성과 네트워크 오버헤드를 증가시켰기 때문
    • 단일 모델로 통합하여 설정 간소화, 컨트롤 플레인 대역폭 절감, 글로벌 일관적 메커니즘 하에 모든 속도 제한 판단 통합
    • 트레이드오프: 매초 업데이트되는 글로벌 집계 데이터에 의존해 2~3초의 적용 지연 발생
      • 실무에서는 대부분의 워크로드에 무시할 수준이며, 매우 짧고 극단적인 버스트에서만 영향
  • 최종 설계: 컨트롤 플레인 지시 확률적 드롭

    • 현재 GRL에서 적용은 전적으로 네트워크 데이터 플레인의 클라이언트 레이어에서 발생
    • 요청 도착 시 처리 흐름:
      • 설정된 버킷(호출자, 프로시저, 또는 둘 다로 정의)에 요청 매칭
      • 해당 버킷에 활성 드롭 비율 지시가 있으면 그 비율에 따라 확률적 드롭
      • 드롭 지시 없으면 정상 전달
    • 핫 경로가 극도로 경량: 로컬 토큰 계산이나 요청별 컨트롤 플레인 통신 불필요, 단순 확률적 샘플링으로 인프로세스 판단
    • 애그리게이터와 컨트롤러가 전달 플레인 외부에서 복잡한 계산(요청 수 집계, 임계값 비교, 새 드롭 비율 계산)을 매초 수행
    • 이 설계로 초당 수억 건의 요청으로 확장하면서 수 초 이내의 글로벌 적용 정확도 유지

한도 설정

  • 서비스 소유자가 설정 파일에서 속도 제한 버킷을 정의
    • Scope: 글로벌, 리전별, 존별
    • 매칭 규칙: 호출자 이름, 프로시저, 또는 둘 다
    • 동작: deny(적용) 또는 allow(테스트용 섀도우 모드)
  • 목적지 서비스에 코드 변경 없이 투명하게 적용

운영 성과

  • 지연 시간 감소 및 오버헤드 제거

    • GRL 이전에는 많은 서비스가 요청마다 네트워크 왕복이 필요한 Redis 기반 제한기 사용
    • 서비스 메시 데이터 플레인에서 로컬 평가로 전환해 추가 홉 제거, 지연 시간 대폭 감소
    • P50 지연 시간 약 1ms 감소, P90은 수십 ms 감소, P99.5에서는 수백 ms에서 수십 ms로 줄어 최대 90% 개선
  • 운영 간소화 및 자원 효율성

    • 서비스 메시 데이터 플레인 내 속도 제한 중앙화로 인프라 간소화
    • 쿼터 적용을 위한 별도 데이터 저장소나 캐싱 레이어 불필요
    • 이전에 속도 제한 전용이었던 상당수의 Redis 인스턴스 해제로 의미 있는 컴퓨트 효율성 확보
  • 안정성 향상 및 인시던트 대응

    • 배포 이후 GRL이 스파이크, 페일오버, 재시도 폭풍 시 반복적으로 과부하 방지
    • 서비스 메시에서 초과 트래픽을 확률적으로 셰딩하여 급격한 유입 부하 증가에도 일관된 응답 시간 유지
    • 핵심 서비스가 22K에서 367K RPS로 15배 트래픽 급증을 저하 없이 감내
    • DDoS 공격을 내부 시스템 도달 전 흡수
    • 인시던트 대응 시 프로덕션 엔지니어링 팀이 GRL로 특정 고트래픽 호출자/프로시저에 타겟 속도 제한 적용, 컨트롤 플레인 업데이트가 매초 전파되어 수 초 내 과부하 대응 가능
    • 서비스 재배포 없이 특정 트래픽 패턴을 빠르고 안전하게 스로틀링
    • 전체 규모: 초당 약 8,000만 건, 1,100개 이상의 서비스에서 동적 쿼터 적용

속도 제한 자동화: Rate Limit Configurator (RLC)

  • 수동 설정의 한계

    • GRL이 적용을 통합했지만, 한도 설정은 여전히 수동 작업 필요
    • 서비스 소유자가 YAML 파일로 호출자별·프로시저별 쿼터를 정의하고 트래픽 패턴 변화마다 조정
    • 수백 개의 마이크로서비스가 지속적으로 진화하는 환경에서 정적 설정은 빠르게 비신선화
      • 너무 엄격하면 정상 트래픽 피크에서도 스로틀링 발생
      • 너무 느슨하면 실제 용량 대비 과도하게 높은 한도로 보호 효과 미미
      • 변경이 대시보드 분석과 수동 튜닝에 의존
  • RLC의 작동 방식

    • RLC(Rate Limit Configurator) 가 GRL 설정을 자동으로 최신 상태 유지
    • 고정 스케줄 또는 설정 변경 시 즉시 다음 사이클 수행:
      • Uber의 관찰성 플랫폼에서 지난 수 주간의 메트릭 수집
      • 과거 피크와 버퍼 여유를 활용해 호출자·프로시저별 안전 한도 계산
      • 업데이트된 설정을 공유 설정 저장소에 기록
      • 기존 컨트롤 플레인을 통해 GRL에 새 한도 푸시
    • 이 클로즈드 루프 프로세스로 한도가 실제 트래픽과 함께 진화, 수동 개입 최소화
  • 확장 가능한 설계

    • RLC는 처음부터 다중 속도 제한 계산 전략 지원 설계
    • 기본 정책은 과거 RPS 데이터 기반이지만, 새로운 정책 유형을 모듈식으로 추가 가능
    • 매핑·위치 데이터 서비스 등은 트래픽 예측과 사전 계획된 용량을 반영하는 예측 모델 사용, 과거 추세 대신 미래 부하를 예측
    • 사전 결정된 계약적·운영적 합의에 의한 고정 쿼터 할당 방식도 지원
    • 모듈식 인터페이스를 통해 서비스 도메인별로 근실시간 트래픽 패턴, 예측, 정적 쿼터 중 적합한 계산 로직 선택 가능
  • 섀도우 모드와 검증

    • 안전을 위해 섀도우 모드로 한도를 생성·모니터링하되 미적용 가능
    • 서비스 소유자가 프로덕션에서 속도 제한의 동작을 관찰한 후 활성화
    • 전용 대시보드와 알림이 관찰 트래픽과 가상 드롭을 시각화하여 롤아웃 전 신뢰도 확보
  • 자동화 효과

    • 수천 개의 속도 제한 규칙이 수동 편집 없이 자동 업데이트
    • 동일한 공식과 데이터 소스로 모든 서비스에 걸쳐 일관된 정책 생성
    • 다양한 정책 유형으로 팀이 워크로드에 최적화된 계산 로직 선택·확장 가능
    • 섀도우 모드로 적용 전 정확성 보장

향후 방향

  • RLC 도입 이후에도 버퍼 튜닝 확대, 설정 변경의 영향 범위를 줄이기 위한 리전별 속도 제한 도입, 라이브 트래픽 반응성을 높이기 위한 업데이트 빈도 증가 진행
  • Uber의 스로틀러 레이어가 애플리케이션에 더 가까운 곳에서 추가 과부하 보호 제공
  • 현재 GRL은 Uber의 다층 안정성 스택의 핵심 구성 요소로, 극한 부하에서도 플랫폼의 안정성과 공정성 유지