ES /docs

Api::V1::Admin::PointcloudsController#index (avg 1112ms, max 1112ms)

RCA: Api::V1::Admin::PointcloudsController#index Latency (avg 1054ms, max 1112ms)

Overview#

What Happened#

2026-05-26 04:29~11:23 UTC 사이에 cupixworks-api 서비스의 Api::V1::Admin::PointcloudsController#index 엔드포인트에서 평균 1054ms, 최대 1112ms의 응답 지연이 us-west-2 및 ap-southeast-2 리전에서 3건 감지되었다. 모든 요청은 HTTP 200 정상 응답하였으나 500ms SLO 임계값을 초과했다. DB 쿼리 시간은 4-7ms에 불과하며 나머지 ~995ms는 Cognito 인증 외부 HTTP 호출과 cross-region 네트워크 latency에서 발생한다.

Quick Facts#

Field Value
resource_name Api::V1::Admin::PointcloudsController#index
cluster_type latency
avg_duration_ms 1054.7
max_duration_ms 1112
top_frame app/controllers/api/v1/admin/pointclouds_controller.rb:8
env production (us-west-2, ap-southeast-2)

Affected Teams#

Team / Domain Error Count Impact
cupixworks-api (Admin/QA) 3 Retool 관리 대시보드에서 pointcloud 목록 조회 시 ~1초 지연. 내부 editing/QA 팀 체감 성능 저하.

Timeline#

  1. 2026-05-26T04:29:31Z — 최초 slow trace 감지 (us-west-2)
  2. 2026-05-26T05:01-05:02Z — us-west-2에서 DB contention 스파이크 (DB time 500-640ms)
  3. 2026-05-26T08:29-11:23Z — ap-southeast-2에서 지속적 latency (DB 4-7ms, 전체 800-1230ms)
  4. 2026-05-27 — RCA 분석 완료

Error Log#

Datadog Logs

json
{
  "resource_name": "Api::V1::Admin::PointcloudsController#index",
  "service": "cupixworks-api",
  "occurrences": 1,
  "avg_ms": 1112,
  "max_ms": 1112,
  "sample_trace_id": "668033571993185258"
}

Impact#

  • Service: cupixworks-api
  • 발생 횟수: 3
  • 최초 발생: 2026-05-26T04:29:31.601Z
  • 최근 발생: 2026-05-26T11:23:25.670Z
  • 영향 범위: Retool 관리 대시보드 사용자 (cupix 내부 editing/QA 팀). 일반 사용자 API에는 영향 없음.

Root Cause Summary#

Admin::PointcloudsController#index 요청의 ~1000ms latency는 Cognito 인증 캐시 미스 시 발생하는 cross-region 외부 HTTP 호출이 주요 원인이다. lib/cupix/aws/cognito.rb:206에서 Rails.cache.fetch(expires_in: 1.hour)로 캐싱하지만, 캐시 만료 후 첫 요청에서 client.get_user(access_token:) 외부 호출이 실행된다. ap-southeast-2 리전에서 us-east-1 Cognito를 호출하면 RTT만 200-400ms 추가된다. DB 쿼리 자체는 4-7ms로 매우 빠르며, 요청 시간의 ~95%가 인증 미들웨어에서 소비된다. 보조 요인으로 permission_joins의 16-table LEFT JOIN 오버헤드와 us-west-2에서 관찰된 일시적 DB contention이 있다.

Technical Analysis#

Code Path#

  • Entry point: app/controllers/api/v1/admin/pointclouds_controller.rb:8
  • Authentication (before_action): lib/cupix/auth/verification.rb:81lib/cupix/aws/cognito.rb:209
  • Repository search: app/repositories/admin/pointcloud_repository.rb:31
  • Permission joins: app/repositories/base_repository.rb:70-82
  • Serialization: app/serializers/pointcloud_serializer.rb

1. Controller index action:

app/controllers/api/v1/admin/pointclouds_controller.rb:8-18ruby
def index
  pointclouds = repository_instance.search(
    Cupix::QueryOption::Pointcloud.new(get_query_option(enable_current_team: false), params)
  )

  render_api Renderable.new(
    search_result: pointclouds,
    is_collection: true,
    serializer_option: @serializer_option.merge(params: { current_user: current_user })
  )
