ES /docs

Api::V1::LinksController#create (avg 1832ms, max 1832ms)

RCA: Api::V1::LinksController#create Latency (1832ms)

Overview#

What Happened#

2026-05-26 06:32Z에 cupixworks-api 서비스의 Api::V1::LinksController#create 엔드포인트가 1832ms 응답 시간을 기록했다. DB 시간은 1.66ms에 불과했으며, 전체 지연은 외부 CupixGo 서비스에 대한 동기 HTTP 호출에서 발생했다. 이 패턴은 모든 리전에서 일관되게 ~1800-1900ms로 반복되고 있어 시스템적 문제이다.

Quick Facts#

Field Value
resource_name Api::V1::LinksController#create
top_frame app/controllers/api/v1/links_controller.rb:11
env production, us-west-2
deploy production-us-west-2-20260526t0459z0-dd7bd097-cupixworks
duration 1832ms (DB: 1.66ms, View: 0.12ms)

Timeline#

  1. 2026-05-26 06:32:39Z — LinksController#create 요청 시작 (user: mark.lee@cupix.com)
  2. 2026-05-26 06:32:42Z — 응답 완료 (HTTP 200, 1830.51ms)
  3. 2026-05-26 06:33:18Z — 동일 사용자 후속 요청 243ms로 정상 응답

Error Log#

Datadog Logs

json
{
  "resource_name": "Api::V1::LinksController#create",
  "service": "cupixworks-api",
  "occurrences": 1,
  "avg_ms": 1832,
  "max_ms": 1832,
  "sample_trace_id": "756110360056982764"
}

Impact#

  • Service: cupixworks-api
  • 발생 횟수: 1 (이번 클러스터), 다만 최근 30시간 동안 모든 호출에서 동일 패턴 반복
  • 최초 발생: 2026-05-26T06:32:39.064Z
  • 최근 발생: 2026-05-26T06:32:39.064Z
  • 영향 범위: 링크 생성(URL 단축) 기능을 사용하는 모든 사용자 (모든 리전)

Root Cause Summary#

LinksController#create는 CupixGo 외부 서비스(go.{APP_HOST}/api/v1)에 동기 HTTP 요청을 보내 URL 단축 링크를 생성한다. 이 외부 서비스의 응답 시간이 일관되게 ~1800ms로 느려, 전체 API 응답 시간이 그대로 영향을 받는다. DB 쿼리(1.66ms)나 뷰 렌더링(0.12ms)은 무시할 수 있는 수준이며, 1830ms 전부가 외부 서비스 대기 시간이다. 이는 특정 시점의 일시적 문제가 아니라, 여러 리전(us-west-2, ap-southeast-2, ap-southeast-1)과 호스트에서 동일하게 재현되는 시스템적 문제이다.

Technical Analysis#

Code Path#

  • Entry point: app/controllers/api/v1/links_controller.rb:4 (create action)
  • External call: app/controllers/api/v1/links_controller.rb:11 (api_instance.link_create_link)
  • API client setup: app/controllers/api/v1/links_controller.rb:51-65 (api_instance method)
app/controllers/api/v1/links_controller.rb:4-23ruby
def create
  create_link_request = CupixGo::CreateLinkRequest.new(
    url: params[:url],
    key: params[:key]
  )

  begin
    result = api_instance.link_create_link(create_link_request)  # ← 1830ms 소요
  rescue CupixGo::ApiError => e
    if [400, 401, 403].include?(e.code)
      raise Cupix::Errors::Parameter.new(code: 'PRM12000', reason: e.to_s, message: e.message)
    end

    raise Cupix::Errors::System.new(code: 'SYS10000', reason: e.to_s, message: e.message)
  else
    render_json 200, {
      shorten_url: "#{@schema}://#{$CONFIG[:cupix_go_host]}/#{result.key}"
    }
  end
end
app/controllers/api/v1/links_controller.rb:51-65ruby
def api_instance
  configuration = CupixGo::Configuration.new do |config|
    config.host = "#{$CONFIG[:cupix_go_host]}/api/v1"
    config.scheme = $CONFIG[:cupix_go_scheme] || 'https'
  end
  configuration.class_eval do
    def base_url(operation = nil)
      "#{scheme}://#{[host, base_path].join('/').gsub(%r{/+}, '/')}".sub(%r{/+\z}, '')
    end
  end

  api_client = CupixGo::ApiClient.new(configuration)
  api_client.config.access_token = request.headers['x-cupix-auth']
  CupixGo::LinkApi.new(api_client)
end

실행 흐름:

  1. create 액션이 CupixGo::CreateLinkRequest 객체를 생성 (즉시 완료)
  2. api_instance 메서드가 매 요청마다 새로운 Configuration, ApiClient, LinkApi 인스턴스를 생성 (connection pooling 없음)
  3. link_create_linkhttps://go.{APP_HOST}/api/v1로 동기 HTTP POST 요청 전송
  4. CupixGo 서비스가 ~1800ms 후에 응답 반환
  5. 응답을 받아 shorten_url로 렌더링

