TCP 로 DB 문제 확인하기 - 3

SCOUTER 는 어플리케이션 성능 모니터링 툴로 오픈소스 APM 입니다. 해당 현상을 분석하기 위해 저번주에 계속 모니터링 한 경과 최종적으로 3가의 의심스러운 패턴을 찾을 수 있었는데,

  1. Protocol.read 시에 지연이 발생.
  2. DB에서 지연이 발생.
  3. 레디스의 데이러를 JSON Mapper 를 통해 객체를 할 때 지연이 발생.

SCOUTER 에서 지연되는 내역이 다음과 같이 나왔는데, 해당 현상에 대해서는 확신을 할 수없어, 또다른 APM 인 네이버 pinpoint로 분석하고자 했습니다.

설치하는 방법은 QuickStart를 참고했습니다.

예전에 서버에 바로 올렸다가, 1분마다 8기가의 데이터가 쌓이는 공포를 겪었기 때문에, 반영하는 모든 log4j.xml 의 DEBUG를 ERROR 로 변경하였습니다. 혹시 나중에 또 필요할 수 있어 간단하게 설정한 내역을 정리합니다.

JAVA 설치

vi /etc/profile

export JAVA_6_HOME=/usr/lib/jvm/java-1.6.0
export JAVA_7_HOME=/usr/lib/jvm/java-1.7.0
export JAVA_8_HOME=/usr/lib/jvm/java-1.8.0
export JAVA_9_HOME=/usr/lib/jvm/java-1.9.0

하단에 JAVA_6_HOME 및 추가된 jdk 경로 설정합니다. jdk 가 없을 시 download 하거나 yum install 로 설치합니다. 수정 후 꼭 ssh 재접속해야합니다. 실제로 가이드 문서에는 jdk 9 (JAVA_9_HOME) 을 넣으라는 글이 없었는데, 해당 버젼이 없으면, 에러가 나네요.

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] javac: invalid target release: 9
Usage: javac <options> <source files>
use -help for a list of possible options

jdk9 가 없어 도중에 에러가 납니다.

[DEBUG] Goal:          org.apache.maven.plugins:maven-enforcer-plugin:1.4.1:enforce (enforce-pinpoint-build-requirements)
[DEBUG] Style:         Regular
[DEBUG] Configuration: <?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <fail default-value="true">true</fail>
  <failFast default-value="false">${enforcer.failFast}</failFast>
  <ignoreCache default-value="false">${enforcer.ignoreCache}</ignoreCache>
  <mojoExecution default-value="${mojoExecution}"/>
  <project default-value="${project}"/>
  <rules>
    <requireMavenVersion>
      <version>3.2</version>
    </requireMavenVersion>
    <requireJavaVersion>
      <version>1.7</version>
    </requireJavaVersion>
    <requireEnvironmentVariable>
      <variableName>JAVA_6_HOME</variableName>
    </requireEnvironmentVariable>
    <requireEnvironmentVariable>
      <variableName>JAVA_7_HOME</variableName>
    </requireEnvironmentVariable>
    <requireEnvironmentVariable>
      <variableName>JAVA_8_HOME</variableName>
    </requireEnvironmentVariable>
    <requireEnvironmentVariable>
      <variableName>JAVA_9_HOME</variableName>
    </requireEnvironmentVariable>
  </rules>
  <session default-value="${session}"/>
  <skip default-value="false">${enforcer.skip}</skip>
</configuration>
[DEBUG] -----------------------------------------------------------------------

JAVA_9_HOME 가 필수적으로 필요했는데, 해당 내용이 없어서, pom.xml 을 변경하려다가 그냥 jdk 9 를 설치해버렸습니다.

MAVEN 설치

http://maven.apache.org/download.cgi 에서 최신 maven 다운로드
설치 경로에서 tar xvf apache-maven-3.5.0-bin.tar.gz

