로컬에서 예상치 못한 오류가 발생하면, 디버깅 모드를 활용하여 해당 오류를 해결합니다.
플로우를 순차적으로 따라가면서 각각의 상태와 상황들을 쉽게 파악할 수 있기 때문이죠.
클라이언트 개발자와 협업을 하기 위해선, 작성한 어플리케이션을 배포하여야 합니다.
배포된 어플리케이션에서 발생한 오류는 어떻게 파악하면 좋을까요?
물론, 로그를 꼼꼼하게 기록한다면 파악하기 쉬울 것 같습니다. 하지만 한계는 있죠.
배포되어있는 어플리케이션을 대상으로 원하는 지점에서 디버깅을 한다면, 좀 더 쉽게 파악할 수 있을 것 같습니다.
Intellij
나 Ecplise
와 같은 IDE(Integrated development environment, 통합 개발 환경)에서 제공해주는 디버깅 기능을 사용해본 경험이 있을겁니다.
Debugging 모드로 실행하는 것은 어떤 의미인지 간단하게만 짚고 넘어갑시다.
Intellij
같은 IDE
에서 디버깅 모드로 실행을 하면,
해당 실행 어플리케이션을 Debugee(디버그 대상)으로 실행하고, Debugger(디버거)로서의 역할을 수행합니다.
JPDA(Java Platform Debugger Architecture)
라는 구조에서 동작하게 된다고 하고,
그리고 이 JPDA
는 JVM TI
, JDI
라는 두개의 인터페이스와 JDWP
라는 프로토콜로 구성되어 있다고 합니다.
각각에 대해 간단히 설명하자면 다음과 같습니다.
JWM TI(JVM Tools Interface): 디버깅이 진행중인 어플리케이션을 실행하는 VM
JDI(Java Debug Interface): 애플리케이션이 디버깅되는 동안 IntelliJ IDEA
가 애플리케이션과 상호 작용할 수 있도록 하는 Java API. (Ex. 코드를 단계별로 진행, breakpoint 생성, 변수를 검사 등의 작업은 JDI 호출로 변환)
JDWP(Java Debugging Wire Protocol): JDWP는 디버깅 중인 프로세스(디버거)와 디버거(이 경우 IntelliJ IDEA) 간에 전송되는 정보 및 요청의 형식의 프로토콜.
위 내용은 크게 중요하지 않습니다.
잘 알지도 못하고요.
짚고 넘어갈 점은, Java Application
을 디버깅 모드로 실행하면 [Debuggee]
와 [Debugger]
가 따로 존재하고, 특정 JVM 기준이나 구조를 구현한 기능들을 사용한다는 점 입니다.
그리고, 이 [Debuggee]
와 [Debugger]
사이에 JDWP
라는 프로토콜을 통해 통신을 한다는 점 입니다.
간단한 구조
출처: https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/architecture.html
그렇다면, 서버에서 실행중인 어플리케이션을 Debuggee
, 이를 디버깅 하는 Debugger
로 intellij
를 사용하면 원격으로 디버깅이 가능합니다.
방식은 간단합니다.
Server에 배포하는 Java Application을 실행할 때 다음과 같은 매개변수를 설정합니다.
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8081 -jar application.jar
각각 살펴보죠.
agentlib:jdwp=transport=dt_socket
: JVM에 JDWP를 에이전트로 등록하여 디버거가 JVM에 소켓 방식으로 연결할 수 있도록 설정합니다. 실행중인 두 어플리케이션을 연결할 때, 소켓이 표준으로 사용됩니다.server:y
: 서버 역할을 합니다.suspend=n
: 디버거를 기다리지 않고, 즉시 프로그램을 실행합니다.address=*:8081
: 8081 포트에 디버거가 연결될 수 있도록 Listening 합니다.위 옵션을 추가하여 Java 기반의 Spring Application
을 실행합니다.
이제
Debugee
로 실행된 Server에Debugger
를 연결해봅시다.
Intellij
에서 다음과 같은 실행 환경을 추가합니다.
Attach to remote JVM
을 선택합니다.
배포된 서버의 endpoint를 추가하고, 서버를 실행할 때 지정한 Listening 포트를 설정합니다.
하나의 Breakpoint를 지정하고 디버깅을 실행하면, 해당 서버에서 발생한 요청에 대한 디버깅이 가능해집니다.
디버깅 모드를 사용중인 경우, 해당 프로세스를 붙잡고 있습니다.
실제 사용자들이 사용하는 프로덕션 코드에서 개방해두면, 불필요한 병목 현상을 초래할 수 있습니다.
또, 보안적인 이슈가 존재합니다. 어떤 인증 Key 없이, Debugee의 url과 개방된 포트만 알고 있다면 실행중인 어플리케이션에 쉽게 접근하고 다양한 조작을 할 수 있기 때문입니다.
프론트와 협력을 하는 상황에서 쉽게 재연하고 발생한 오류를 파악할 때 유용하게 사용될 것 같습니다.