기대 동작: 링크 생성은 단순 CRUD 작업으로 100-300ms 이내 응답이 기대됨 실제 동작: CupixGo 서비스 응답 대기로 인해 1800-1900ms 일관 소요

Log Evidence#

Datadog 검색 쿼리:

text
service:cupixworks-api @http.url_details.path:"/api/v1/links" @duration:>500000000

핵심 로그 (대표 요청):

json
{
  "timestamp": "2026-05-26T06:32:42.355Z",
  "message": "[200] POST /api/v1/links (Api::V1::LinksController#create)",
  "duration_ms": 1830.51,
  "db_ms": 1.66,
  "view_ms": 0.12,
  "host": "ip-10-1-19-190.us-west-2.compute.internal",
  "request_id": "f230bcfe-d8cd-4313-929e-3760f964b1a4",
  "user": "mark.lee@cupix.com",
  "params": {"key": "daidan-sv0giv"}
}

여러 리전에서의 일관된 지연 패턴:

text
2026-05-26T06:32:42Z | us-west-2      | 1830.51ms | DB 1.66ms
2026-05-25T21:31:06Z | ap-southeast-2 | 1867.73ms | DB 13.13ms
2026-05-25T16:50:55Z | us-west-2      | 1795.22ms | DB 2.10ms
2026-05-25T05:05:19Z | ap-southeast-2 | 1885.00ms | DB 2.64ms
2026-05-25T04:58:04Z | ap-southeast-1 | 1851.49ms | DB 2.44ms

모든 요청에서 DB 시간은 무시 가능(1-13ms)하며, 전체 1800-1900ms가 외부 서비스 호출에 소요됨.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 CupixGo 외부 서비스의 높은 기본 응답 시간이 원인 모든 리전에서 일관된 ~1800ms, DB/View 시간 무시 가능, 코드에서 동기 HTTP 호출 확인 (links_controller.rb:11) Confirmed
H2 DB 쿼리 지연 또는 lock contention DB 시간 1.66ms로 극히 짧음, 동일 호스트의 다른 요청도 DB 시간과 무관한 지연 Rejected
H3 호스트 과부하로 인한 CPU/메모리 경합 동일 시간대 호스트에서 여러 느린 요청 존재 다른 리전/호스트에서도 동일 패턴(~1800ms), 호스트별 차이 없음 Rejected
H4 API Client 인스턴스 재생성 오버헤드 매 요청마다 Configuration/ApiClient/LinkApi 새로 생성, class_eval 메타프로그래밍 사용 객체 생성은 수 ms 수준, 1800ms를 설명하기에 부족 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • CupixGo 서비스(go.{APP_HOST}) 자체의 응답 시간을 조사해야 한다. 서비스 내부에서 왜 ~1800ms가 걸리는지 확인 필요.
  • CupixGo 서비스에 대한 APM 트레이싱 또는 health check 추가하여 내부 병목 지점 파악.

단기 개선 (1주 이내)#

  • api_instance 메서드에서 매 요청마다 새로 생성하는 대신 connection pooling 또는 persistent HTTP connection을 활용하도록 변경. TLS handshake 오버헤드가 반복되고 있을 가능성.
  • CupixGo API 호출에 timeout 설정 추가 (현재 timeout 없이 무한 대기 가능). 예: open_timeout: 5, read_timeout: 5.
  • links_controller.rb:56-60class_eval 메타프로그래밍을 제거하고, CupixGo gem 설정을 initializer에서 한 번만 수행하도록 리팩터링.

장기 개선 (재발 방지)#

  • 링크 생성을 비동기 처리로 전환 검토: 클라이언트에 즉시 응답하고, 백그라운드에서 CupixGo 호출 후 결과를 push/poll 방식으로 전달.
  • CupixGo 서비스 자체의 성능 최적화 (내부 아키텍처 검토 필요).
  • 외부 서비스 호출이 있는 모든 컨트롤러에 대해 timeout 정책과 circuit breaker 패턴 적용.

Monitoring#

  • CupixGo 서비스 응답 시간 메트릭 추가
  • LinksController#create p95/p99 latency 알림 설정
text
service:cupixworks-api resource_name:"Api::V1::LinksController#create" @duration:>1000000000
  • CupixGo 서비스 자체의 APM 트레이싱 도입으로 내부 병목 모니터링

Risk Assessment#

  • Risk level: low (기능 자체는 정상 동작, HTTP 200 응답)
  • 예상 복잡도: standard (CupixGo 서비스 내부 조사 필요, timeout/pooling 추가는 간단)