현상
MBeanServer의 queryNames 메서드 수행 시 많은 시간이 소요된다.
JMX 모니터링 클라이언트가 주기적으로 queryNames를 호출하는 환경에서는 해당 호출 구간에서 CPU 사용률이 높아지거나, 스레드 덤프에 JMX 관련 처리 스택이 반복적으로 나타날 수 있다.
원인
JBoss EAP 6.2의 버그로, 6.2 CP3(6.2.3)에서 해결되었다.
6.2.3 Release Notes에는 다음 내용이 포함되어 있다.
1089616 - High CPU usage by JMX monitoring client, RBAC seems the hotspot A performance issue affecting JMX Query was identified, where the CPU load was much higher than expected in previous JBoss EAP releases. The cause of the issue was that role-based access control (RBAC) was checking the address of every query, regardless of whether that address was relevant to JMX Query. To resolve this issue the processing of querie was changed to first check if the address is relevant to JMX Query and if not, avoid the processing involved. The result of this change is that CPU load of JMX monitoring is again at a normal level.
요약하면, JMX Query 처리 과정에서 RBAC(Role-Based Access Control)가 JMX Query와 직접 관련 없는 주소까지 매번 검사하면서 불필요한 비용이 발생했고, 이로 인해 CPU 사용률이 비정상적으로 높아질 수 있었다.
확인 방법
- JBoss EAP 버전이 6.2 CP3(6.2.3) 미만인지 확인한다.
- JMX 모니터링 도구가
MBeanServer.queryNames를 자주 호출하는지 확인한다. - 장애 또는 지연이 발생하는 시점의 스레드 덤프에서 아래와 같이
org.jboss.as.jmx.model.ModelControllerMBeanHelper.queryNames,ResourceAccessControlUtil.getResourceAccess,ReadResourceDescriptionHandler등이 반복적으로 보이는지 확인한다.
해결책
JBoss EAP 6.2 CP03 이상 패치를 적용한다. 원문 작성 시점에는 CP04까지 릴리스되어 있었다.
패치 적용 후에는 동일한 JMX 모니터링 부하 조건에서 queryNames 응답 시간과 CPU 사용률이 개선되는지 비교한다. 운영 환경에 바로 적용하기 전에는 테스트 환경에서 JMX 모니터링 도구의 호출 주기와 대상 MBean 범위를 동일하게 맞춰 재현 여부를 확인하는 것이 좋다.
비고
- Stacktrace (1)
at java.lang.Enum.valueOf(Enum.java:236)
at org.jboss.as.controller.operations.validation.EnumValidator.validateParameter(EnumValidator.java:125)
at org.jboss.as.controller.operations.validation.NillableOrExpressionParameterValidator.validateParameter(NillableOrExpressionParameterValidator.java:75)
at org.jboss.as.controller.AttributeDefinition.validateOperation(AttributeDefinition.java:692)
at org.jboss.as.controller.AttributeDefinition.validateOperation(AttributeDefinition.java:246)
at org.jboss.as.controller.operations.global.ReadResourceDescriptionHandler.doExecuteInternal(ReadResourceDescriptionHandler.java:174)
at org.jboss.as.controller.operations.global.ReadResourceDescriptionHandler.doExecute(ReadResourceDescriptionHandler.java:157)
at org.jboss.as.controller.operations.global.ReadResourceDescriptionHandler.execute(ReadResourceDescriptionHandler.java:150)
at org.jboss.as.controller.AbstractOperationContext.executeStep(AbstractOperationContext.java:607)
at org.jboss.as.controller.AbstractOperationContext.doCompleteStep(AbstractOperationContext.java:485)
at org.jboss.as.controller.AbstractOperationContext.completeStepInternal(AbstractOperationContext.java:282)
at org.jboss.as.controller.AbstractOperationContext.executeOperation(AbstractOperationContext.java:277)
at org.jboss.as.controller.ModelControllerImpl.internalExecute(ModelControllerImpl.java:231)
at org.jboss.as.controller.ModelControllerImpl.execute(ModelControllerImpl.java:137)
at org.jboss.as.jmx.model.ResourceAccessControlUtil.getResourceAccess(ResourceAccessControlUtil.java:85)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:48)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.iterate(RootResourceIterator.java:41)
at org.jboss.as.jmx.model.ModelControllerMBeanHelper.queryNames(ModelControllerMBeanHelper.java:158)
at org.jboss.as.jmx.model.ModelControllerMBeanServerPlugin.queryNames(ModelControllerMBeanServerPlugin.java:168)
at org.jboss.as.jmx.PluggableMBeanServerImpl.queryNames(PluggableMBeanServerImpl.java:850)
- Stacktrace (2)
at org.jboss.dmr.ModelNode.set(ModelNode.java:431)
at org.jboss.as.controller.AttributeDefinition.getNoTextDescription(AttributeDefinition.java:585)
at org.jboss.as.controller.AttributeDefinition.addResourceAttributeDescription(AttributeDefinition.java:454)
at org.jboss.as.controller.descriptions.DefaultResourceDescriptionProvider.getModelDescription(DefaultResourceDescriptionProvider.java:76)
at org.jboss.as.controller.operations.global.ReadResourceDescriptionHandler.doExecuteInternal(ReadResourceDescriptionHandler.java:192)
at org.jboss.as.controller.operations.global.ReadResourceDescriptionHandler.doExecute(ReadResourceDescriptionHandler.java:157)
at org.jboss.as.controller.operations.global.ReadResourceDescriptionHandler.execute(ReadResourceDescriptionHandler.java:150)
at org.jboss.as.controller.AbstractOperationContext.executeStep(AbstractOperationContext.java:607)
at org.jboss.as.controller.AbstractOperationContext.doCompleteStep(AbstractOperationContext.java:485)
at org.jboss.as.controller.AbstractOperationContext.completeStepInternal(AbstractOperationContext.java:282)
at org.jboss.as.controller.AbstractOperationContext.executeOperation(AbstractOperationContext.java:277)
at org.jboss.as.controller.ModelControllerImpl.internalExecute(ModelControllerImpl.java:231)
at org.jboss.as.controller.ModelControllerImpl.execute(ModelControllerImpl.java:137)
at org.jboss.as.jmx.model.ResourceAccessControlUtil.getResourceAccess(ResourceAccessControlUtil.java:85)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:48)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.doIterate(RootResourceIterator.java:59)
at org.jboss.as.jmx.model.RootResourceIterator.iterate(RootResourceIterator.java:41)
at org.jboss.as.jmx.model.ModelControllerMBeanHelper.queryNames(ModelControllerMBeanHelper.java:158)
at org.jboss.as.jmx.model.ModelControllerMBeanServerPlugin.queryNames(ModelControllerMBeanServerPlugin.java:168)
at org.jboss.as.jmx.PluggableMBeanServerImpl.queryNames(PluggableMBeanServerImpl.java:850)