엔지니어링

Metricbeat와 Jolokia를 이용한 자바 애플리케이션 모니터링

자바 가상 머신(JVM)은 운영 관리 및 모니터링에 대한 완전한 프레임워크를 특징으로 합니다. 이 글에서는, JMX(Java Management eXtensions)가 무엇인지 소개하고, JMX가 노출시키는 정보를 탐색하는 방법, JMX를 Jolokia, Elastic Stack과 함께 활용하는 방법에 대해 알아보겠습니다. JMX과 Jolokia에 대해 알고 계시면, 첫 부분은 건너뛰고 바로 이동하셔서 관련 Metricbeat 기능에 대해 좀더 상세히 알아보셔도 됩니다.

JMX과 JConsole

JMX는 자바 애플리케이션을 모니터링하고 관리하기 위한 완전한 아키텍처와 일련의 디자인 패턴을 정의하는 테크놀로지입니다. 이것은 관리되는 빈(managed beans)을 기반으로 하는데, 흔히 MBeans라고 하며, JVM에서 리소스를 표현하는 의존성 주입에 의해 인스턴스화되는 클래스입니다. 이러한 표현은 애플리케이션의 특정 측면을 관리하기 위해 사용될 수 있으며, 좀더 빈번하게, 이러한 리소스의 사용에 대한 통계를 수집하기 위해서도 사용될 수 있습니다. JMX의 핵심에는 MBean Server가 있는데, MBeans, 동일한 JVM의 애플리케이션, 그리고 외부 세계 사이에서 중개자 역할을 하는 엘리먼트입니다. MBeans와의 상호작용은 이 서버를 통해 이루어집니다. 일반적으로, 자바 코드만이 JMX API에 직접 접근할 수 있지만, 이 API를 표준 프로토콜로 변환하는 어댑터들이 있습니다. 예를 들면, Jolokia는 이것을 HTTP로 변환해 줍니다. JMX로 작업하는데 있어 유용한 도구는 JConsole인데, 자바 런타임의 통상적인 배포에 포함되어 있습니다. JConsole을 열면, 사용자의 장비에서 작동 중인 자바 프로세스 목록과 함께 환영 인사가 뜹니다. 작동 중인 자바 프로세스가 없더라도, 최소한 JConsole 그 자체는 보게 됩니다.

JConsole 환영 화면

이 프로세스 중 어느 것에라도 연결되면, 메모리나 스레드와 같은 프로세스의 여러 다른 측면에 대한 일반적인 모니터링 정보와 함께 여러 다른 탭이 있는 창이 열립니다. MBeans 브라우저가 있는 탭도 있습니다.

JConsole 메인 창

브라우저에서, 네임스페이스 별로 그룹화된 프로세스의 MBeans 목록을 볼 수 있습니다. 그 중 일부는 java.lang 네임스페이스 하에 있는 것들처럼, 모든 JVM에서 찾아볼 수 있으며, 반면에 다른 것들은 애플리케이션에 고유한 것들입니다. 각 MBean마다, 속성, 기능, 알림에 대한 여러 다른 카테고리를 보실 수 있습니다. 모니터링의 경우, 우리는 속성에 중점을 둡니다. 일부 MBeans는 서로 다르더라도, 동일한 인터페이스를 실행합니다. 예를 들어, Tomcat이나 Kafka 같은 다른 애플리케이션이 사용 사례에 따라 다른 가비지 콜렉터를 사용하는 것을 흔히 찾아볼 수 있습니다. 그러나 JMX에서는, 이것이 동일한 유형의 객체이며, 이름만 다릅니다.

JConsole의 MBean 브라우저

이 정보를 모두 찾을 수 있다면 정말 좋겠지만, 모니터링을 할 때 JConsole 같은 인프라는 보통 사용이 가능하지 않습니다. 게다가, 다른 서버에 있을 수 있는 다른 프로세스로부터 정보를 집계해야 할 수도 있습니다. 다행히도, Metricbeat와 Jolokia에서 이것을 처리할 수 있습니다.

Metricbeat와 Jolokia를 이용해 JMX 메트릭 수집하기

