Nginx는 오픈소스 웹 서버 및 리버스 프록시 서버 소프트웨어로, 다양한 운영 체제에서 사용되며 높은 성능과 안정성을 가지고 있습니다. Nginx는 이벤트 기반 구조를 사용하여 비동기적으로 동작하며, 적은 자원으로 많은 연결을 처리할 수 있어 인기 있는 소프트웨어입니다.
NGINX는 이벤트 구동, 비동기 및 비차단 모델을 지원하여 마스터-슬레이브 아키텍처로 구성되어있습니다.
Master process : 모든 워커 프로세스를 관리하는 부모 프로세스입니다.
Worker process : 클라이언트 요청을 처리하는 자식 프로세스입니다.
Event module : Nginx의 비동기 이벤트 처리 엔진으로, I/O 처리를 담당합니다.
Cache module : 자주 요청되는 리소스를 캐시하여 처리 속도를 높입니다.
HTTP module : HTTP 요청 및 응답 처리를 담당합니다.
Reverse proxy module : 웹 서버에서 클라이언트 요청을 받아 백엔드 서버로 전달하는 역할을 합니다.
Load balancing module : 여러 백엔드 서버로 부하를 분산하는 로드 밸런싱을 수행합니다.
SSL module : SSL/TLS 암호화 연결을 지원합니다.
위의 이미지에서 핵심 부분 3가지를 조금 더 정리하면 다음과 같습니다.
Master Process
클라이언트의 요청에 따라 작업자에게 작업을 할당합니다.작업자에게 작업이 할당되면 마스터는 작업자의 응답을 기다리지 않는 클라이언트의 다음 요청을 찾습니다.작업자로부터 응답이 오면 마스터가 클라이언트에 응답을 보냅니다.
Worker Process
워커는 NGINX 아키텍처의 슬레이브이며 마스터를 리스닝합니다(원문 heed).각 워커는 단일 스레드 방식으로 한 번에 1000개 이상의 요청을 처리할 수 있습니다.프로세스가 완료되면 응답이 마스터로 전송됩니다.단일 스레드는 다른 메모리 공간 대신 동일한 메모리 공간에서 작업하여 RAM 및 ROM 크기를 절약합니다.다중 스레드는 다른 메모리 공간에서 작동합니다.
Cache
Nginx 캐시는 서버에서 가져오는 대신 캐시 메모리에서 가져와 페이지를 매우 빠르게 렌더링하는 데 사용됩니다.페이지에 대한 첫 번째 요청 시 페이지가 캐시 메모리에 저장됩니다.
정리
Nginx의 구조를 알아보면서 마스터-슬레이브 아키텍처, 그리고 Nginx가 멀티프로세스 - 단일스레드 방식으로 작동한다는 것을 알게 되었습니다.
사내 솔루션을 ASIS JSP + Spring로 구성된 WAS 단일서버에서 Vue.js + Spring으로 UI 차세대를 진행하였습니다.
그에따라 Web서버를 구성해야 할 필요성이 생겼으며, Nginx로 Web서버를 구성하기 위해 찾은 내용을 정리하였습니다.
Nginx란
nginx는 오픈 소스 웹 서버 및 리버스 프록시 소프트웨어입니다. nginx는 Apache와 함께 가장 인기있는 웹 서버 중 하나입니다. nginx는 간단하고 가벼우며 높은 성능과 안정성을 제공합니다.
nginx는 단일 서버 또는 여러 서버에서 사용할 수 있습니다. 여러 서버에서 사용할 경우, nginx는 로드 밸런싱, 캐싱 및 HTTP 및 TCP 로드 밸런싱 기능을 제공합니다.
nginx의 구성은 유연하고 사용자 정의가 가능합니다. nginx 구성 파일은 기본적으로 설정 파일을 읽는 순서로 작성됩니다. 이렇게하면 새로운 구성을 적용하기 전에 이전 구성을 쉽게 되돌릴 수 있습니다.
nginx는 다양한 운영 체제에서 실행될 수 있습니다. 또한 다양한 모듈과 플러그인이 있어서 다양한 기능을 확장할 수 있습니다. 이러한 기능 중 일부는 HTTPS 지원, FastCGI 프로토콜 지원 및 웹 소켓 프로토콜 지원입니다.
nginx는 높은 성능, 안정성 및 유연성으로 인해 많은 대규모 웹 사이트와 애플리케이션에서 사용됩니다.
WEB서버와 WAS 서버
일반적으로, 웹 서버는 정적인 컨텐츠를 처리하고, 애플리케이션 서버는 동적인 컨텐츠를 처리합니다. 이렇게 역할을 나누어 웹 서버는 클라이언트의 요청을 받아 정적인 페이지나 파일을 반환하고, 애플리케이션 서버는 동적인 컨텐츠를 생성하여 반환합니다.
웹 서버와 애플리케이션 서버를 분리하는 이유는 다음과 같습니다.
확장성: 웹 서버와 애플리케이션 서버를 분리하면, 각각의 서버를 별도로 확장할 수 있습니다. 웹 서버를 추가로 배치하여 클라이언트 요청을 더 많이 처리하고, 애플리케이션 서버를 추가로 배치하여 동적인 컨텐츠를 처리하는 데에 집중할 수 있습니다.
보안: 웹 서버와 애플리케이션 서버를 분리하면, 보안 측면에서 더욱 안전한 구성이 가능합니다. 애플리케이션 서버는 외부로부터 직접적인 접근을 받지 않기 때문에, 애플리케이션 서버 자체의 보안성을 높일 수 있습니다.
유지보수: 웹 서버와 애플리케이션 서버를 분리하면, 각각의 역할에 따라 서버를 유지보수할 수 있습니다. 예를 들어, 웹 서버는 정적인 컨텐츠를 처리하므로, 웹 서버를 유지보수할 때 애플리케이션 서버를 중단시키지 않아도 됩니다.
Nginx 기능
wiki에 나열되어 있는 웹 서버 기능은 다음과 같습니다.
정적 파일과 인덱스 파일 표현, 자동 인덱싱 기능.
캐싱을 통한 리버스 프록시
로드 밸런싱
고장 진단
SSL 지원
캐싱을 통한 FastCGI 지원
Name-, IP-기반 가상서버
FLV 스트리밍
MP4 스트리밍 모듈을 이용한 MP4 스트리밍
웹페이지 접근 인증
gzip 압축
10000개의 동시 접속을 처리할 수 있는 능력
URL 다시쓰기 (URL rewriting)
맞춤 로깅
서버 사이드 기능 포함
WebDAV
이중 궁금한 내용 몇가지만 추가로 찾아보았습니다.
정적 파일과 인덱스 파일 표현, 자동 인덱싱 기능
Nginx는 웹 서버 기능을 수행하며, HTTP 요청에 대한 응답으로 정적 파일을 서비스할 수 있습니다. 이때, 정적 파일이란 이미 생성된 HTML, CSS, JavaScript, 이미지 파일 등을 의미합니다. 이러한 정적 파일들은 일반적으로 웹 서버의 특정 디렉토리에 저장되어 있으며, 클라이언트가 해당 파일의 URL을 요청하면 Nginx는 해당 파일을 응답으로 제공합니다.
Nginx는 클라이언트가 요청한 파일이 없을 경우, 디렉토리 내에 있는 인덱스 파일을 반환합니다. 인덱스 파일은 해당 디렉토리에 위치한 기본 파일을 말합니다. 기본적으로 Nginx에서는 index.html, index.htm, index.php 등을 인덱스 파일로 지정하고 있습니다.
또한, Nginx는 자동 인덱싱 기능을 제공합니다. 자동 인덱싱 기능은 인덱스 파일을 설정하지 않았을 경우, 해당 디렉토리 내에 있는 파일 목록을 자동으로 생성하여 클라이언트에게 보여줍니다. 이때 파일 목록은 정렬된 상태로 제공되며, 클라이언트는 이 목록에서 원하는 파일을 선택하여 다운로드할 수 있습니다.
캐싱을 통한 리버스 프록시
이번에 Nginx를 사용하게 된 주된 이유입니다.
캐싱을 통한 리버스 프록시란, 리버스 프록시 서버가 클라이언트 요청에 대한 응답을 받아서 해당 응답을 캐시에 저장하고, 이후에 같은 요청이 들어오면 캐시된 응답을 바로 제공하는 방식입니다. 이는 웹 서버의 부하를 줄이고, 성능을 향상시키는 데에 유용합니다.
리버스 프록시는 일반적으로 웹 서버 앞단에서 사용되며, 클라이언트 요청을 받아서 웹 서버로 전달합니다. 이때, 리버스 프록시는 요청에 대한 응답을 받아서 클라이언트에게 전달하기 전에 캐시에 저장할 수 있습니다. 이후에 같은 요청이 들어오면 리버스 프록시는 캐시된 응답을 클라이언트에게 바로 전달합니다.
캐시를 통한 리버스 프록시는 다음과 같은 장점을 가집니다.
성능 향상: 캐시를 사용하면 웹 서버의 부하를 줄일 수 있습니다. 이미 캐시된 응답을 제공하기 때문에 웹 서버가 해당 요청에 대한 처리를 다시 할 필요가 없기 때문입니다.
대역폭 절약: 캐시를 사용하면 웹 서버에서 클라이언트로 전송되는 데이터 양을 줄일 수 있습니다. 이미 캐시된 응답을 제공하기 때문에 웹 서버에서 클라이언트로 전송되는 데이터 양이 줄어들기 때문입니다.
빠른 응답 속도: 캐시를 사용하면 클라이언트가 요청한 응답을 바로 제공할 수 있습니다. 이미 캐시된 응답을 제공하기 때문에 웹 서버에서 응답을 생성하는 시간이 필요 없기 때문입니다.
로드밸런싱
Nginx는 로드 밸런싱 기능을 지원하는 웹 서버 및 리버스 프록시입니다. 로드 밸런싱은 여러 대의 서버에 걸쳐 트래픽을 분산시키는 기술로, 클라이언트 요청을 여러 대의 서버에 분산하여 서버의 부하를 분산시켜 안정적인 서비스를 제공하는 것을 목적으로 합니다.
Nginx의 로드 밸런싱 기능은 다음과 같은 특징을 가집니다.
알고리즘: Nginx는 가중 라운드 로빈, IP 해시, Least Connections 등 다양한 로드 밸런싱 알고리즘을 지원합니다. 가중 라운드 로빈 알고리즘은 서버에 부여된 가중치를 기반으로 요청을 분산시키며, IP 해시 알고리즘은 클라이언트의 IP 주소를 해시하여 분산시킵니다. Least Connections 알고리즘은 현재 가장 적은 연결 수를 가진 서버에 요청을 전달하는 방식으로 작동합니다.
Health check: Nginx는 로드 밸런싱 대상 서버의 상태를 주기적으로 확인하는 Health check 기능을 제공합니다. 서버의 상태가 이상하면 요청을 보내지 않고, 정상적인 서버에만 요청을 분산시킵니다.
Sticky session: Sticky session 기능은 클라이언트가 처음 요청한 서버에 계속해서 요청이 전달되도록 합니다. 이 기능을 사용하면 클라이언트의 세션 상태를 유지할 수 있어, 로그인 등의 상태 유지 기능을 구현할 수 있습니다.
Upstream: Nginx는 로드 밸런싱 대상 서버를 Upstream 블록으로 정의하여 관리합니다. Upstream 블록은 로드 밸런싱 대상 서버의 주소와 포트 정보를 포함하며, 서버의 추가나 삭제 등 유지보수 작업이 용이합니다.
다양한 프로토콜 지원: Nginx는 HTTP, HTTPS, TCP, UDP 등 다양한 프로토콜을 지원합니다. 따라서, 로드 밸런싱 기능을 사용하여 다양한 서비스를 제공할 수 있습니다.
MFA 관련 개발을 하면서 Google Authentication 앱을 사용하여 QR Code 이미지를 페이지에 보여주도록 하는 일이 있었다.
문제는 생성된 QR Code 이미지가 안드로이드 폰에서는 잘 작동하는데, iOS에서는 잘못된 바코드라는 오류메시지와 함께 작동하지 않았다.
이유를 찾다보니까 QR Code 이미지를 web URL을 이용하여 생성하는데, 이때 사용되는 문자열에 URL에서 중요하게 사용되는 예약 문자가 있어서 문자열을 파싱하는데 이슈가 있었다.
URL Encoding
URL Encoding은 예약문자들을 표현하기 위하여 대체문자를 사용하는 것을 의미한다.
Percent Encoding이라고 표현하기도 하며, 관련 규약은 RFC 3986에 정의되어 있다.
2.1. Percent-Encoding A percent-encoding mechanism is used to represent a data octet in a component when that octet's corresponding character is outside the allowed set or is being used as a delimiter of, or within, the component. A percent-encoded octet is encoded as a character triplet, consisting of the percent character "%" followed by the two hexadecimal digits representing that octet's numeric value. For example, "%20" is the percent-encoding for the binary octet "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space character (SP). Section 2.4 describes when percent-encoding and decoding is applied.
pct-encoded = "%" HEXDIG HEXDIG
The uppercase hexadecimal digits 'A' through 'F' are equivalent to the lowercase digits 'a' through 'f', respectively. If two URIs differ only in the case of hexadecimal digits used in percent-encoded octets, they are equivalent. For consistency, URI producers and normalizers should use uppercase hexadecimal digits for all percent- encodings.
위의 표에 있는 예약 문자들은 옥텟 단위로 묶어서 16진수 값으로 인코딩해야 한다.
예를들어 ? 문자는 이후에 나오는 내용이 쿼리스트링 파라미터라는 것을 의미하며, cp = 0 은 key = value 값을 의미한다.
이런 의미를 가지고 있는 기호들이 제대로 동작하기 위하여 의미가 아닌 문자로 쓰여야 하는 예약문자는 %인코딩으로 표현하여야 한다.