Backend/Image Server

[1] Nginx를 이용한 이미지 서버 ⎻ 개요

eraser 2022. 6. 6. 13:43
반응형

 

 회사에서 서비스에 필요한 이미지 파일의 업로드, 다운로드, 삭제 등의 기능을 담당하는 이미지 서버를 개발하는 프로젝트를 진행했다. 이미지 서빙을 WAS에서 겸할 수도 있지만, 정적 파일 서빙에 대한 것은 어플리케이션 기능과는 분리되는 것이 맞다고 보여 별도의 웹 서버를 두고 해당 웹 서버에서 이미지 업로드, 다운로드, 삭제 요청을 처리하기로 하였다.

 웹 서버에서 파일 업로드, 삭제 등과 같은 동적 기능을 구현하기 위해 CGI 방식을 이용했다. (아마존 S3 따라잡기라는 원대한 꿈을 가지고 시작했으나(...) 수많은 시행착오를 겪고) 웹 서버를 이용해 정적 파일 업로드, 다운로드 등의 기능을 어떻게 구현할 수 있는지 고민했던 내용을 기록하고자 한다.

 

 

 

GitHub - sirzzang/nginx-image-server: 정적 이미지 파일 업로드, 다운로드, 삭제 서비스

정적 이미지 파일 업로드, 다운로드, 삭제 서비스. Contribute to sirzzang/nginx-image-server development by creating an account on GitHub.

github.com

 

 


 

 

# 개발 요구 사항

 

 프로젝트에서 개발해야 하는 기능은 다음과 같다.

 

 

1. 업로드

  • 이미지 업로드 시, 이미지는 파일 시스템에 저장
  • 파일 시스템 저장 시, 파일 검색 성능 보장을 위한 디렉토리 계층화 정책 설계 필요
    • 예컨대, 파일명을 2글자 정도씩 쪼개서 디렉토리를 짜는 설계 가능(예: 파일명이 ar213fdvxcwe.png인 경우, /ar/21/3fdvxcwe.png와 같이 저장할 수 있음)
    • 말단 디렉토리 하나당 들어가는 이미지 파일의 개수가 분산될 수 있도록 디렉토리 규칙 및 depth를 고려하여야 함
  • 업로드 시, 이미지 고유 식별이 가능한 id(예: uuid, hash)를 발급해 응답으로 반환
  • 다중 업로드 가능

 

2. 다운로드

  • 이미지 id로 다운로드 요청 시, 파일 시스템에서 해당 이미지 파일 반환

 

3. 삭제

  • 이미지 id로 삭제 요청 시, 파일 시스템에서 해당 이미지 파일 삭제

 

 위의 개발 요구 사항 중, 이미지 id 발급, 이미지 파일 삭제 등이 웹 서버가 수행해야 하는 동적인 기능이 된다.

 

 


 

 

# 기술 스택

 

 프로젝트 진행을 위해 사용한 기술 스택은 다음과 같다.

  • Nginx 1.20.2: 웹 서버
  • fcgiwrap: FastCGI 프로세스 wrapper
  • nginx-upload-module 2.3.0: Nginx에서 파일 업로드를 처리할 수 있도록 하는 모듈
  • Python 3.9: FastCGI 스크립트 작성

 

각 스택을 이용해 구축될 이미지 서버 구조 개요

 

 