Metricbeat는 여러 다른 서버로부터 정보를 수집하여 Elasticsearch로 전송할 수 있고, 거기서 Kibana에서 제공하는 다양한 방식으로 시각화할 수 있습니다. 그러나 앞서 본 것처럼, JMX는 자바 애플리케이션에서만 사용이 가능합니다. 바로 이 때 Jolokia가 등장하게 됩니다. Jolokia는 JVM에서 배포될 수 있는 에이전트로서, REST 같은 HTTP 엔드포인트를 통해 MBeans를 노출시켜, 이 모든 정보가 동일한 호스트에서 작동하는 비 자바 애플리케이션에 쉽게 제공되도록 합니다. 일반 JVM 에이전트로, Java EE 환경에서는 WAR로, 또는 OSGI나 Mule 에이전트로 배포될 수 있습니다. Jolokia를 에이전트로 배포하려면, 자바 애플리케이션을 시작할 때 ‘-javaagent’ 플래그가 사용되어야 합니다. 자바 명령어를 직접 사용할 때는 아규먼트로 넘겨줄 수 있지만, 일부 애플리케이션은 자체의 시작 스크립트를 가지고 있을 수 있고, 문서에서 다른 종류의 실행 방법을 권장할 수도 있습니다. 예를 들어, Kafka를 자체의 시작 스크립트와 함께 사용할 때는, KAFKA_OPTS 환경 변수를 이용해야 할 수도 있습니다.

export KAFKA_OPTS=-javaagent:/opt/jolokia-jvm-1.5.0-agent.jar=port=8778,host=localhost
./bin/kafka-server-start.sh ./config/server.properties

Jolokia를 WAR로 배포하려면, 에이전트가 Java EE 서버에 설치되어야 합니다. 예를 들어, Tomcat에서는 WAR 파일을 그 webapps 디렉토리로 복사하면 됩니다. 각 애플리케이션마다, 문서를 확인해 자바 에이전트를 작동시키기 위한 가장 좋은 방법을 찾아보실 것을 권합니다. 또한 Jolokia 문서에서 어떤 에이전트가 제공되고 어떤 옵션이 있는지 확인해 보실 것도 권해 드립니다. 동일한 JVM에서 Jolokia를 배포하는 것이 가능하지 않은 경우, Jolokia에는 또한 다른 JVM으로부터 JMX를 쿼리하는데 사용할 수 있는 프록시 모드가 있습니다. 일단 Jolokia가 애플리케이션의 JVM에서 작동하고 있으면, 무척 간단하게 Metricbeat 5.4에서 소개되는 Jolokia 모듈의 JMX metricset]7를 사용해 Metricbeat로 JMX 메트릭을 수집할 수 있습니다. 이 모듈은 Jolokia 에이전트의 호스트와 포트, 그리고 JMX 메트릭과 Metricbeat 이벤트 필드 사이의 일련의 매핑으로 구성되어야 합니다. 예를 들어 보겠습니다.

예: Metricbeat와 Jolokia로 자바 애플리케이션 모니터링하기 ------------------------------------------------------------------ 앞서 Kafka의 예를 든 경우에서처럼, 로컬호스트, 포트 8778에서 Jolokia가 듣게 한다고 가정합시다. JConsole을 사용해 모니터링하고자 하는 MBeans와 속성을 찾아볼 수 있습니다. MBean을 선택함으로써, 우리는 그 이름을 볼 수 있고, 그 이름을 직접 구성 파일로 복사할 수 있습니다.

JConsole에서 MBean 스레딩

이 예에서, 우리는 java.lang:type=Threading MBean으로부터 스레드 수를 모니터링하게 되고, java.lang:type=Memory로부터 메모리 사용을 히프하게 됩니다. 구성은 이와 같을 것입니다.

- module: jolokia
  metricsets: ["jmx"]
  hosts: ["localhost:8778"]
  period: 10s
  namespace: "jvm"
  jmx.mappings:
  - mbean: "java.lang:type=Memory"
    attributes:
    - attr: "HeapMemoryUsage"
        field: "memory.heap"
    - attr: "NonHeapMemoryUsage"
        field: "memory.nonheap"
  - mbean: "java.lang:type=Threading"
    attributes:
    - attr: "ThreadCount"
        field: "thread.count"
    - attr: "DaemonThreadCount"
        field: "thread.daemon"

Metricbeat는 주기적으로 정보를 수집하여 4개의 값을 가진 이벤트를 전송합니다. JConsole에서는 메모리 사용량 속성이 스레드 수 같은 평범한 값이 아니라, 각각 4개의 필드를 포함하는 객체임을 알 수 있습니다. Metricbeat는 이벤트에서 데이터를 다시 구조화하며, 결국 jolokia.jvm 네임스페이스

수집된 jolokia 이벤트 메트릭이 있는 이벤트

하에 10개의 필드를 포함합니다.

고급 구성

