Skip to content

[Task] insight 로그 스캔 효율 — 파티션 prefix 필터 + 증분 집계 (#53 후속) #58

Description

@jkas2016

Background

PR #53hostdoc insight <code>는 로그 버킷의 .gz 객체를 나열 → 다운로드 → gunzip → W3C 파싱 → 집계하는 CLI-side 파이프라인이다. PR 본문도 "기본(--days 없음)은 ~30일 전체를 스캔한다"를 follow-up으로 명시했다.

이 이슈는 그 스캔 경로의 두 가지 비효율을 함께 다룬다 — 둘 다 runInsight의 같은 루프에 있어 한 PR로 처리하는 게 자연스럽다.

Problem

1. 서버측 prefix 필터를 안 쓴다

src/commands/insight.ts:

const allKeys = await listKeys(s3, logBucket, "");
const keys = filterLogKeys(allKeys, { since });

빈 prefix로 버킷 전체를 나열한 뒤 클라이언트에서 날짜를 거른다. 그런데 로그는 이미 파티션되어 있다 — infra/main.tfsuffix_path = "{DistributionId}/{yyyy}/{MM}/{dd}/{HH}", 실제 키는 AWSLogs/<account-id>/CloudFront/<DistId>/<yyyy>/<MM>/<dd>/<HH>/... 형태다(파티셔닝 문서 — prefix 없는 버킷 ARN을 destination으로 주면 CloudFront가 AWSLogs/{account-id}/CloudFront/를 앞에 붙인다).

--days 1이어도 30일치 전체 키를 페이징한 뒤 버린다. ListObjectsV2는 1000개씩 페이징하므로 트래픽이 많은 배포에서는 왕복이 그대로 늘어난다.

2. 파싱된 레코드를 전부 메모리에 쌓는다

const records: LogRecord[] = [];
for (const key of keys) {
  records.push(...parseCloudFrontLog(gunzipSync(gz).toString("utf8")));
}
return formatInsight(aggregateInsight(records, args.code), keys.length);

모든 로그 파일의 모든 요청(다른 문서 대상, 봇, 에셋 포함 — 필터는 aggregateInsight 안에서야 적용된다)이 하나의 배열에 남는다. 메모리는 O(전체 요청 수)로 증가한다. 파일 단위로 집계하면 O(고유 IP 수)로 떨어진다.

Scope

  • prefix 필터: 파티션 경로를 이용해 listKeys에 prefix를 넘긴다. 날짜 파티션이 {yyyy}/{MM}/{dd} 계층이라 단일 prefix로 임의 날짜 범위를 표현할 수 없으므로, 범위에 해당하는 일자별 prefix 목록을 만들어 나열하거나 최소한 AWSLogs/<acct>/CloudFront/<DistId>/ 까지는 좁힌다. 계정 ID를 모르므로 AWSLogs/ 수준부터 시작해도 유의미하다.
  • 증분 집계: aggregateInsight를 누적 가능한 형태로 바꾸거나(누적기 객체 주입), 파일별 부분 결과를 합치는 merge 함수를 추가. 배열 축적 제거.
  • 기존 순수 함수 테스트(test/insight.test.ts)를 유지하면서 누적 경로에 대한 테스트 추가.

Non-goals

  • 병렬 다운로드·동시성 튜닝 — 별개 최적화이고 S3 요청 비용/스로틀과 얽힌다.
  • Athena·S3 Select 등 서버측 쿼리로의 전환 — 아키텍처 변경 수준.
  • 결과 캐싱.

Acceptance criteria

  • --days N이 지정되면 나열되는 S3 키가 해당 범위로 좁혀진다 (mock 기준 ListObjectsV2 호출의 Prefix로 검증).
  • 여러 로그 파일을 처리해도 전체 레코드 배열을 유지하지 않는다.
  • 기존 hits / uniqueVisitors / range 출력이 동일하게 유지된다 (회귀 테스트).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions