개발자로서 우리는 대규모 데이터 처리 및 전달을 처리할 때 종종 어려움에 직면합니다. Kamero에서는 최근 파일 전송 파이프라인의 심각한 병목 현상을 해결했습니다. 우리 애플리케이션을 사용하면 사용자는 특정 이벤트와 관련된 수천 개의 파일을 단일 zip 파일로 다운로드할 수 있습니다. S3 버킷에서 파일을 가져오고 압축하는 역할을 하는 Node.js 기반 Lambda 함수로 구동되는 이 기능은 사용자 기반이 증가함에 따라 메모리 제약과 긴 실행 시간으로 인해 어려움을 겪고 있었습니다.
이 게시물에서는 리소스가 부족한 Node.js 구현에서 대규모 S3 다운로드를 효율적으로 처리하는 간결하고 초고속 Go 솔루션으로의 여정을 자세히 설명합니다. 특정 이벤트에서 많은 수의 파일을 요청할 때 사용자에게 원활한 환경을 제공하기 위해 시스템을 최적화한 방법을 살펴보겠습니다. 모두 편리한 단일 zip 다운로드로 패키지되어 있습니다.
원래 Lambda 함수는 대규모 이벤트 기반 파일 세트를 처리할 때 몇 가지 중요한 문제에 직면했습니다.
원래 구현에서는 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을 생성하기 전에 모든 파일을 메모리에 로드하여 대용량 파일 세트의 경우 메모리 사용량이 늘어나고 메모리 부족 오류가 발생할 수 있습니다.
우리는 효율성과 내장된 동시성 기능을 활용하여 Go에서 Lambda 함수를 다시 작성하기로 결정했습니다. 결과는 놀라웠습니다.
우리는 v1에 비해 더 나은 성능과 더 낮은 메모리 사용량을 제공하는 Go v2용 AWS SDK를 사용했습니다.
cfg, err := config.LoadDefaultConfig(context.TODO()) s3Client = s3.NewFromConfig(cfg)
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이 접근 방식을 사용하면 여러 파일을 동시에 처리하는 동시에 동시성 수준을 제어하여 시스템에 부담을 주지 않을 수 있습니다.
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를 다시 작성하여 인상적인 개선이 이루어졌습니다.
- 메모리 사용량: 99% 감소(10GB에서 100MB로)
- 처리 속도: 약 1000% 증가
- 신뢰성: 문제 없이 20,000개의 파일을 성공적으로 처리합니다.
- 비용 효율성: 메모리 사용량이 적고 실행 시간이 빨라져 AWS Lambda 비용이 절감됩니다.
배운 교훈
- 언어 선택이 중요합니다: Go의 효율성과 동시성 모델은 우리 사용 사례에 엄청난 변화를 가져왔습니다.
- 병목 현상 이해: Node.js 기능을 프로파일링하는 것은 개선이 필요한 주요 영역을 식별하는 데 도움이 되었습니다.
- 클라우드 네이티브 솔루션 활용: Go v2용 AWS SDK를 사용하고 S3의 기능을 이해하면 더 나은 통합과 성능을 얻을 수 있습니다.
- 스트림 방식으로 생각: 모든 것을 메모리에 로드하는 대신 데이터를 스트림으로 처리하는 것은 대규모 작업에 매우 중요합니다.
결론
Go에서 Lambda 함수를 다시 작성하면 즉각적인 확장 문제가 해결되었을 뿐만 아니라 파일 처리 요구 사항에 맞는 더욱 강력하고 효율적인 솔루션도 제공되었습니다. 처음에는 Node.js가 우리에게 큰 도움이 되었지만 이번 경험을 통해 특히 규모에 맞게 리소스 집약적인 작업을 처리할 때 작업에 적합한 도구를 선택하는 것이 중요하다는 점을 강조했습니다.
가장 적합한 언어나 프레임워크는 특정 사용 사례에 따라 다르다는 점을 기억하세요. 우리 시나리오에서 Go의 성능 특성은 우리의 요구 사항과 완벽하게 일치하여 사용자 경험이 크게 향상되고 운영 비용이 절감되었습니다.
서버리스 기능과 관련해 비슷한 문제에 직면한 적이 있나요? 어떻게 극복하셨나요? 아래 댓글을 통해 여러분의 경험을 듣고 싶습니다!
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3