end

2. Cognito 인증 (주요 병목) — before_action에서 실행:

lib/cupix/auth/verification.rb:79-81ruby
sub = verified_access_token.decoded_access_token.dig(0, 'sub')
# ...
user_response = Cupix::Aws::Cognito.get_user_by_access_token(access_token: access_token, sub: sub)
lib/cupix/aws/cognito.rb:203-217ruby
def get_user_by_access_token(access_token: nil, sub: nil)
  sub ||= ::JWT.decode(access_token, nil, false).first['sub']

  Rails.cache.fetch(user_cache_key(sub), expires_in: 1.hour) do
    Cupix::Logger.info("Fetching an user from Cognito: #{sub}", ...)

    response = client.get_user(access_token: access_token)  # 외부 HTTP call (300-500ms)
  rescue ::Aws::CognitoIdentityProvider::Errors::NotAuthorizedException
    raise Cupix::Errors::Unauthorized.new(code: 'AUTH20013', reason: 'Invalid access token')
  else
    Cupix::Aws::Cognito::UserResponse.new(user_response_hash(response))
  end
end

캐시 TTL이 1시간이므로, Retool 세션이 1시간 이상 지속되면 캐시 만료 후 첫 요청에서 Cognito HTTP call이 발생한다. ap-southeast-2에서 us-east-1 Cognito를 호출하면 cross-region 네트워크 latency(RTT 200-400ms)가 추가된다.

3. Admin repository — group_codes 조회 + ES 쿼리:

app/repositories/admin/pointcloud_repository.rb:31-34ruby
def _search(query_option = nil)
  set_query_option(query_option)
  group_codes = ::UserRepository.new(model: current_user).group_codes  # DB query: groups.pluck

4. BaseRepository#search — Permission JOINs (보조 병목):

app/repositories/base_repository.rb:70-82ruby
def search(query_option = nil)
  _search(query_option)

  begin
    contents = self.class.permission_joins(
      self.class.default_joins(self.response.records),
      self.current_user,
      skip_join: _skip_join?
    )
  rescue Elasticsearch::Transport::Transport::Errors::BadRequest => e
    # ...
  end
end

permission_joins는 16개 permission 테이블에 대한 LEFT JOIN을 구성한다. pagination 결과가 0건(total_entries: 0)이더라도 이 쿼리 구성이 실행된다.

Log Evidence#

Datadog 검색 쿼리:

text
service:cupixworks-api "Admin::PointcloudsController#index" @duration:>500
Time range: 2026-05-26T03:30:00Z to 2026-05-26T12:00:00Z

ap-southeast-2 — 지속적 latency (DB는 빠르지만 전체 느림):

text
Duration: 1230.46ms | DB: 6.82ms | View: 0.08ms | Host: ip-10-1-145-251.ap-southeast-2 | 08:29:52 UTC
Duration: 1117.84ms | DB: 4.31ms | View: 0.07ms | Host: ip-10-1-81-184.ap-southeast-2 | 07:48:36 UTC
Duration: 1054.71ms | DB: 5.12ms | View: 0.09ms | Host: ip-10-1-17-211.ap-southeast-2 | 10:15:08 UTC

DB time (4-7ms)과 전체 duration (1000-1230ms) 사이의 ~995ms gap이 일관적으로 관찰됨. 이 gap은 인증 미들웨어(Cognito HTTP call)에서 소비되는 시간과 일치.

us-west-2 — DB contention 스파이크 (05:01-05:02 UTC):

text
Duration: 1563.62ms | DB: 639.37ms | record.id=130125 | user: peter.nam@cupix.com
Duration: 598.98ms  | DB: 574.46ms | record.id=130124
Duration: 546.29ms  | DB: 523.20ms | record.id=130140

이 시간대에만 DB time이 비정상적으로 높으며 일시적인 DB lock contention 의심.

