>  기사  >  백엔드 개발  >  Node.js에서 Go까지: 단일 Zip으로 수천 개의 파일 다운로드 슈퍼차저

Node.js에서 Go까지: 단일 Zip으로 수천 개의 파일 다운로드 슈퍼차저

WBOY
WBOY원래의
2024-08-21 12:32:40821검색

From Node.js to Go: Supercharging Sownloads of Thousands of Files as a Single Zip

개발자로서 우리는 대규모 데이터 처리 및 전달을 처리할 때 종종 어려움에 직면합니다. Kamero에서는 최근 파일 전송 파이프라인의 심각한 병목 현상을 해결했습니다. 우리 애플리케이션을 사용하면 사용자는 특정 이벤트와 관련된 수천 개의 파일을 단일 zip 파일로 다운로드할 수 있습니다. S3 버킷에서 파일을 가져오고 압축하는 역할을 하는 Node.js 기반 Lambda 함수로 구동되는 이 기능은 사용자 기반이 증가함에 따라 메모리 제약과 긴 실행 시간으로 인해 어려움을 겪고 있었습니다.

이 게시물에서는 리소스가 부족한 Node.js 구현에서 대규모 S3 다운로드를 효율적으로 처리하는 간결하고 초고속 Go 솔루션으로의 여정을 자세히 설명합니다. 특정 이벤트에서 대량의 파일을 요청할 때 사용자에게 원활한 환경을 제공하기 위해 시스템을 최적화한 방법을 살펴보겠습니다. 이 모든 파일은 모두 편리한 단일 zip 다운로드로 패키지되어 있습니다.

도전

저희 원래 Lambda 함수는 대규모 이벤트 기반 파일 세트를 처리할 때 몇 가지 중요한 문제에 직면했습니다.

  1. 메모리 소비: 할당된 메모리가 10GB라도 더 큰 규모의 이벤트를 위해 20,000개 이상의 파일을 처리하면 기능이 실패합니다.
  2. 실행 시간: 파일이 많은 이벤트에 대한 Zip 작업이 너무 오래 걸리고 완료되기 전에 시간이 초과되는 경우도 있었습니다.
  3. 확장성: 이 기능은 증가하는 로드를 효율적으로 처리할 수 없어 인기 이벤트의 대용량 파일 세트를 사용자에게 제공하는 능력이 제한되었습니다.
  4. 사용자 경험: 느린 다운로드 준비 시간은 특히 파일 수가 많은 이벤트의 경우 사용자 만족도에 영향을 미쳤습니다.

Node.js 구현: 간략히 살펴보기

원래 구현에서는 s3-zip 라이브러리를 사용하여 S3 객체에서 zip 파일을 생성했습니다. 다음은 파일 처리 방법에 대한 간단한 정보입니다.

const s3Zip = require("s3-zip");

// ... other code ...

const body = s3Zip.archive(
  { bucket: bucketName },
  eventId,
  files,
  entryData
);

await uploadZipFile(Upload_Bucket, zipfileKey, body);

이 접근 방식은 효과가 있었지만 zip을 생성하기 전에 모든 파일을 메모리에 로드하여 메모리 사용량이 늘어나고 대용량 파일 세트의 경우 메모리 부족 오류가 발생할 수 있습니다.

Enter Go: 판도를 바꾸는 재작성

우리는 효율성과 내장된 동시성 기능을 활용하여 Go에서 Lambda 함수를 다시 작성하기로 결정했습니다. 결과는 놀라웠습니다.

  1. 메모리 사용량: 동일한 작업 부하에 대해 10GB에서 단 100MB로 줄었습니다.
  2. 속도: 기능이 약 10배 빨라졌습니다.
  3. 신뢰성: 20,000개 이상의 파일을 문제 없이 성공적으로 처리합니다.

Go 구현의 주요 최적화

1. 효율적인 S3 운영