MAVEN 홈페이지에 가서, maven 을 설치합니다. 저는 그냥 최신 버젼 설치했습니다. maven 로 yum install 로 설정하려고 했는데 기존 설치되어있는 거랑 뭔가 안맞아서, 강제로 환경설정을 셋팅했습니다.

# vi /etc/profile.d/maven.sh


#!/bin/bash
MAVEN_HOME=/설치경로/apache-maven-3.5.0 /usr/local/maven/bin/mvn
PATH=$MAVEN_HOME/bin:$PATH
export PATH MAVEN_HOME
export CLASSPATH=.

쉘스크립트 작성후, 해당 쉘스크립트에 실행권한을 부여했습니다.

# chmod +x /etc/profile.d/maven.sh
# source /etc/profile.d/maven.sh

설치여부 확인

[root@localhost apache-maven-3.5.3]# mvn -version
Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T04:49:05+09:00)
Maven home: /home/pinpoint/apache-maven-3.5.3
Java version: 1.8.0_161, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre
Default locale: ko_KR, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-693.17.1.el7.x86_64", arch: "amd64", family: "unix"

GIT 설치


[root@localhost pinpoint]# git --version
git version 1.8.3.1
[root@localhost pinpoint]# java -version
openjdk version "1.8.0_161"
OpenJDK Runtime Environment (build 1.8.0_161-b14)
OpenJDK 64-Bit Server VM (build 25.161-b14, mixed mode)
[root@localhost pinpoint]# 

git 은 그냥 귀찮아서 yum install 로 설치했습니다.

설치 완료 후

./mvnw install -Dmaven.test.skip=true

해당 파일을 설치합니다.

저는 서버에 설치된 파일과, 클라이언트 서버가 틀리므로, quickstart 폴더의 agent 폴더를 다운받아, 클라이언트 서버에 해당 파일을 올립니다. 물론 log4j.xml 의 모든 내용은 DEBUG -> ERROR, INFO -> ERROR 로 바꿉니다.

./quickstart/lib/log4j.xml

해당 파일의 내용을 수정합니다. [QuickStart]에서 알려준 대로, 순서대로 실행합니다.

quickstart/bin/start-hbase.sh
quickstart/bin/init-hbase.sh
quickstart/bin/start-collector.sh
quickstart/bin/start-web.sh

http://host:28080 로 해당 web 페이지가 정상적으로 뜨는지 확인합니다.

결론

scouter 의 hook_method_patterns 로 분석하였던 내용과 비슷한 내용이 pinpoint 에도 나왔습니다.

레디스의 Json 형태의 String을 Json 라이브러리를 통해 객체화 하는 대서 200 (ms) 의 지연이 간혈적으로 발생.

Method Gap(ms) Class Api
toJSON(Object object, JsonConfig jsonConfig) 211 JSONSerializer JSON-LIB

mysql 의 excute 에서 미약한 지연 발생

Method Gap(ms) Class Api
execute() 139 PreparedStatement MYSQL(xxxx)

레디스에서 해당 데이터를 읽을 때 지연이 발생

Method Argument Gap(ms) Class Api
exists(String key) write: 0ms, read: 587ms 585 Jedis REDIS

위 3가지 항목으로 우선적으로 redis 서버를 증설 및 분리했습니다. 분리됨에 따라 레디스에서 해당 데이터를 읽을 때 지연이 발생하는 현상에 대한 해결은 어느정도 된 것으로 파악됩니다. 이제 Redis 에 해당 데이터를 write 할떄, Json 이 아니라 Object를 바이너리화하여 바로 넣고 사용하는 형태로 변경하는 작업을 진행하고자 합니다.

변경할 작업은 다음과 같습니다.

  1. JSONObject를 그냥 Object 로 바이너리로 레디스 저장.
  2. kakao 에 맞는 성능의 별도의 JSON-Lib 적용 참고 주소
  3. 레디스 및 ehcache 시간 및 기능 변경

참조