본문 바로가기
Programming/Java

VisualVM 원격에서 접속하기 [이론편]

by peter paak 2021. 2. 17.
728x90

지난 주 Udemy에서 Java Application Performance and Memory Management 강의를 보편서 한동안 개인 프로젝트 letshadow에 사용해보고 싶은 생각이 문득 들었습니다. 회사에서는 scouter를 사용해서 모니터링하고 있지만 개인 프로젝트 서버에 scouter를 도입하기는 agent를 따로 설치해야되어 모니터링 효율대비 리소스를 잡아 먹을 것 같다는 생각이 들었고, 스프링부트 어드민 또한 어드민 어플리케이션을 하나 더 띄워야 했기 때문에 한동안은 JVM에 내장되어있는(JDK 8기준) visualvm을 사용하는 것이 좋겠다고 생각했습니다. 이번에는 visualvm을 원격에서 구동하는데 필요한 JMX와 RMI에 대해서 한번 알아보겠습니다.

visualvm 동작과정

visualvm은 JVM이 설치된 서버의 자원(메모리, cpu 사용량) 등을 사용자가 쉽게 모니터링 할 수 있는 클라이언트 툴입니다. 우리 컴퓨터에 visualvm을 설치하고 외부서버의 JVM과 연결을 하면 JVM을 가진 서버의 서버 자원의 사용량을 가져와 화면에 보여주게 됩니다. 이때 JVM 내부에 JMX이라는 심부름꾼이 서버의 자원을 가져와 visualvm에 던져주게 됩니다.

JMX

JMX는 Java Management Extension으로 모니터링 목적으로 사용되는 프로그램이라고 할 수 있습니다. 앞서 visualvm으로 서비스의 자원을 가져올 때 JMX를 사용한다고 하였습니다. 정확히는 서버의 자원을 숫자로 표현하기 위해서는 visualvm과 같은 클라이언트에서 어떤 자원을 가져와 라는 이벤트를 받으면 서버의 메모리나 cpu 자원의 값을 가져오는 메소드를 사용하게 됩니다. 우리가 흔히 아는 클래스를 생성하고 객체를 생성하여 메소드를 호출하듯 같은 과정을 통해 메소드의 리턴값으로 메모리, cpu 등의 자원 사용량을 받아오게 됩니다.

그 역할을 MBean이 하게 됩니다. MBean은 Managed Bean의 약자로 JVM에서 관리되고 있는 bean입니다. 마치 스프링 컨테이너에서 관리되는 bean처럼 JVM에서 서버의 자원을 가져오는 메소들을 가진 bean들을 한곳에 모아놓게 됩니다. 이렇게 모아 놓은 MBean을 참조하여 자원을 가져오는 메소드를 가져오라고 시키는 것이 바로 JVM에 존재하는 JMX Agent의 역할입니다. 내부에 MBean에 대응하는 서비스를 가지고 있어서 원하는 자원을 가져오도록 시킬수 있습니다. 또한 JMX Agent에는 MBean Server라는 외부와 소통하는 서버가 있습니다. 이를 통해서 우리가 visualvm이라는 JMX 클라이언트 툴과 연결을 할 수 있습니다.

코드관점에서 이를 가능하게 하는 것은 내부적으로 추상화 기법을 사용하고 있기 때문입니다. JMX Agent가 MBean의 메소드를 호출한다고 하였는데 이는 JMX Agent가 MBean을 interface 타입으로 bean에 등록하면 MBean은 해당 인터페이스의 구현체로써 역할을 하게 됩니다. 간단히 말하면 아래와 같이 동작하게 됩니다.

MBean

interface MemeryBean {

    public int getMemoryUsage();
}

class Memory implement MemoryBean {

    @Override
    public int getMemoryUsage() {
        return Memory.getUsage();
    }

}

JMX Agent

MemoryBean memoryBean = new Memory();
memoryBean.getMemoryUsage();

MBean은 MemoryBean이라는 getMemoryUsage()라는 메소드를 가진 인터페이스를 상속받고 해당 메소드를 Override하여 구현합니다. JMX Agent는 MemoryBean이라는 인터페이스 타입을 추상화하여 getMemoryUsage() 메소드를 사용하여 실제 메모리 사용량을 가져옵니다.

정리를 하면 visualvm은 외부 서버의 JVM의 JMX Agent와 소통하기 위해 MBean Server와 연결하게 되고 JMX Agent를 통해 MBean의 메소드를 사용하여 서버의 메모리, cpu를 정보를 visualvm에 리턴하게 됩니다.

RMI

RMI는 Remote Method Invocation으로 우리가 흔히 아는 HTTP와 같은 통신 규약 중 원격 메소드를 호출하는데 사용하는 규약(protocol)입니다. 실제 visualvm과 JMX Server을 통신하도록 해주는 역할을 합니다. 나중에 visualvm을 원격서버와 연결을 할 때, RMI과 JMX를 서버에서 실행시키고 같은 포트를 사용하게 할 것인데 이 같은 이유로 보통은 같은 포트를 사용하게 됩니다.

정리

정리를 하면 다음과 같은 순서로 동작하며, 이는 실제 visualvm을 원격으로 연결하는 순서와 비슷한 흐름을 가지게 됩니다.

  1. visualvm 실행 (JMX 클라이언트 실행)
  2. JMX Agent 실행
  3. RMI를 실행하여 JMX Agent와 visualvm의 통신
  4. visualvm에서 cpu, memory 사용량을 JMX에 요청하면 해당 자원의 값을 가져오는 메소드를 가진 MBean을 호출하여 visualvm에 반환

조금 더 자세한 내용은 Java JMX이란에 자세히 설명 되어 있습니다. 저는 다음 시간에 visualvm을 실제로 원격에 접속하는데 필요한 전체적인 흐름에 대해서 살펴보았습니다. 사실 모니터링 툴을 그 목적으로만 사용해보았지 내부적으로 어떻게 동작하는지에 대해서는 생각해보지 않았습니다. 실제로 JMX 키워드로 검색해보면 많은 분들이 모니터링 툴을 제작하는 것을 볼 수 있습니다. 기회가 되면 웹용 모니터링 툴을 한번 제작 해보는 것도 좋은 경험이 될 것 같습니다.

728x90