NGINX debug (디버깅) 기능으로 내부 조사
최신 버전의 NGINX에는 문제가 발생할 경우 NGINX에서 더 많은 정보를 얻는 데 도움이 되는 몇 가지 유용한 NGINX debug (디버깅) 기능이 추가되었습니다. 실행 중인 서버에서 정보를 추출하기 위해 GDB를 사용하여 작동합니다. 프로덕션에서 실행 중인 NGINX 인스턴스에서 GDB를 사용하는 것을 권장하지 않지만 개발 또는 테스트 환경에서는 매우 유용할 수 있습니다.
이 포스트에 포함된 기능이 작동하려면 NGINX를 빌드할 때 –with-debug 구성 옵션을 포함하세요. 바이너리가 옵션으로 빌드되었는지 확인하려면 nginx -V 명령을 실행합니다.
# nginx -V
nginx version nginx/1.9.3
built by gcc 5.1.1 20150618 (Red Hat 5.1.1-4) (GCC)
configure arguments: --with-debug --prefix-/opt/nginx-debug
목차
1. 메모리에 NGINX debug(디버깅) 로그 쓰기
2. Active NGINX debug 구성 덤프
3. 코어 파일과 함께 GDB 사용
4. 결론
1. 메모리에 NGINX debug (디버깅) 로그 쓰기
첫 번째 새로운 기능은 메모리 내 NGINX debug (디버깅) 로그입니다. NGINX 디버깅 로그는 복잡한 문제를 파헤치는 데 매우 유용하지만 동시에 매우 빠르게 커져 디스크 공간을 차지할 수 있습니다.
NGINX 1.7.11에서는 디버그 로깅이 디스크 저장소를 전혀 사용하지 않도록 순환 버퍼를 사용하여 메모리에 직접 로그인하는 기능을 추가했습니다. 자세한 내용은 NGINX 설명서의 순환 메모리 버퍼에 로깅을 참조하세요.
디버그 로깅을 위해 32MB 버퍼를 활성화하려면 NGINX 구성 파일의 기본 컨텍스트에 이 error_log 지시문을 포함합니다.
error_log memory:32m debug;
GDB를 사용하여 메모리에서 로그를 추출할 수 있습니다. 이를 지원하기 위해 이 포스의 예제에 필요한 모든 것을 포함하는 GitHub Gist를 만들었습니다. 다운로드하여 nginx.gdb로 저장하거나 홈 디렉토리에서 .gdbinit로 이름을 변경하여 자동으로 로드되도록 합니다.
먼저 다음 명령을 실행하여 NGINX Worker 프로세스의 프로세스 ID를 표시합니다.
# pgrep -f "nginx: worker"
조사하려는 Worker의 프로세스 ID를 찾으십시오. 내 경우에는 프로세스 ID가 20192인 하나의 Worker가 있습니다.
GDB를 시작하고 Worker 프로세스를 로드하려면 다음 명령을 실행합니다(GDB가 실행되는 동안 Worker 프로세스가 일시 중지됨).
# sudo gdb --pid 20192
GitHub Gist에서 다운로드한 스크립트를 로드하고 NGINX debug (디버깅) 로그를 덤프하려면 다음 명령을 실행합니다.
(gdb) source nginx.gdb
(gdb) ddl
GDB는 error_log
지시문을 사용하여 할당된 메모리 덤프를 포함하는 debug_log.txt라는 파일을 생성하므로 우리의 경우 파일 크기는 32MB입니다. 파일에 몇 개의 항목만 있는 경우 다음 sed 명령을 사용하여 쉽게 자를 수 있습니다. 대부분의 경우 이 작업을 수행할 필요가 없으며 로그가 이미 시작 부분으로 되돌아간 경우 명령이 효과가 없습니다.
# sed -i 's/[[:space:]]*$//' debug_log.txt
분명히 로그를 가져오는 동안 Worker 프로세스를 일시 중지하는 것이 좋은 생각은 아닙니다. 따라서 GDB에게 로그를 잡고 즉시 종료하도록 지시하여 일시 중지를 매우 짧은 시간으로 제한할 수 있습니다.
# gdb --pid 20192 -iex "source nginx.gdb" -ex "ddl" --batch
2. Active NGINX debug 구성 덤프
NGINX 1.9.2 이상에서는 --with-debug
구성 옵션을 사용하여 NGINX를 빌드할 때 전체 구성이 메모리에 저장되므로 GDB를 사용하여 Master 프로세스에서 구성을 추출할 수 있습니다. 이는 로드된 구성을 확인하고 디스크의 버전이 실수로 제거되거나 덮어쓴 경우 이전 구성을 복원하는 데 유용할 수 있습니다.
이전과 마찬가지로 GitHub Gist의 nginx.gdb 파일에는 메모리 덤프를 실행하는 데 필요한 기능이 있습니다. 따라서 먼저 GDB를 로드합니다.
# sudo gdb --pid `pgrep -f "nginx: master"`
그런 다음 다음 명령을 실행하여 구성을 덤프합니다.
(gdb) source nginx.gdb
(gdb) dcfg
GDB는 파일을 덤프할 때 파일 이름을 내뱉습니다. 이 샘플 출력에서 볼 수 있듯이 문자열이 NUL로 종료되지 않으면 GDB의 printf 함수가 제대로 작동하지 않기 때문에 각 파일 이름 끝에 약간의 정크가 있을 수 있습니다. 최종 결과는 완전한 활성 구성을 포함하는 nginx_conf.txt라는 파일입니다.

NGINX debug (디버깅) 로그와 마찬가지로 배치 모드에서 구성을 덤프할 수 있습니다.
# gdb --pid `pgrep -f "nginx: master"` -iex "source nginx.gdb" -ex "dcfg" --batch
3. 코어 파일과 함께 GDB 사용
이 포스트에서 다룬 모든 내용은 문제의 원인을 디버깅하는 데 도움이 되는 코어 파일과 함께 사용할 수도 있습니다.
# gdb --core core.9491 nginx
이 포스트에 설명된 dcfg 및 ddl 함수는 여기서 논의한 방식으로 코어 파일과 함께 사용할 수 있습니다. 이는 코어 파일이 생성된 시간에 NGINX 서버의 구성을 찾아야 하거나 코어 파일 생성으로 이어지는 이벤트에 대한 디버깅 정보를 가져와야 하는 경우에 유용할 수 있습니다.
4. 결론
NGINX debug (디버깅) 로그와 구성을 덤프하는 것은 NGINX 내부에 대한 정보를 추출하는 데 정말 유용한 방법이 될 수 있으며 물론 GDB 스크립트를 조정하여 소개한 기술을 확장할 수 있습니다. 예를 들어 구성을 덤프할 때 모든 것을 단일 파일로 덤프하는 대신 로드된 각 구성 파일을 별도의 출력 파일로 덤프할 수 있어야 합니다. 파일 이름의 길이는 파일 이름 자체와 함께 저장되므로 파일 이름을 사용할 때 복사하거나 잘라낼 수 있는 방법이 있어야 합니다. 표준 스크립팅 API로 이 작업을 수행하는 좋은 방법을 찾지 못했지만 최신 버전의 GDB는 이 작업을 수행할 수 있는 Python 스크립팅을 지원합니다.
개발 및 테스트 환경에서만 이러한 기술을 사용하는 것이 좋습니다. 프로덕션 환경에서 NGINX 프로세스, 특히 Worker의 실행을 일시 중지하는 것은 좋지 않습니다.
사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.
댓글을 달려면 로그인해야 합니다.