Background
규모가 있는 Java application에서는 OS, JVM의 resource를 최대치까지 사용하거나 다수의 thread들 간 race condition이 발생하는 등 시스템에 영향을 주는 일이 발생한다. 이와 같은 일이 발생하기 이전에, 혹은 이전과 동일한 에러로 인해 시스템에서 장애가 발생하지 않도록 시스템 지표들을 분석하고 이를 바탕으로 application을 개선해야 한다.
JMX
Java에서는 어떻게 성능을 측정하고 그 지표들을 제공해줄까? JMX (Java Management Extension)를 통해 가능하다. JMX는 Java 표준 중 일부로서 application, system objects, devices, networks를 manage하고 monitoring하기 위한 tool을 제공한다. 또한 JVM에 대한 monitoring도 가능하다.
위 그림이 나타내는 것처럼 JMX는 크게 instrumentation layer, agent layer, distributed service layer 이렇게 three layer로 구성되어 있다. instrumentation layer는 POJO를 wrapping하여 JMX에서 관리하는 MBeans (managed beans) 형태로 만드는 역할을 한다. 이렇게 만들어진 bean은 agent layer에서 creation, registration, deletion 전체 bean lifecycle에 대해서 관리가 된다. agent layer는 MBeans에 대한 control을 하는 부분과 distributed service layer에 대한 API를 제공하는 역할을 한다. Java application 내부에서는 MBeanServer를 실행시킴으로써 동작하며 target MBeans을 이 MBeanServer에등록(registration)할 수 있다. 마지막으로 distributed service layer에서는 local 혹은 remote에 대한 API를 제공하여 MBeans에 대한 operation이나 local cache evict 등의 제어를 할 수 있게 하며 성능 지표를 제공한다.
https://github.com/taehyeok-jang/jmx-sample
위 링크는 JMX를 사용하는 간단한 code이다. JVM마다 JMX access에 관한 default 설정이 다르므로 실행 환경의 JVM을 살펴볼 필요가 있지만, JVM 실행 시 '-Dcom.sun.management.jmxremote'으로 설정하면 enable하여 JMX access를 가능하게 한다. 다른 설정들로 SSL을 통한 access만 가능하게 하거나, id/password를 사용한 접근만 허용하거나 target application에서 사용하는 listening port와 다른 port를 설정할 수 있게 한다. port를 다르게 하는 것은 특히 deployment 환경에서 중요한데 system 성능 지표를 노출하는 port가 외부로 열려있는 것은 위험하므로, 통상적으로 JMX에 대한 port는 inbound로만 접근이 가능하도록 한다.
```
java -jar ./build/libs/jmx-sample.jar
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1617
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
```
JConsole을 통해서 위 application의 JMX에 접근을 하면 MBean에 대한 정보를 확인할 수 있고 method를 실행할 수도 있다.
JConsole, VisualVM
JMX에서 제공하는 monitoring 기능을 활용하여 Java 성능 profiling을 제공해주는 여러 tool이 있다. 그중에서 대표적인 것이 Java 표준에 속한 JConsole과 OSS로 관리되는 VisualVM이다.
shell에서 jconsole 명령어를 입력하면 위와 같은 JConsole GUI application이 실행된다. JConsole에서는 JVM에대한 overview, memory, threads, classes 등 시스템에 관한 전반적인 지표를 보여준다. 하지만 다소 지엽적인 형태로 제공해주고만 있는데 조금 더 의미있는 정보를 제공해주는 다른 tool을 살펴보자.
VisualVM은 본래 Java 표준에 있던 기술이었지만 현재는 OSS로서 계속 개발되고 있으며, JConsole보다 더 다양한 성능 profiling을 제공한다.
위 그림에서와 같이 시스템 성능 지표를 제공해줄뿐만 아니라 thread dump, heap dump가 가능하며 sampling, profiling을 제공하여 자세한 분석이 가능하다. 아직 sampling, profiling은 제대로 사용하는 방법을 몰라서 소개가 어려운데 아래 영상을 통해서 어떤 기능인지 개괄적으로 살펴볼 수 있다.
TDA, ThreadLogic
thread는 Java application의 핵심적인 자원을 하나로서 동작을 항상 주의깊게 살펴보아야 한다. 필요한 최소 개수의 thread로 최대한의 성능을 이끌어내는 것은 중요하다. 실행 중인 application의 thread 동작을 알기 위해서는 thread dump를 떠야하는데 이를 위한 가장 기본적인 방법으로 JDK에 포함된 jstack이 있다.
```
jstack <target process id> > threaddump
"http-nio-8081-exec-5" #289 daemon prio=5 os_prio=31 cpu=0.10ms elapsed=528.26s tid=0x00007fda88bb0800 nid=0x15303 waiting on condition [0x0000700012684000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.7/Native Method) - parking to wait for <0x000000070897dfc0>
...
"http-nio-8081-exec-6" #290 daemon prio=5 os_prio=31 cpu=0.16ms elapsed=528.26s tid=0x00007fda88bb1800 nid=0x15103 waiting on condition [0x0000700012787000]
java.lang.Thread.State: WAITING (parking)
```
shell에다가 위와 같이 입력하면 thread dump 정보가 담긴 파일을 얻을 수 있으며 내용을 보면 각 thread (application에서 사용하는 thread, GC thread 등의 system thread, web application의 경우 통신과 관련된 thread 등이 있다)에 대한 정보와 현재 상태 (RUNNABLE, WATING, BLOCKING, ...)를 확인할 수 있다. 그런데 enterprise level의 Java application에서는 수백, 수천개의 thread가 생성될 수도 있는데 이들 각각을 모두 살펴보고 thread들 간의 관계를 파악하는 것은 매우 어렵다. 이를 위한 tool로서 TDA (thread dump analyzer), ThreadLogic 등이 있다.
위 그림은 ThreadLogic의 실행을 나타낸다. 각 thread에 대한 상태를 간결하게 확인할 수 있으며 공유 자원 (Java monitor lock)등에 접근하는 thread 집합이 어떻게 되는지, 그리고 그 thread들의 자원에 대한 점유율을 확인하여 효율성에 대해서도 분석한다. 위 application은 하나의 동기화된 (synchonized) 공유 자원에 접근하는 10개의 thread를 실행하고 있는데 10개 thread들 중 특정 시점에 해당 자원을 점유할 수 있는 thread는 하나임으로 그 효율이 매우 낮음을 WARN으로 알려주고 있다. 이 정보를 바탕으로 더 나은 Java application 설계가 가능하다.
GCViewer
Java의 메모리 관리는 garbage collector를 통해서 이루어지므로 이에 대한 지표가 필수적이다. Java application을 실행할 때 JVM option으로서 gc log를 남길 수가 있는데 이를 graphical하게 살펴볼 수 있는 tool이 GCViewer이다. GCViewer는 다음에 살펴보도록 하겠다.
Resources
https://en.wikipedia.org/wiki/Java_Management_Extensions
https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/overview/intro.html#wp5529
https://docs.oracle.com/javase/7/docs/api/javax/management/MBeanServer.html
https://docs.oracle.com/javadb/10.10.1.2/adminguide/radminjmxenabledisable.html
https://alvinalexander.com/blog/post/java/source-code-java-jmx-hello-world-application/
https://alvinalexander.com/blog/post/java/source-code-java-multi-threaded-jmx-application/
https://visualvm.github.io
https://visualvm.github.io/gettingstarted.html?VisualVM_2.0.2
https://www.youtube.com/watch?v=z8n7Bg7-A4I&feature=emb_logo
https://github.com/irockel/tda
https://github.com/sparameswaran/threadlogic
https://www.baeldung.com/java-verbose-gc
https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/overview/intro.html#wp5529
https://docs.oracle.com/javase/7/docs/api/javax/management/MBeanServer.html
https://docs.oracle.com/javadb/10.10.1.2/adminguide/radminjmxenabledisable.html
https://alvinalexander.com/blog/post/java/source-code-java-jmx-hello-world-application/
https://alvinalexander.com/blog/post/java/source-code-java-multi-threaded-jmx-application/
https://visualvm.github.io
https://visualvm.github.io/gettingstarted.html?VisualVM_2.0.2
https://www.youtube.com/watch?v=z8n7Bg7-A4I&feature=emb_logo
https://github.com/irockel/tda
https://github.com/sparameswaran/threadlogic
https://www.baeldung.com/java-verbose-gc
No comments:
Post a Comment