
.NET Core로 문서 처리 확장
애플리케이션이 파일럿 프로젝트 단계에서 전사적인 플랫폼으로 성장함에 따라 인프라에 걸리는 부하가 급격히 증가합니다. 문서 처리—보기, 변환, OCR—는 계산량이 많습니다. 10명의 사용자에게는 완벽히 동작하던 솔루션도 10,000명의 동시 사용자를 상대하면 급속히 정체됩니다.
고부하 시스템의 세계에서는 확장성이 가장 중요합니다. 개발자는 트래픽 급증을 부드럽게 처리하고, 자원을 효율적으로 관리하며, 비용을 예측 가능하게 유지할 수 있는 아키텍처가 필요합니다. 여기서 .NET Core의 향상된 성능과 Doconut의 확장 가능한 아키텍처가 결합하면 큰 장점을 얻을 수 있습니다. 이번 포스트에서는 .NET Core와 Doconut을 활용해 문서 처리 파이프라인을 효과적으로 확장하는 전략을 살펴보겠습니다.
문서 처리의 성능 특성
효과적으로 확장하려면 먼저 작업량을 이해해야 합니다. 문서 처리는 동시에 세 가지 주요 자원 제한에 걸리는 경우가 많습니다.
- CPU 바인드: 복잡한 벡터 PDF를 렌더링하거나 CAD 도면을 변환하려면 많은 수학 연산이 필요합니다.
- 메모리 바인드: 500 MB 크기의 고해상도 지도를 메모리로 로드해 처리하려면 힙이 크게 증가하고 가비지 컬렉터(GC)에 부담이 생깁니다.
- I/O 바인드: 대용량 원본 파일을 디스크·클라우드에서 읽고 캐시된 타일을 쓰는 과정에서 입출력 작업이 크게 늘어납니다.
이러한 특성을 고려한 다각적인 접근이 필요하며, 최신 .NET Core 런타임이 제공하는 장점을 활용해야 합니다.
전략 1: 비동기 I/O(Async/Await)의 힘
레거시 .NET 애플리케이션은 종종 스레드 풀 고갈 문제에 시달렸습니다. 웹 요청이 디스크에서 파일을 읽는 동안 스레드를 차단하면, 서버는 새로운 요청을 처리할 스레드를 충분히 확보하지 못해 CPU가 유휴 상태임에도 503 오류가 발생했습니다.
Doconut은 Async/Await 패턴에 완벽히 최적화되어 있습니다. 파일 읽기, 라이선스 조회, 캐시 쓰기 등 모든 I/O 작업을 비동기로 수행해야 합니다.
뷰 컨트롤러가 async 메서드를 끝까지 사용하도록 설계하면, 하나의 서버 인스턴스가 수천 개의 동시 연결을 효율적으로 대기시킬 수 있어 스레드가 블로킹되지 않습니다.
전략 2: 분산 캐싱
단일 서버 환경에서는 IMemoryCache를 이용한 메모리 캐시가 빠르고 구현도 간단합니다. 하지만 웹 팜과 같이 서버가 여러 대로 확장될 경우에는 문제가 발생합니다. 사용자 A가 서버 1에 요청하면 페이지가 해당 서버에 캐시됩니다. 다음 요청이 서버 2로 라우팅될 경우 캐시가 없어 다시 렌더링해야 하므로 CPU가 불필요하게 소모됩니다.
대규모 문서 처리에서는 분산 캐싱을 구현해야 합니다. Doconut은 사용자 정의 캐시 프로바이더 작성을 지원합니다. Redis나 SQL Server 기반 캐시 프로바이더를 도입하면 렌더링 작업이 한 번만 수행되고 결과가 모든 노드에서 공유됩니다.
- 시나리오: 사용자가 “AnnualReport.pdf”의 페이지 1을 요청합니다.
- 서버 1: Redis에 캐시가 없음을 확인하고 페이지를 렌더링한 뒤 타일을 Redis에 저장하고 이미지를 반환합니다.
- 서버 2(다른 사용자를 처리 중): Redis에 캐시가 존재함을 확인하고 즉시 이미지를 반환합니다.
이 방식은 CPU 부하를 크게 줄여주며, 어떤 노드가 요청을 처리하든 일관된 응답 속도를 제공합니다.
전략 3: 지능형 계층형 스토리지
수백만 개의 문서를 저장하려면 스마트한 스토리지 전략이 필요합니다. Doconut은 클라우드 스토리지(AWS S3, Azure Blob Storage)에서 파일을 직접 스트리밍하는 기능을 제공하므로, 전체 파일을 웹 서버의 로컬 디스크에 다운로드할 필요가 없습니다.
스토리지 계층을 다음과 같이 구분하면 비용과 성능을 최적화할 수 있습니다.
- 핫 스토리지 (Local NVMe): 활성 문서 타일의 임시 캐시용으로 사용합니다.
- 쿨 스토리지 (S3 Standard): 자주 접근되는 문서를 저장합니다.
- 콜드 스토리지 (S3 Glacier): 장기 보관용 아카이브에 활용합니다.
Doconut의 Stream 기반 API를 이용하면 S3에서 바로 데이터를 파이프라인으로 전달해 렌더링 엔진에 넘길 수 있어, 파일 크기에 관계없이 메모리 사용량이 일정하게 유지됩니다.
결론
문서 처리 시스템을 확장하는 것은 “동작하게 만들기”에서 “모두에게 동작하게 만들기”로 나아가는 여정입니다. .NET Core의 비동기 프로그래밍 모델을 채택하고, Docker 기반 마이크로서비스 아키텍처와 스마트 캐싱·큐잉 전략을 결합하면 Doconut 기반 뷰어 솔루션을 수백만 사용자를 지원하도록 만들 수 있습니다.
Doconut은 단순한 라이브러리를 넘어 높은 동시성을 견딜 수 있도록 설계된 기업용 컴포넌트입니다. 올바른 아키텍처를 통해 문서 인프라를 눈에 보이지 않는 무한 확장 가능한 유틸리티로 전환하고, 병목 현상을 근본적으로 해소할 수 있습니다.