애플리케이션 성능 관리를 위한 변수 사용
NGINX 구성에서 변수는 중요한 요소지만 자주 간과됩니다.
약 150개의 변수를 활용하면 구성을 더욱 효과적으로 최적화할 수 있습니다.
이 블로그에서는 NGINX 변수를 사용해 애플리케이션 추적과 성능 관리(APM)를 구현하는 방법을 살펴보고,
성능 병목 현상을 발견하는 데 중점을 둡니다.
이 내용은 NGINX Open Source와 NGINX Plus에 모두 적용되며,
두 버전 간 차이가 있는 경우를 제외하고는 NGINX Plus를 기준으로 설명합니다.
애플리케이션 전달 환경
샘플 애플리케이션 제공 환경에서 NGINX Plus는 애플리케이션의 역방향 프록시로 작동합니다.
애플리케이션 자체는 웹 프런트엔드로 구성되어 있으며 그 뒤에 여러 마이크로서비스가 있습니다.
샘플 애플리케이션 제공 환경추적 요청 종단간
NGINX Plus R10(및 NGINX 1.11.0)은 $request_id각 HTTP 요청이 도착할 때마다
자동으로 할당되는 32개의 16진수 문자로 구성된 무작위로 생성된 문자열인 변수를 도입합니다.
(예: 444535f9378a3dfa1b8604bc9e05a303).
이 속이는 듯이 간단한 메커니즘은 추적 및 문제 해결을 위한 강력한 도구의 잠금을 해제합니다.
NGINX Plus와 모든 백엔드 서비스를 구성하여 값을 전달하면 $request_id모든 요청을 종단 간 추적할 수 있습니다.
이 샘플 구성은 프런트엔드 NGINX Plus 서버를 위한 것입니다.
upstream app_server {
server 10.0.0.1:80;
}
server {
listen 80;
add_header X-Request-ID $request_id; # Return to client
location / {
proxy_pass http://app_server;
proxy_set_header X-Request-ID $request_id; # Pass to app server
}
}요청 추적을 위해 NGINX Plus를 구성하려면 먼저 `upstream` 블록에서 애플리케이션 서버의 네트워크 위치를 정의해야 합니다.
여기에서는 단일 애플리케이션 서버만 예로 들지만,
실제 환경에서는 고가용성과 부하 분산을 위해 여러 서버를 사용하는 경우가 많습니다.
애플리케이션 서버 블록은 NGINX Plus가 들어오는 HTTP 요청을 처리하는 방식을 정의합니다.
예를 들어, `listen` 지시문은 NGINX Plus가 포트 80(HTTP 트래픽의 기본값)에서 요청을 수신하도록 설정합니다.
하지만 실제 프로덕션 환경에서는 SSL/TLS를 통해 데이터 전송을 보호하는 것이 일반적입니다.
`add_header` 지시문은 `$request_id` 값을 사용자 지정 응답 헤더로 클라이언트에 반환합니다.
이 기능은 테스트 시 유용하며, 자체 로그를 생성하는 모바일 앱 같은 클라이언트 애플리케이션에서도 활용할 수 있습니다.
이를 통해 클라이언트 측 오류를 서버 로그와 정확히 매칭할 수 있습니다.
마지막으로, `location` 블록은 전체 애플리케이션 경로(`/`)에 적용됩니다.
`proxy_pass` 지시문은 모든 요청을 애플리케이션 서버로 프록시하며,
`proxy_set_header`를 사용해 애플리케이션에 전달되는 HTTP 헤더를 추가로 설정합니다.
이 예에서는 `X-Request-ID`라는 새 헤더를 생성하고, 변수 `$request_id` 값을 할당합니다.
이를 통해 애플리케이션은 NGINX Plus에서 생성된 요청 ID를 받을 수 있습니다.
$request_id엔드 투 엔드 로깅
애플리케이션 추적의 목표는 애플리케이션 성능 관리의 일부로 요청 처리 라이프사이클에서 성능 병목 현상을 식별하는 것입니다.
이를 위해 처리 중에 중요한 이벤트를 로깅하여 나중에 예상치 못하거나 불합리한 지연을 분석할 수 있습니다.
NGINX Plus 구성
$request_id사용자 정의 로깅 형식을 포함하도록 프런트엔드 NGINX Plus 서버를 구성하는 것으로 시작합니다 .
이 형식은 access_trace.logtrace 파일 에 사용됩니다 .
log_format trace
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'"$http_x_forwarded_for" $request_id';
upstream app_server {
server 10.0.0.1;
}
server {
listen 80;
add_header X-Request-ID $request_id; # Return to client
location / {
proxy_pass http://app_server;
proxy_set_header X-Request-ID $request_id;
# Pass to app server access_log /var/log/nginx/access_trace.log trace; # Log $request_id
}
}백엔드 애플리케이션 구성
애플리케이션에 요청 ID를 전달하는 것은 좋지만 애플리케이션이 이를 처리하지 않는 한 애플리케이션 추적에 실제로 도움이 되지 않습니다.
이 예에서는 uWSGI 가 관리하는 Python 애플리케이션이 있습니다.
애플리케이션 진입점을 수정하여 요청 ID를 로깅 변수로 가져오겠습니다.
from uwsgi import set_logvar
def main(environ, start_response): set_logvar('requestid', environ['X_REQUEST_ID'])그런 다음 uWSGI 구성을 수정하여 표준 로그 파일에 요청 ID를 포함할 수 있습니다.
log-format = %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)" %(requestid)
이런 구성을 통해 이제는 여러 시스템에서 단일 요청에 연결할 수 있는 로그 파일을 생성할 수 있습니다.
NGINX의 로그 항목:
172.17.0.1 - - [02/Aug/2016:14:26:50 +0000] "GET / HTTP/1.1" 200 90 "-" "-" "-" 5f222ae5938482c32a822dbf15e19f0f
애플리케이션의 로그 항목:
192.168.91.1 - - [02/Aug/2016:14:26:50 +0000] "GET / HTTP/1.0" 200 123 "-" "-" 5f222ae5938482c32a822dbf15e19f0f
Splunk 및 Kibana 와 같은 도구를 사용하면 트랜잭션을 요청 ID 필드에 일치시켜
애플리케이션 서버의 성능 병목 현상을 파악할 수 있습니다.
예를 들어 완료하는 데 2초 이상 걸린 요청을 검색할 수 있습니다.
그러나 일반 타임스탬프에서 1초라는 기본 시간 해상도는 대부분의 실제 분석에 충분하지 않습니다.
고도로 정밀한 타이밍
요청을 종단간 정확하게 측정하려면 밀리초 수준의 정밀도를 가진 타임스탬프가 필요합니다.
$msec로그 항목에 변수를 포함하면 각 항목의 타임스탬프에 대한 밀리초 해상도를 얻습니다.
애플리케이션 로그에 밀리초 타임스탬프를 추가하면 2초가 아닌 200밀리초 이상 걸리는 요청을 찾을 수 있습니다.
하지만 그때도 우리는 전체 그림을 얻지 못합니다. 왜냐하면 NGINX Plus는 $msec각 요청을 처리한 후에만 타임스탬프를 쓰기 때문입니다.
다행히도 밀리초 정밀도를 가진 다른 여러 NGINX Plus 타이밍 변수가 있어서 처리 자체에 대한 더 많은 통찰력을 얻을 수 있습니다.
이러한 타이밍 변수에 대한 자세한 내용은 애플리케이션 성능 모니터링을 위한 NGINX 로깅 사용을 참조하세요 .log_format이러한 모든 고정밀 타이밍 변수를 로그 형식에 포함하도록 지침을 확장해 보겠습니다 trace.
log_format trace
'$remote_addr - $remote_user [$time_local] "$request" $status '
'$body_bytes_sent "$http_referer" "$http_user_agent" '
'"$http_x_forwarded_for" $request_id $msec $request_time '
'$upstream_connect_time $upstream_header_time $upstream_response_time';우리가 선호하는 로그 분석 도구를 사용하여 변수 값을 추출하고
다음 계산을 수행하여 NGINX Plus가 애플리케이션 서버에 연결하기 전에 요청을 처리하는 데 걸린 시간을 확인할 수 있습니다.
NGINX Plus processing time = $request_time - $upstream_connect_time - $upstream_response_time
또한 가장 높은 값을 검색하여 $upstream_response_time특정 URI 또는 업스트림 서버와 연관되어 있는지 확인할 수 있습니다.
그런 다음 동일한 요청 ID를 가진 애플리케이션 로그 항목과 추가로 확인할 수 있습니다.
결론
새로운 $request_id변수와 일부 또는 모든 밀리초 정밀도 변수를 활용하면 애플리케이션의 성능 병목 현상을 잘 파악할 수 있으며,
무거운 에이전트와 플러그인을 사용하지 않고도 애플리케이션 성능 관리를 개선할 수 있습니다.
애플리케이션 성능 관리를 위한 변수 사용
NGINX 구성에서 변수는 중요한 요소지만 자주 간과됩니다.
약 150개의 변수를 활용하면 구성을 더욱 효과적으로 최적화할 수 있습니다.
이 블로그에서는 NGINX 변수를 사용해 애플리케이션 추적과 성능 관리(APM)를 구현하는 방법을 살펴보고,
성능 병목 현상을 발견하는 데 중점을 둡니다.
이 내용은 NGINX Open Source와 NGINX Plus에 모두 적용되며,
두 버전 간 차이가 있는 경우를 제외하고는 NGINX Plus를 기준으로 설명합니다.
애플리케이션 전달 환경
샘플 애플리케이션 제공 환경에서 NGINX Plus는 애플리케이션의 역방향 프록시로 작동합니다.
애플리케이션 자체는 웹 프런트엔드로 구성되어 있으며 그 뒤에 여러 마이크로서비스가 있습니다.
추적 요청 종단간
NGINX Plus R10(및 NGINX 1.11.0)은 $request_id각 HTTP 요청이 도착할 때마다
자동으로 할당되는 32개의 16진수 문자로 구성된 무작위로 생성된 문자열인 변수를 도입합니다.
(예: 444535f9378a3dfa1b8604bc9e05a303).
이 속이는 듯이 간단한 메커니즘은 추적 및 문제 해결을 위한 강력한 도구의 잠금을 해제합니다.
NGINX Plus와 모든 백엔드 서비스를 구성하여 값을 전달하면 $request_id모든 요청을 종단 간 추적할 수 있습니다.
이 샘플 구성은 프런트엔드 NGINX Plus 서버를 위한 것입니다.
upstream app_server { server 10.0.0.1:80; } server { listen 80; add_header X-Request-ID $request_id; # Return to client location / { proxy_pass http://app_server; proxy_set_header X-Request-ID $request_id; # Pass to app server } }요청 추적을 위해 NGINX Plus를 구성하려면 먼저 `upstream` 블록에서 애플리케이션 서버의 네트워크 위치를 정의해야 합니다.
여기에서는 단일 애플리케이션 서버만 예로 들지만,
실제 환경에서는 고가용성과 부하 분산을 위해 여러 서버를 사용하는 경우가 많습니다.
애플리케이션 서버 블록은 NGINX Plus가 들어오는 HTTP 요청을 처리하는 방식을 정의합니다.
예를 들어, `listen` 지시문은 NGINX Plus가 포트 80(HTTP 트래픽의 기본값)에서 요청을 수신하도록 설정합니다.
하지만 실제 프로덕션 환경에서는 SSL/TLS를 통해 데이터 전송을 보호하는 것이 일반적입니다.
`add_header` 지시문은 `$request_id` 값을 사용자 지정 응답 헤더로 클라이언트에 반환합니다.
이 기능은 테스트 시 유용하며, 자체 로그를 생성하는 모바일 앱 같은 클라이언트 애플리케이션에서도 활용할 수 있습니다.
이를 통해 클라이언트 측 오류를 서버 로그와 정확히 매칭할 수 있습니다.
마지막으로, `location` 블록은 전체 애플리케이션 경로(`/`)에 적용됩니다.
`proxy_pass` 지시문은 모든 요청을 애플리케이션 서버로 프록시하며,
`proxy_set_header`를 사용해 애플리케이션에 전달되는 HTTP 헤더를 추가로 설정합니다.
이 예에서는 `X-Request-ID`라는 새 헤더를 생성하고, 변수 `$request_id` 값을 할당합니다.
이를 통해 애플리케이션은 NGINX Plus에서 생성된 요청 ID를 받을 수 있습니다.
$request_id엔드 투 엔드 로깅
애플리케이션 추적의 목표는 애플리케이션 성능 관리의 일부로 요청 처리 라이프사이클에서 성능 병목 현상을 식별하는 것입니다.
이를 위해 처리 중에 중요한 이벤트를 로깅하여 나중에 예상치 못하거나 불합리한 지연을 분석할 수 있습니다.
NGINX Plus 구성
$request_id사용자 정의 로깅 형식을 포함하도록 프런트엔드 NGINX Plus 서버를 구성하는 것으로 시작합니다 .
이 형식은 access_trace.logtrace 파일 에 사용됩니다 .
log_format trace '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" ' '"$http_x_forwarded_for" $request_id'; upstream app_server { server 10.0.0.1; } server { listen 80; add_header X-Request-ID $request_id; # Return to client location / { proxy_pass http://app_server; proxy_set_header X-Request-ID $request_id; # Pass to app server access_log /var/log/nginx/access_trace.log trace; # Log $request_id } }백엔드 애플리케이션 구성
애플리케이션에 요청 ID를 전달하는 것은 좋지만 애플리케이션이 이를 처리하지 않는 한 애플리케이션 추적에 실제로 도움이 되지 않습니다.
이 예에서는 uWSGI 가 관리하는 Python 애플리케이션이 있습니다.
애플리케이션 진입점을 수정하여 요청 ID를 로깅 변수로 가져오겠습니다.
from uwsgi import set_logvar def main(environ, start_response): set_logvar('requestid', environ['X_REQUEST_ID'])그런 다음 uWSGI 구성을 수정하여 표준 로그 파일에 요청 ID를 포함할 수 있습니다.
log-format = %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)" %(requestid)이런 구성을 통해 이제는 여러 시스템에서 단일 요청에 연결할 수 있는 로그 파일을 생성할 수 있습니다.
NGINX의 로그 항목:
172.17.0.1 - - [02/Aug/2016:14:26:50 +0000] "GET / HTTP/1.1" 200 90 "-" "-" "-" 5f222ae5938482c32a822dbf15e19f0f애플리케이션의 로그 항목:
192.168.91.1 - - [02/Aug/2016:14:26:50 +0000] "GET / HTTP/1.0" 200 123 "-" "-" 5f222ae5938482c32a822dbf15e19f0fSplunk 및 Kibana 와 같은 도구를 사용하면 트랜잭션을 요청 ID 필드에 일치시켜
애플리케이션 서버의 성능 병목 현상을 파악할 수 있습니다.
예를 들어 완료하는 데 2초 이상 걸린 요청을 검색할 수 있습니다.
그러나 일반 타임스탬프에서 1초라는 기본 시간 해상도는 대부분의 실제 분석에 충분하지 않습니다.
고도로 정밀한 타이밍
요청을 종단간 정확하게 측정하려면 밀리초 수준의 정밀도를 가진 타임스탬프가 필요합니다.
$msec로그 항목에 변수를 포함하면 각 항목의 타임스탬프에 대한 밀리초 해상도를 얻습니다.
애플리케이션 로그에 밀리초 타임스탬프를 추가하면 2초가 아닌 200밀리초 이상 걸리는 요청을 찾을 수 있습니다.
하지만 그때도 우리는 전체 그림을 얻지 못합니다. 왜냐하면 NGINX Plus는 $msec각 요청을 처리한 후에만 타임스탬프를 쓰기 때문입니다.
다행히도 밀리초 정밀도를 가진 다른 여러 NGINX Plus 타이밍 변수가 있어서 처리 자체에 대한 더 많은 통찰력을 얻을 수 있습니다.
$upstream_connect_time – 업스트림 서버와 연결을 설정하는 데 소요된 시간
$upstream_header_time – 업스트림 서버에 연결을 설정한 후 응답 헤더의 첫 번째 바이트를 수신하는 사이의 시간
$upstream_response_time – 업스트림 서버에 연결을 설정한 후 응답 본문의 마지막 바이트를 수신하는 사이의 시간
log_format이러한 모든 고정밀 타이밍 변수를 로그 형식에 포함하도록 지침을 확장해 보겠습니다 trace.
log_format trace '$remote_addr - $remote_user [$time_local] "$request" $status ' '$body_bytes_sent "$http_referer" "$http_user_agent" ' '"$http_x_forwarded_for" $request_id $msec $request_time ' '$upstream_connect_time $upstream_header_time $upstream_response_time';우리가 선호하는 로그 분석 도구를 사용하여 변수 값을 추출하고
다음 계산을 수행하여 NGINX Plus가 애플리케이션 서버에 연결하기 전에 요청을 처리하는 데 걸린 시간을 확인할 수 있습니다.
NGINX Plus processing time = $request_time - $upstream_connect_time - $upstream_response_time또한 가장 높은 값을 검색하여 $upstream_response_time특정 URI 또는 업스트림 서버와 연관되어 있는지 확인할 수 있습니다.
그런 다음 동일한 요청 ID를 가진 애플리케이션 로그 항목과 추가로 확인할 수 있습니다.
결론
새로운 $request_id변수와 일부 또는 모든 밀리초 정밀도 변수를 활용하면 애플리케이션의 성능 병목 현상을 잘 파악할 수 있으며,
무거운 에이전트와 플러그인을 사용하지 않고도 애플리케이션 성능 관리를 개선할 수 있습니다.
위 내용과 같이 NGINX Plus를 활용하여 Demo 가 필요하시면 하단의 전문가에게 상담받기 버튼을 클릭해주세요.
전문가에게 상담받기