다른 이벤트에서 필드를 사용하고 싶어질 수도 있습니다. Metricbeat 6.3부터, JMX 매핑은 또한 어떻게 필드가 이벤트 설정을 사용해 그룹화되어야 하는지를 정의할 수 있습니다. 동일한 값을 가진 두 개의 이벤트는 함께 그룹화됩니다. 예를 들어, 다음 구성은 두 개의 다른 이벤트를 생성하게 됩니다. 하나는 메모리 필드, 또 하나는 스레드 필드를 위한 것입니다.

  jmx.mappings:
  - mbean: "java.lang:type=Memory"
    attributes:
    - attr: "HeapMemoryUsage"
        field: "memory.heap"
        event: "memory"
    - attr: "NonHeapMemoryUsage"
        field: "memory.nonheap"
        event: "memory"
  - mbean: "java.lang:type=Threading"
    attributes:
    - attr: "ThreadCount"
      field: "thread.count"
      event: "threads"
    - attr: "DaemonThreadCount"
      field: "thread.daemon"
      event: "threads"

버전 6.3에서 소개되는 또하나의 새로운 기능은 와일드카드 지원입니다. 덕분에 우리는 여러 MBeans에 단일 매핑을 사용할 수 있으며, 이것은 애플리케이션에 동일한 유형의 인스턴스가 여러 개 포함되어 있거나 특정 이름이 사전에 알려져 있지 않을 때 유용합니다. 예를 들어, Tomcat은 여러 개의 스레드 풀을 갖는데, 우리는 추가 구성으로 이전 매핑을 확장시켜 풀 당 스레드와 접속 수를 얻을 수 있습니다.

  - mbean: "Catalina:name=*,type=ThreadPool"
    attributes:
    - attr: "currentThreadCount"
      field: "thread.count"
    - attr: "maxThreads"
      field: "thread.max"
    - attr: "connectionCount"
      field: "connection.count"

이 구성을 이용하면, 새 이벤트가 매칭되는 각 mbean에 대해 전송되며, mbean의 이름을 새 필드

와일드카드를 사용할 때 수집된 Jolokia 메트릭을 가진 이벤트

로 포함합니다. Metricbeat 6.4에서 Jolokia를 전폭적으로 지원하기 위해 우리는 커뮤니티의 기여Jolokia Discovery의 실행에 힘입어 프록시 모드를 추가하게 됩니다. 이것은 보다 동적인 환경에서 자바 애플리케이션을 모니터링할 수 있게 해줄 것입니다. Jolokia Discovery는 UDP 멀티캐스트를 기반으로 하는 테크놀로지로서, Jolokia 에이전트가 속한 서비스에 대한 일부 추가 정보와 더불어 엔드포인트를 선언할 수 있게 해줍니다. 우리의 실행은 우리가 이미 Kubernete와 Docker에서 사용하고 있는 autodiscover 프레임워크가 지원하며, 템플릿을 기반으로 모든 기능을 갖춘 동적 구성을 제공해 줍니다. 이전 사례에 대해 Jolokia Discovery를 활용하고자 하는 경우에는 다음과 같이 할 수 있습니다(스레드 수만 수집하는 걸로 줄였습니다).

metricbeat.autodiscover:
  providers:
  - type: jolokia
    templates:
    - condition:
        contains:
          jolokia.agent.version: "1.5.0"
      config:
      - module: "jolokia"
        metricsets: ["jmx"]
        hosts: ["${data.jolokia.url}"]
        namespace: "jvm"
        jmx.mappings: 
        - mbean: "java.lang:type=Threading"
          attributes:
          - attr: "ThreadCount"
            field: "thread.count"
    - condition:
        contains:
          jolokia.server.product: "tomcat"
      config:
      - module: "jolokia"
        metricsets: ["jmx"]
        hosts: ["${data.jolokia.url}"]
        namespace: "jvm"
        jmx.mappings:
        - mbean: "Catalina:name=*,type=ThreadPool"
          attributes:
          - attr: "currentThreadCount"
            field: "thread.count"

이 구성은 두 개의 템플릿으로 이루어지는데, 하나는 모두 발견된 Jolokia 인스턴스에 적용되고, 두 번째는 Tomcat 인스턴스에만 적용됩니다. 템플릿의 구성들이 대부분 이전과 동일하지만, 호스트에 대해 변수를 사용하는 방식을 눈여겨 보세요. 이 기능은 JMX metricset와 함께 사용하려고 만든 것이지만, 다른 모듈들, 심지어 filebeat와도 함께 창조적으로 사용할 수 있는 모든 가능성이 열려 있습니다. 더 자세히 알고 싶으시면, Jolokia 모듈autodiscover 문서를 보시거나 [Discuss에 대해 저희에게 문의해 주세요].19. [