우리는 v1에 비해 더 나은 성능과 더 낮은 메모리 사용량을 제공하는 Go v2용 AWS SDK를 사용했습니다.

cfg, err := config.LoadDefaultConfig(context.TODO())
s3Client = s3.NewFromConfig(cfg)

2. 동시 처리

Go의 고루틴을 사용하면 여러 파일을 동시에 처리할 수 있습니다.

var wg sync.WaitGroup
sem := make(chan struct{}, 10) // Limit concurrent operations

for _, photo := range photos {
    wg.Add(1)
    go func(photo Photo) {
        defer wg.Done()
        sem <- struct{}{} // Acquire semaphore
        defer func() { <-sem }() // Release semaphore

        // Process photo
    }(photo)
}

wg.Wait()

이 접근 방식을 사용하면 동시성 수준을 제어하여 시스템에 부담을 주지 않고 여러 파일을 동시에 처리할 수 있습니다.

3. 스트리밍 Zip 생성

모든 파일을 메모리에 로드하는 대신 zip 콘텐츠를 S3에 직접 스트리밍합니다.

pipeReader, pipeWriter := io.Pipe()

go func() {
    zipWriter := zip.NewWriter(pipeWriter)
    // Add files to zip
    zipWriter.Close()
    pipeWriter.Close()
}()

// Upload streaming content to S3
uploader.Upload(ctx, &s3.PutObjectInput{
    Bucket: &destBucket,
    Key:    &zipFileKey,
    Body:   pipeReader,
})

이 스트리밍 접근 방식을 사용하면 메모리 사용량이 크게 줄어들고 훨씬 더 큰 파일 세트를 처리할 수 있습니다.

결과

Go를 다시 작성하여 인상적인 개선이 이루어졌습니다.

  1. 메모리 사용량: 99% 감소(10GB에서 100MB로)
  2. 처리 속도: 약 1000% 증가
  3. 신뢰성: 20,000개 이상의 파일을 문제 없이 성공적으로 처리
  4. 비용 효율성: 메모리 사용량이 적고 실행 시간이 빨라져 AWS Lambda 비용이 절감됩니다

배운 교훈

  1. 언어 선택이 중요합니다: Go의 효율성과 동시성 모델은 우리 사용 사례에 엄청난 변화를 가져왔습니다.
  2. 병목 현상 이해: Node.js 기능을 프로파일링하는 것은 개선이 필요한 핵심 영역을 식별하는 데 도움이 되었습니다.
  3. 클라우드 네이티브 솔루션 활용: Go v2용 AWS SDK를 사용하고 S3의 기능을 이해하면 더 나은 통합과 성능을 얻을 수 있습니다.
  4. Think in Streams: 대규모 작업에서는 모든 것을 메모리에 로드하는 대신 데이터를 스트림으로 처리하는 것이 중요합니다.

결론

Go에서 Lambda 기능을 다시 작성하면 즉각적인 확장 문제가 해결되었을 뿐만 아니라 파일 처리 요구 사항에 맞는 더욱 강력하고 효율적인 솔루션이 제공되었습니다. 처음에는 Node.js가 우리에게 큰 도움이 되었지만 이번 경험을 통해 특히 규모에 맞게 리소스 집약적인 작업을 처리할 때 작업에 적합한 도구를 선택하는 것이 중요하다는 점을 강조했습니다.

가장 적합한 언어나 프레임워크는 특정 사용 사례에 따라 다르다는 점을 기억하세요. 우리 시나리오에서 Go의 성능 특성은 우리의 요구 사항과 완벽하게 일치하여 사용자 경험이 크게 향상되고 운영 비용이 절감되었습니다.

서버리스 기능과 관련해 비슷한 문제에 직면한 적이 있나요? 어떻게 극복하셨나요? 아래 댓글을 통해 귀하의 경험을 듣고 싶습니다!

위 내용은 Node.js에서 Go까지: 단일 Zip으로 수천 개의 파일 다운로드 슈퍼차저의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.