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#
- 2026-05-26T04:29:31Z — 최초 slow trace 감지 (us-west-2)
- 2026-05-26T05:01-05:02Z — us-west-2에서 DB contention 스파이크 (DB time 500-640ms)
- 2026-05-26T08:29-11:23Z — ap-southeast-2에서 지속적 latency (DB 4-7ms, 전체 800-1230ms)
- 2026-05-27 — RCA 분석 완료
Error Log#
{
"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:81→lib/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:
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에서 실행:
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)
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 쿼리:
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 (보조 병목):
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 검색 쿼리:
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는 빠르지만 전체 느림):
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):
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— Cognitoget_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 의존을 제거.
subclaim으로 로컬 DB에서 사용자를 조회하면 network latency가 완전히 사라진다. - Admin API 엔드포인트에 대해 request lifecycle 단계별(auth, ES query, permission_joins, serialization) timing을 Datadog APM custom span으로 분리하여 상시 모니터링.
Monitoring#
- Cognito 캐시 miss 빈도:
service:cupixworks-api "Fetching an user from Cognito" | stats count by @region
- Admin API latency P95 알림:
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::admin::pointcloudscontroller#index} > 800
- 리전별 latency 비교:
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건으로 낮음.