## Nginx

 

 사용할 수 있는 웹 서버로 Nginx, Apache Httpd, WebtoB 등이 있다. 프로젝트 구현에 사용할 수 있는 기술 스택을 선정하면서, 예전에 웹 서버 및 CGI에 대해 공부했던 내용 중, 웹 서버에서 CGI로 동적인 서비스를 구현할 때 매번 새로운 프로세스를 fork하여 나타날 수 있는 성능 하락 문제를 복기했다. 그리고 각 스택이 해당 문제를 어떻게 해결하고 있는지 살펴 보았다.

 세 스택 중 앞의 두 스택은 CGI 방식을 개선해, 하나의 프로세스에서 동적인 요청을 처리하도록 하는 FastCGI를, 관련 모듈을 제공하는 방식으로 지원한다(Nginx의 경우, ngx_http_fastcgi_module을, Apache Httpd의 경우 mod_fcgid 모듈이 제공된다). WebtoB는 앞의 두 스택과는 달리, 웹 서버가 동적 기능을 하는 서비스를 구현할 수 있도록 WBAPI를 제공한다. 이 API는 WebtoB 서버 기동 시, WBAPI 서비스를 메모리에 로딩함으로써 서비스 호출시마다 매번 새로운 프로세스를 fork하지 않도록 설계되었다고 한다.

 특히 WebtoB의 경우 CGI 방식의 문제점을 개선했고, wbSaveFile, wbPutFile 등 개발 요구 사항에 알맞은 기능이 WBAPI 함수로 이미 제공되고 있었다. 다만, WBAPI가 C언어로 제공되고 있어 C를 알지 못하는 상태에서 해당 스택을 선택하기 쉽지 않았다. 결국 Nginx와 Apache Httpd 둘 중 하나를 선택하기로 하였고, 그 중 더 최신 기술이고, 성능이 더 좋다고 알려진 Nginx를 이용해 웹 서버를 구축하기로 하였다.

 

 

## Fcgiwrap

 

 Nginx는 FastCGI 방식을 지원하기 위한 ngx_http_fastcgi_module을 기본적으로 제공한다. 한편, 이 모듈을 통해 이미지 서버가 수행해야 할 동적인 기능을 처리하기 위한 FastCGI 프로세스가 필요하다. fcgiwrap이라는 프로그램이 이 역할을 담당한다. fcgiwrap은 fgciwrap.socket(혹은 fcgiwrap.sock)이라는 유닉스 도메인 소켓을 통해 Nginx와 프로세스 간 통신을 하며 Nginx가 수행하지 못하는 이미지 id 발급, 이미지 파일 삭제 등의 기능을 한다. fcgiwrap이 동적인 요청을 처리하기 위해 필요한 스크립트는 Python으로 작성할 예정이다.

  Ubuntu Community의 위키에 따르면, fcgiwrap은 FastCGI 규약에 따라 CGI 어플리케이션을 수행하는 간단한 프로세스 wrapper라고 나와 있으며, Nginx에 CGI support를 제공하기 위한 것이라고 한다. 비슷한 목적의 프로그램으로는 php로 스크립트를 작성할 때 사용하는 php-fpm이 있다.

 

 

## nginx-upload-module

 

 Nginx에서 파일 업로드를 처리할 수 있도록 도와 주는 3rd party module이다.

 엄밀히 웹 서버는 정적인 기능만을 할 수 있기 때문에, 파일을 받아 메모리에 올려서 디스크에 저장하는 것 역시 웹 서버가 할 수 없는 동적인 기능이다. 이 기능을 구현할 수도 있지만(예컨대, fcgiwrap 프로세스에서 클라이언트가 전송한 폼 데이터를 전부든, 일부든 메모리에 올려서 디스크에 저장할 수 있을 것이다), 이미 Nginx, Apache Httpd 등의 웹 서버에서는 파일 업로드 기능을 구현해 놓은 모듈이 존재하기 때문에, 이를 사용하면 FastCGI 프로세스 단까지 넘어오지 않고서도 웹 서버 단에서 업로드를 처리할 수 있다. 또한, 직접 구현하는 것보다 성능이 낫지 않을까...

 다만, Nginx에서 기본으로 제공하는 모듈이 아니기 때문에, Nginx를 소스 코드로부터 컴파일하고, 이 과정에 해당 모듈을 사용할 수 있게 해 주는 설정이 필요하다.

 

 


 

# 소스 코드 구조

 

 위와 같이 개요를 잡고 개발을 진행했으며, 이 때 대략적인 소스 코드 구조는 다음과 같이 구성했다.

 

└── (project root)
    ├── config/  : nginx 웹 서버 설정 관련 파일 모음
    ├── scripts/ : 이미지 서버 동적 요청 처리를 위한 스크립트 파일 모음
    ├── .env                
    ├── Dockerfile
    ├── docker-compose.yml
    ├── (...)

 

 

 

반응형