check_voxels_uploading S3 ListObjectsV2 high latency
RCA: Api::V1::PointcloudsController#check_voxels_uploading Latency (avg 2292ms, max 5467ms)
Overview#
What Happened#
ap-southeast-2 리전에서 Api::V1::PointcloudsController#check_voxels_uploading 엔드포인트가 평균 2292ms, 최대 5467ms의 응답 시간을 보임. 이 엔드포인트는 S3 ListObjectsV2 API 호출을 동기적으로 수행하여 voxel 파일 업로드 완료 여부를 확인하는데, ap-southeast-2 리전에서의 S3 API 호출 지연이 주요 원인.
Quick Facts#
| Field | Value |
|---|---|
| resource_name | Api::V1::PointcloudsController#check_voxels_uploading |
| avg_duration | 2292ms |
| max_duration | 5467ms |
| env | production, ap-southeast-2 |
Timeline#
- 2026-05-26T04:04:13Z — 최초 고지연 요청 감지
- 2026-05-26T05:57:12Z — 마지막 고지연 요청 감지 (총 4건)
- 2026-05-26 — RCA 분석 완료
Error Log#
{
"resource_name": "Api::V1::PointcloudsController#check_voxels_uploading",
"service": "cupixworks-api",
"occurrences": 4,
"avg_ms": 2292,
"max_ms": 5467,
"sample_trace_id": "2129367162740673873"
}
Impact#
- Service:
cupixworks-api - 발생 횟수: 4
- 최초 발생: 2026-05-26T04:04:13.979Z
- 최근 발생: 2026-05-26T05:57:12.032Z
- 영향:
ap-southeast-2리전 사용자의 voxel 업로드 확인 요청이 수 초간 블로킹됨. 기능 장애는 아니나 UX 저하.
Root Cause Summary#
check_voxels_uploading 엔드포인트는 요청 처리 중 S3 ListObjectsV2 API를 동기적으로 호출하여 voxel 파일 존재 여부를 확인한다. ap-southeast-2 리전의 API 서버에서 S3 버킷으로의 네트워크 왕복 시간(RTT)이 높아 17초의 지연이 발생한다. APM 메트릭에서 동일 리전의 동일 엔드포인트에 대해 1.1s6.99s의 응답 시간이 관측됨. 또한 voxel 파일이 존재하는 경우 done_voxel_state 전환 시 Cupix::VoxelService.add_partition HTTP 호출과 remove_cache HTTP 호출이 추가로 동기 실행되어 지연을 가중시킨다.
Technical Analysis#
Code Path#
- Entry point:
app/controllers/concerns/voxels_controller.rb:33 - Repository layer:
app/repositories/concerns/voxels_repository.rb:33 - Model method:
app/models/concerns/voxel_module/s3.rb:39 - S3 call:
app/services/cupix/storage_service.rb:64(object_list→list_objects_v2) - State transition:
app/models/concerns/voxel_module/reality_capture.rb:55(before_transition to: :done) - External HTTP call:
app/services/cupix/voxel_service.rb:115(add_partition)
1. Controller → Repository → Model 위임:
def check_voxels_uploading
@model = repository_instance.check_voxels_uploading
render_api Renderable.new({
contents: @model,
serializer: VoxelsSerializer,
serializer_option: {
fields: {
voxels: @fields
}
}
})
end
2. S3 ListObjectsV2 호출 (주요 병목):
def check_voxels_uploading
self.voxels_objects = voxels_object_key_list # S3 API 호출
if self.voxels_objects.present?
Cupix::Logger.info('Voxels uploading is done', class: self.class.name, function: __method__, id: id)
self.done_voxel_state # 상태 전환 → 추가 HTTP 호출 발생
else
self.missing_voxel_state
end
end
voxels_object_key_list는 Cupix::StorageService.object_key_list를 호출하며, 내부적으로 S3 list_objects_v2를 실행:
def object_list(storage_option: nil, **kwargs)
opts = parse_storage_option(storage_option).merge(kwargs)
check_required_params(opts, %i[region bucket_name prefix])
client(storage_option: storage_option)
.list_objects_v2(
bucket: storage_option.s3_hosting_bucket_name,
prefix: opts[:prefix],
delimiter: 'delimiter'
)
.contents
.reject do |object|
object.key.end_with?('/')
end
end
3. done 상태 전환 시 동기 HTTP 호출:
before_transition to: :done do |model, transition|
if model.respond_to?(:increase_voxel_revision)
model.increase_voxel_revision
Cupix::VoxelService.add_partition(model: model) # 동기 HTTP PUT
if model.has_attribute?(:level_id)
Cupix::VoxelService.remove_cache(model: model.level) # 동기 HTTP 호출
end
true
end
end
4. add_partition HTTP 호출:
def add_partition(model: nil, session: nil)
# ...
response = Cupix::HttpClient.put("#{$CUPIX_VOXEL_SERVICE_URL}/add_partition", body.to_json, headers)
body = JSON.parse(response.body)
# ...
end
기대 동작: API 요청은 빠르게 S3 상태를 확인하고 응답해야 함 (목표: <500ms).
실제 동작: S3 list_objects_v2 호출이 ap-southeast-2에서 15초 소요. voxel이 존재하는 경우 7초 총 지연.add_partition + remove_cache 추가 HTTP 호출로 2
Log Evidence#
APM 메트릭 조회 (ap-southeast-2 리전):
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::pointcloudscontroller_check_voxels_uploading,region:ap-southeast-2}
결과 (24시간, 초 단위):
{
"times": [1779759300000, 1779763500000, 1779768000000, 1779771900000, 1779772500000, 1779774900000, 1779780600000, 1779781500000],
"values": [1.115319, 6.556662, 3.255954, 1.347751, 6.986963, 6.782132, 6.783877, 5.589174]
}
"Voxels uploading is done" 로그 (인시던트 시간대):
{
"timestamp": "2026-05-26T06:48:01.912Z",
"message": "Voxels uploading is done",
"class": "Capture",
"function": "check_voxels_uploading",
"region": "us-west-2"
}
참고: us-west-2 리전에서도 동일 엔드포인트가 호출되지만, 해당 리전은 지연 문제 없음. ap-southeast-2에서만 고지연 발생.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | S3 list_objects_v2 크로스리전 호출 지연 |
APM 메트릭: ap-southeast-2에서 1.1~6.99s 응답. StorageService.object_list는 pagination 없이 단일 API 호출. us-west-2는 정상. |
— | Confirmed |
| H2 | voxel-service add_partition HTTP 호출 지연 |
done_voxel_state 전환 시 동기 HTTP PUT 호출 (voxel_service.rb:115). 외부 서비스 RTT가 총 지연에 합산됨. |
4건 모두 동일 패턴이 아닐 수 있음 (voxel 미존재 시 호출 안 됨) | Contributing |
| H3 | S3 버킷에 대량 오브젝트로 listing 느림 | list_objects_v2는 delimiter 사용하여 prefix 범위 제한됨. 1000개 제한 내 결과. |
delimiter 사용으로 범위가 좁혀져 대량 오브젝트 문제는 아닌 것으로 판단 | Rejected |
| H4 | DB 쿼리 또는 모델 로딩 지연 | — | APM 메트릭이 전체 request duration만 보여주나, 코드 경로상 DB 쿼리는 모델 로딩(before_action)에서만 발생하며 핵심 로직은 S3/HTTP 호출 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
app/models/concerns/voxel_module/s3.rb:39-48:check_voxels_uploading메서드에서done_voxel_state전환을 비동기(Sidekiq worker)로 분리하여 S3 확인 후 즉시 응답 반환.add_partition과remove_cache호출을 별도 worker에서 처리.
단기 개선 (1주 이내)#
app/services/cupix/storage_service.rb:64-79:object_list에max_keys: 1옵션 추가 —check_voxels_uploading은 파일 존재 여부만 확인하면 되므로 전체 목록을 가져올 필요 없음.max_keys: 1로 S3 응답 시간 단축.ap-southeast-2리전의 API 서버가 같은 리전의 S3 버킷에 접근하도록 storage_option 구성 검증. 크로스리전 호출이면 같은 리전 버킷 사용 권장.
장기 개선 (재발 방지)#
- Voxel 업로드 완료 확인을 polling 방식에서 S3 Event Notification (또는 EventBridge) 기반 push 방식으로 전환. 클라이언트가 업로드 완료 시 콜백을 보내거나, S3 이벤트가 상태 전환을 트리거하도록 아키텍처 변경.
- 모든 동기 외부 서비스 호출(
add_partition,remove_cache)을 비동기 worker로 이관하여 API 응답 시간에서 제거.
Monitoring#
- APM 메트릭 알림 추가:
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::pointcloudscontroller_check_voxels_uploading,region:ap-southeast-2} > 2
- S3 API 호출 duration 별도 custom metric 추가 (StorageService 레벨)
ap-southeast-2리전의 p95/p99 latency 모니터 설정
Risk Assessment#
- Risk level: low
- 예상 복잡도: standard
- 기능 장애 없음 (모든 요청 200 OK), 응답 지연만 발생. 사용자 체감 품질 저하이나 데이터 손실이나 에러는 없음.