카테고리 없음

[Java] JDWP 프로토콜로 원격 디버깅 수행

웅대 2026. 1. 7. 23:21
728x90

개요

개발을 하다 보면 로컬 환경에서 재현하기 어려운 문제를 해결하기 위해 실행 중인 애플리케이션을 직접 디버깅해야 하는 경우가 있습니다.

 

예를 들어 서비스가 여러 의존성을 가진 경우 로컬 환경 구축하기 보다 개발 서버에 배포되어 있는 서버를 원격 디버깅하는 것이 효율적일 수 있습니다.

 

이번 포스팅에서는 JDWP라는 프로토콜을 통해 원격 디버깅을 수행하는 방법을 다뤄보려고 합니다.

 

JDWP (Java Debug Wire Protocol)란?

JDWP는 JPDA라는 Java Platform Debug Architecture 라고 불리는 글로벌 java 디버깅 시스템의 구성 요소 중 하나입니다.

 

JDWP는 디버거 프로세스와 JVMDI/JVMTI 사이 정의된 통신 프로토콜입니다.

Java Debug Wire Protocol

JDWP를 사용하면 로컬 IDE와 원격 서버의 JVM을 연결하여 실시간으로 브레이크포인트를 설정하고 디버깅할 수 있습니다.

 

다만, 브레이킹 포인트를 걸게 되면 실제 요청들도 모두 브레이크 포인트에 걸리기 때문에 상용 서버가 아닌 개발 서버에서 사용해야 합니다.

JDWP 설정 방법

서버는 간단한 REST API를 가지고 있는 java/spring 기반 springio/gs-spring-boot-docker image를 사용했습니다.

docker run -p 8080:8080 -p 5005:5005 \
  -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" \
  springio/gs-spring-boot-docker

 

 

JAVA_OPTS에 대한 설명은 다음과 같습니다.

  • agentlib:jdwp
    • JVM에 JDWP 에이전트 활성화
  • transport=dt_socket
    • TCP/IP 소켓 사용
  • server=y
    • JVM이 서버 역할
  • suspend=n
    • 디버거 연결 없이도 애플리케이션 바로 실행 
    • y로 설정하면 디버거 연결까지 대기
  • address=5005
    • 디버그 포트로 5005번 사용

실행 후 로그에서 5005 포트에서 디버거 연결을 대기하는 메시지를 확인할 수 있습니다.

Picked up JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
Listening for transport dt_socket at address: 5005
서버 실행 방식과 무관하게 환경 변수에 JAVA_TOOL_OPTIONS를 설정하면 됩니다.

 

IDE 원격 디버깅 설정

디버깅 할 서버의 프로젝트 코드를 Clone 한 뒤 IntelliJ를 실행합니다.

 

저는 gs-spring-boot-docker 프로젝트를 실행했기 때문에 https://github.com/spring-guides/gs-spring-boot-docker.git에서 프로젝트를 clone했습니다.

 

IntelliJ IDE 기준으로 원격 디버깅 설정은 다음과 같습니다.

 

run -> edit configuration에서 새 항목 추가를 누르면 remote jvm debug를 선택할 수 있습니다.

 

정보 입력 후 적용을 누르면 생성됩니다.

 

현재는 로컬에 서버를 띄웠기 때문에 호스트를 localhost로 입력했지만 실제로는 운영 중인 개발 서버 주소를 입력하면 됩니다.

 

 

방금 생성한 실행을 선택하고 디버거 버튼을 눌러줍니다.

 

타깃 VM에 연결되었다는 로그가 나오면 연결 성공입니다.

 

이제 자유롭게 로컬에서 디버깅을 수행하면 원격 서버에 연결되어 디버깅을 수행할 수 있습니다.

 

"/" API에서 break point를 걸고 localhost:8080으로 GET 요청을 날려보겠습니다.

 

요청한 API가 break point에 걸려 응답이 오지 않으며 로컬 개발 환경에서 원격 디버깅을 수행할 수 있습니다.

 

주의 사항 1 - 개발 환경에서만 사용

첫 번째 주의 사항으로는 JDWP로 원격 디버깅을 수행할 때는 원격 서버의 환경이 개발 환경이어야 합니다.

 

break point를 건 순간 해당 API의 일반 사용자 요청도 모두 break point에 걸리기 때문입니다.

 

상용 원격 서버가 아닌 개발 원격 서버에서 디버깅 목적으로 사용해야 합니다.

 

주의 사항 2 - 원격 서버 프로젝트 코드와 로컬 프로젝트 코드 일치

두 번째 주의 사항으로는 원격 서버에 배포되어 있는 프로젝트 코드와 로컬 프로젝트 코드가 일치해야 합니다.

 

JDWP break point 같은 경우 특정 파일의 몇 번째 줄에 break point를 거는 방식으로 동작합니다.

 

예를 들어 원격 서버에 배포되어 있는 코드가 다음과 같다고 합시다.

 

여기서 14번째 return "Hello Docker World" 코드에서 break point를 걸면 당연히 "/" 경로로 API 요청이 왔을 때 응답을 주기 전에 break point에 걸리게 됩니다.

 

그런데 로컬 프로젝트 코드의 버전이 달라 다음과 같은 코드로 이루어졌다면 어떨까요?

 

위 코드에서 우리가 원하는 상황은 "/test"라는 API의 응답을 보내기 전에 break point를 거는 상황입니다.

 

하지만 원격 서버 코드 기준으로 14번째 줄은 "/" API의 return "Hello Docker World" 입니다.

 

우리는 "/test" API에서 break point가 걸리기를 원했지만 실제로는 "/" API에 break point가 걸리게 됩니다.

 

물론 당연하게도 원격 서버에는 "/test" API가 존재하지 않기 때문에 "/test" API를 보내면 404 에러가 발생합니다.

 

그래서 JDWP로 원격 디버깅을 수행할 때는 로컬 프로젝트 코드와 원격 프로젝트 코드의 버전이 동일해야 합니다.

728x90