API 속도 제한

API 속도 제한 (Rate limiting)

컨트롤러가 모든 API 요청을 처리하려고 하면 컨트롤러가 요청에 압도되는 상황이 생길 수 있어요. 컨트롤러가 리소스를 고갈시키거나, 데이터베이스 서버를 압도해서 그 리소스를 고갈시킬 수도 있죠. API 속도 제한을 사용하면 API 요청의 속도에 한도를 설정해서 리소스를 관리하고 압도당하는 것을 막을 수 있어요.

출처: HashiCorp Boundary docs

본문

할당량 (Quotas)

Boundary는 주어진 시간 동안의 요청 수를 추적하는 할당량을 만들어요. 기본적으로 Boundary는 인증 토큰별, IP 주소별, 그리고 전체 총계로 요청 수를 추적해요. Boundary는 갑작스러운 요청 폭주가 있을 때 메모리를 너무 많이 소비하지 않도록 할당량 추적을 위해 메모리의 일부를 예약해 둬요.

Boundary가 할당량을 저장할 수 없으면 503 HTTP 상태 코드로 요청을 제한해요. api_rate_limit_max_quotas 변수로 Boundary가 허용하는 최대 할당량 수를 설정할 수 있어요. 할당량 추적을 모니터링할 수 있는 두 가지 메트릭도 있어요.

  • boundary_controller_api_ratelimiter_quota_storage_capacity
  • boundary_controller_api_ratelimiter_quota_storage_usage

기본 한도 (Default limits)

API 속도 제한은 컨트롤러에서 적용돼요. 리소스와 액션의 각 조합마다 별도의 설정 가능한 한도가 있어요. 기본적으로 list 액션의 한도는 다음과 같아요.

  • 인증 토큰별 30초당 150개 요청
  • IP 주소별 30초당 1,500개 요청
  • 전체 30초당 1,500개 요청

다른 모든 액션의 기본 한도는 다음과 같아요.

  • 인증 토큰별 30초당 3,000개 요청
  • IP 주소별 30초당 30,000개 요청
  • 전체 30초당 30,000개 요청

기본 설정을 덮어쓰고 다른 구체적 한도를 설정하려면 컨트롤러 구성의 api_rate_limit 스탠자를 사용해요.

속도 제한 HTTP 헤더 (Rate limiting HTTP headers)

컨트롤러 API에 요청하는 클라이언트는 HTTP 응답 헤더를 검사해서 설정된 한도와 현재 사용량을 이해할 수 있어요. 각 응답에는 RateLimit과 RateLimit-Policy 헤더가 포함돼요.

요청이 속도 제한되면 Boundary는 Retry-After 헤더와 함께 429 HTTP 상태 코드를 클라이언트에 보내요. Retry-After 헤더에는 클라이언트가 요청을 다시 보내기 전에 기다려야 하는 초 수가 들어 있어요.

자세한 내용은 HTTP 헤더를 참고해요.

더 알아보기 (More information)

구체적인 api_rate_limit 구성 옵션은 컨트롤러 스탠자 문서를 참고해요. 몇 가지 예시 구성은 아래와 같아요.

속도 제한 구성 예시 (Rate limiting configuration examples)

다음 예시는 모든 리소스와 액션에 동일한 한도를 적용하는 간단한 구성이에요.

controller {
  # 모든 리소스와 액션의 총 한도
  api_rate_limit {
    resources = ["*"]
    actions   = ["*"]
    per       = "total"
    limit     = 500
    period    = "1s"
  }

  # 모든 IP 주소의 모든 리소스/액션 한도.
  # 토큰을 위조하거나 인증되지 않은 엔드포인트를 스팸하는 악성 호스트를 막기 위함.
  api_rate_limit {
    resources = ["*"]
    actions   = ["*"]
    per       = "ip-address"
    limit     = 100
    period    = "1s"
  }

  # 모든 인증된 요청의 한도. 한 사용자가 총 한도를 모두 소비하는 것을 막기 위함.
  api_rate_limit {
    resources = ["*"]
    actions   = ["*"]
    per       = "auth-token"
    limit     = 100
    period    = "1s"
  }
}

다음 예시는 속도 제한을 비활성화하는 구성이에요. 이미 리버스 프록시 같은 외부 시스템을 사용해서 속도 제한을 적용하고 있다면 속도 제한을 끄고 싶을 수 있어요.

controller {
  api_rate_limit_disable = true
}

다음 예시는 대부분의 엔드포인트에 기본 설정을 사용하지만 단일 오버라이드를 구성해요.

controller {
  api_rate_limit {
    resources = ["target"]
    actions   = ["list"]
    per       = "auth-token"
    limit     = 10
    period    = "1s"
  }
}

다음 예시는 더 복잡해요. 먼저 모든 리소스와 액션에 적용할 몇 가지 기본값을 설정하고, 그다음 서로 다른 한도를 가진 몇 가지 특정 엔드포인트를 구성해요.

controller {
  # 모든 리소스와 액션의 총 한도
  api_rate_limit {
    resources = ["*"]
    actions   = ["*"]
    per       = "total"
    limit     = 500
    period    = "1s"
  }

  # 모든 list 작업의 총 한도.
  # list 액션은 상대적으로 비용이 많이 들기 때문에 전체 상한을 설정.
  api_rate_limit {
    resources = ["*"]
    actions   = ["list"]
    per       = "total"
    limit     = 200
    period    = "1s"
  }

  # 모든 리소스/액션의 IP 주소 한도.
  # 토큰을 위조하거나 인증되지 않은 엔드포인트를 스팸하는 악성 호스트를 막기 위함.
  api_rate_limit {
    resources = ["*"]
    actions   = ["*"]
    per       = "ip-address"
    limit     = 50
    period    = "1s"
  }

  # 모든 인증된 요청의 한도.
  # 위에서 설정한 총 list 한도를 한 사용자가 모두 소비하지 못하도록
  # 모든 인증 요청의 기본값을 실질적으로 설정. 뒤따르는 한도는
  # 특정 리소스/액션 집합에 대해 기본값을 덮어쓸 수 있음.
  api_rate_limit {
    resources = ["*"]
    actions   = ["*"]
    per       = "auth-token"
    limit     = 100
    period    = "1s"
  }

  # 인증 토큰별 모든 list 작업의 한도.
  # 일반적으로 더 비싸므로 합리적인 기본값을 설정.
  api_rate_limit {
    resources = ["*"]
    actions   = ["list"]
    per       = "auth-token"
    limit     = 50
    period    = "1s"
  }

  # 인증 토큰별 targets/sessions list 한도.
  # 클라이언트가 자주 나열하길 원하지만 사용자당 수가 많으면 더 비쌀 수 있는
  # 리소스들. 낮은 한도는 refresh 토큰과 캐싱 사용을 유도.
  api_rate_limit {
    resources = ["target", "session"]
    actions   = ["list"]
    per       = "auth-token"
    limit     = 20
    period    = "1s"
  }

  # 인증 토큰별 authorize-session 한도
  api_rate_limit {
    resources = ["target"]
    actions   = ["authorize-session"]
    per       = "auth-token"
    limit     = 150
    period    = "1s"
  }
}

더 알아보기 (Learn more)