이미 배포된 어플리케이션에서 발생한 오류를 디버깅하고 싶다면 어떻게 해야 할까?
JPDA란?
JPDA (Java Platform Debugger Architecture)
- Java 애플리케이션을 외부에서 디버깅할 수 있도록 만들어진 디버거 통신 아키텍처
- 즉, 디버거(IDE)와 JVM(실행 중인 애플리케이션) 간의 통신 프로토콜을 정의한 표준
- JDK에 기본 포함되어있음
JPDA의 구성 요소 (4 계층 아키텍처)
계층 | 구성 요소 | 설명 |
1️⃣ | JDI (Java Debug Interface) | 디버거 측에서 사용하는 고수준 API (IntelliJ, Eclipse 등이 이걸 사용) |
2️⃣ | JDWP (Java Debug Wire Protocol) | 디버거와 JVM 간의 통신 형식과 의미를 정의 (네트워크 프로토콜) |
3️⃣ | JVM TI (Java Virtual Machine Tool Interface) | JVM이 제공하는 디버깅 기능을 정의하는 native-level 인터페이스 |
4️⃣ | JVM | 실제 디버깅 대상 Java 프로세스 |
- debugee : 디버깅 대상, 즉 내가 현재 분석하려는 실행 중인 자바 애플리케이션
- VM : 해당 자바 애플리케이션을 실제로 실행하고 있는 JVM
- JVM TI : JVM의 내부 상태를 낮은 수준에서 조작할 수 있는 native 인터페이스
- back-end : JVM과 디버거 사이에서 명령을 해석하고 전달하는 네이티브 계층
- comm channel : JVM과 디버거를 연결하는 통신 경로 (예 : 포트 5005)
- JDWP : JVM과 디버거가 통신할 떄 사용하는 공식 프로토콜
- front-end : 디버깅 명령을 생성하고 결과를 보여주는 도구 내부 처리 계층
- JDI : intellij가 내부적으로 가지고 있는 디버거용 라이브러리 (Java 언어 기반 디버깅 API)
- UI : 우리가 사용하고 있는 intellij 디버깅 화면
JPDA 플로우
- IntelliJ에서 remote debug를 실행하면 JDI(Java Debug Interface)가 시작됨
- JDI는 JDWP를 통해 디버깅 명령어를 전송 (예: breakpoint 설정, 변수 조회 등)
- JDWP는 이진 프로토콜로 포트(예: 5005)를 통해 JVM에 명령 전송
- 일반 애플리케이션 포트(http 통신용)와 디버깅 포트(디버깅 명령용)는 완전히 별개의 목적이므로 서로 충돌 없이 별도 포트 사용해야 함 - http(8080) / jdwp (5005)
- JVM에서는 JVMTI가 그 명령을 받아 내부에서 처리하고, 다시 결과를 전송
- JDWP → JDI → IntelliJ로 결과 전달 → IDE에 중단점 걸림, 변수값 조회 가능
전체 구성
- Tomcat : 외부 서버에서 실행 중
- Spring 애플리케이션 : Tomcat 안에서 WAR 등으로 배포되어 실행
- IntelliJ : 개발자 PC에서 디버깅 연결
원격 디버깅 설정 방법
1. Tomcat에 원격 디버깅 설정하기
- 리눅스를 기준으로 작성
1. setenv.sh 에 아래 옵션 추가
# setenv.sh
export JPDA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
- address=5005 → 디버깅 포트 (방화벽 허용 필요)
2. Tomcat을 JPDA 모드로 기동
catalina.sh jpda start
- startup.sh나 startup.bat이 아닌 jpda start로 꼭 기동 하기
2. IntelliJ에서 Remote 디버깅 설정
1. Run → Edit Configurations → [+] → Remote JVM Debug
항목 | 값 |
Name | Remote JVM Debug |
Debugger mode | Attach |
Transport | Socket |
Host | 원격 서버 IP or 도메인 |
Port | 5005 (위에서 지정한 포트) |
2. Apply → Debug 클릭
주의할 점
- 방화벽
- 원격 서버의 5005 포트를 열어야 함 (iptables, firewalld 설정 필요)
- 클래스 매칭
- IntelliJ 로컬의 클래스와 서버에 배포된 클래스 버전이 정확히 일치해야 함
- 오류
- 포트 충돌, suspend=y일 경우 서버가 디버깅 연결 전까지 멈춰있음
이런 방법이 있었다니..! 다음에 에러 탐색할 때 유용하게 써봐야겠다.
'Today I Learned > Java' 카테고리의 다른 글
[Java] Java Remote Debugging 자바 원격 디버깅 #2 (JDWP 디버깅 옵션) (2) | 2025.07.24 |
---|---|
[Java] Random 4 종류 (0) | 2025.07.05 |
[Java] META-INF 디렉토리와 MANIFEST.MF (0) | 2025.03.12 |
[Java] try-with-resources (자원 관리 최적화) (1) | 2025.03.11 |
[Java] normalize() 메서드 (1) | 2025.01.17 |