추가 확인 결과:

  • Error/Warn 로그: 0건 (service:cupixworks-api "PointcloudsController" status:error → 0건)
  • 모든 요청의 user_agent: Retool/2.0 (관리 대시보드 polling)
  • 대부분 total_entries: 0 반환 (빈 결과셋에도 동일한 latency)
  • eu-central-1 요청은 일관적으로 20-40ms (cross-region latency 없음 확인)

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Cognito 인증 캐시 미스 시 cross-region HTTP latency DB 4-7ms vs 전체 1000ms의 ~995ms gap; cognito.rb:206 캐시 TTL 1시간; ap-southeast-2→us-east-1 RTT 200-400ms; eu-central-1은 20-40ms로 정상 (Cognito 리전과 가까움) 캐시 hit/miss 여부를 직접 확인하는 로그 없음 ("Fetching an user from Cognito" 로그가 miss 시에만 출력되나 검색 미수행) Confirmed
H2 permission_joins 16-table LEFT JOIN 오버헤드 pointcloud_repository.rb:40-264 — 매 요청마다 15개 LEFT JOIN 실행; us-west-2에서 DB 639ms 관찰 ap-southeast-2에서 DB time 4-7ms로 정상; 빈 결과셋에도 latency 발생하므로 JOIN 자체보다 인증이 주요 원인 Partially confirmed (us-west-2 spike에만 기여)
H3 Elasticsearch 쿼리 자체 성능 문제 ES 쿼리에 should 조건 다수 추가됨 DB time에 ES 응답 포함되며 4-7ms로 매우 빠름; ES circuit breaker 에러 없음 Rejected
H4 Ruby GC pause 또는 thread contention 간헐적 발생 패턴과 부합 가능 동일 호스트에서 일관적으로 발생; 여러 호스트에서 동일 패턴 관찰 (GC라면 sporadic할 것) Rejected
H5 Serializer N+1 쿼리 default_joins에 eager loading 없음 (admin/pointcloud_repository.rb:108); pointcloud_serializer.rb:54 levels 접근 View time 0.07-0.09ms로 매우 빠름; total_entries: 0인 경우 serialization 대상 없음에도 latency 동일 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • lib/cupix/aws/cognito.rb:206 — Cognito 캐시 TTL을 1시간에서 access_token 만료 시간(보통 1일)에 맞춰 연장하는 것을 검토. Retool 세션이 장시간 유지되므로 캐시 갱신 빈도를 줄인다.
  • lib/cupix/auth/verification.rb:81 — Cognito get_user_by_access_token 호출 전후로 latency 로그 추가. 캐시 hit/miss를 구분하여 기록하고 실제 외부 호출 시간을 측정한다.

단기 개선 (1주 이내)#

  • ap-southeast-2 리전에서의 Cognito 호출 latency를 줄이기 위해, 해당 리전에 Cognito User Pool을 생성하거나 리전별 엔드포인트를 사용하도록 변경한다.
  • BaseRepository#search에서 Elasticsearch 결과가 0건일 때 permission_joins를 skip하는 early return 추가. 현재 빈 결과셋에도 불필요하게 permission 쿼리를 구성한다.

장기 개선 (재발 방지)#

  • Cognito 인증을 JWT claim 기반 local verification으로 전환하여 외부 HTTP 의존을 제거. sub claim으로 로컬 DB에서 사용자를 조회하면 network latency가 완전히 사라진다.
  • Admin API 엔드포인트에 대해 request lifecycle 단계별(auth, ES query, permission_joins, serialization) timing을 Datadog APM custom span으로 분리하여 상시 모니터링.

Monitoring#

  • Cognito 캐시 miss 빈도:
text
service:cupixworks-api "Fetching an user from Cognito" | stats count by @region
  • Admin API latency P95 알림:
text
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::admin::pointcloudscontroller#index} > 800
  • 리전별 latency 비교:
text
p95:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::admin::pointcloudscontroller#index} by {region}

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: standard
  • 사유: 일반 사용자 대상 API에는 영향 없으며 Retool 관리 대시보드에 국한된 성능 이슈. 기능 장애(error)가 아닌 latency 문제이며 모든 요청이 HTTP 200으로 정상 응답. 발생 빈도 3건으로 낮음.