오픈 소스 APM Pinpoint 도입 및 후기


들어가며

안녕하세요 트렌비 스토어팀에서 서버 개발을 맡고 있는 오언과 우니입니다.

스토어팀에서는 장바구니, 주문, 결제 등 고객들이 상품을 구매할 때 접하게 되는 주요서비스들을 담당하고 있습니다.

최근 서비스의 병목 지점을 해결하기 위해 성능 개선을 진행하였는데, 그 과정에서 모니터링 도구인 Pinpoint를 도입하였습니다.

이 포스팅을 통해 Pinpoint를 도입했던 과정과 후기를 공유하고자 합니다.

도입 배경

평상시에는 정상적으로 제공되던 서비스가 마케팅 푸시나 문자 알림 등의 영향으로 사이트에 트래픽이 몰리게 되는 경우 서버 지연이나 장애가 발생해 고객들이 서비스 이용에 불편을 겪게 되는 문제들이 종종 발생했습니다.

저희 스토어팀에서는 서비스 품질 확보를 위해 문제가 되는 병목 구간을 추적하고 점진적으로 개선해나가고자 Pinpoint를 도입하게 되었습니다.

Pinpoint를 선택한 이유

모니터링 도구에 대한 고민을 할 때 중요하게 봤던 부분은 아래와 같습니다.

  • 문제 발생 지점 및 병목 구간을 쉽게 발견할 수 있고, 코드 수준의 가시성을 제공하는지
  • 분산 시스템 내 서버 간 관계성을 시각화해서 제공하는지
  • 오픈 소스로서 지속적으로 관리가 되고 지원이 이루어지고 있는지
  • 서버의 트래픽, 응답 시간, Load Average 등 구체적인 상태 확인이 가능한지

Pinpoint는 위와 같은 조건을 만족하였을 뿐만 아니라 소스 코드를 수정하지 않고 손쉽게 적용하고 제거할 수 있는 장점이 있었기에 Pinpoint를 선택하게 되었습니다.

Pinpoint란?

그렇다면 Pinpoint는 무엇일까요?
Pinpoint는 대규모 분산 시스템의 성능을 분석하고 문제를 진단, 처리하는 플랫폼입니다.

내부적으로 서버맵, 실시간 활성 스레드 차트, 요청/응답 차트, API의 호출 상세 이력, 서버의 상태를 실시간으로 시각화하여 볼 수 있는 기능 등을 제공합니다.

Pinpoint 구조

Pinpoint 서비스를 구축하기 위해서는 다음과 같은 모듈이 구성되어야 합니다.

Pinpoint Agent

Pinpoint Agent는 애플리케이션의 모니터링 정보를 수집하여 Pinpoint Collector에 전달합니다.

Pinpoint Agent는 JVM의 javaagent 옵션을 활용하는데, javaagent를 사용하면 클래스 로더가 클래스를 읽어올 때 동적으로 바이트코드를 조작할 수 있습니다.

이는 Pinpoint를 도입하기 위해서 애플리케이션 내의 코드를 수정할 필요가 없다는 것을 의미합니다.

javaagent 옵션에 다음과 같은 Pinpoint Agent jar 파일 $AGENT_PATH/pinpoint-bootstrap-$VERSION.jar를 설정하면 애플리케이션이 실행될 때 바이트코드가 동적으로 조작되어 모니터링 데이터를 수집하고 전달하는 Pinpoint Agent가 실행이 됩니다.

Pinpoint Collector

Pinpoint Collector는 Pinpont Agent에서 받은 데이터를 HBase에 저장합니다.

Pinpoint는 코드 수준의 정보를 추적하기 때문에 트래픽이 많아지게 되면 저장하는 데이터의 양도 기하급수적으로 증가합니다. 이런 대용량 데이터를 저장하기 위해 Pinpoint는 하둡기반의 분산 데이터베이스인 Hbase를 사용하고 있습니다.

Pinpoint Web

HBase에서 데이터를 조회해서 Web UI 형태로 시각화된 모니터링 서비스를 제공합니다.

핀포인트 아키텍쳐 [출처: pinpoint-apm.gitbook.io]

Pinpoint 설치

Pinpoint를 설치하기 위해서는 크게 Pinpoint용 서버와 모니터링이 필요한 서버에 Agent 설치가 필요합니다. 핀포인트 클라우드 [출처: NAVER Pinpoint Cloud]

모니터링 대상 서버에는 agent를 직접 설치하여야 하지만, Pinpoint용 서버는 직접 구축을 할 수도 있고 네이버 클라우드 플랫폼 서비스를 이용해서 구축 없이 편하게 서버를 사용할 수도 있습니다.

Pinpoint용 서버

pinpoint용 서버를 설치하기 위해서는 Pinpoint Agent를 제외한 Pinpoint Collector, Web와 HBase 등의 설치가 필요합니다.

트렌비에서는 Pinpoint용 서버를 직접 구축하는 방식으로 진행을 했고 서버 구축은 플랫폼팀에서 별도로 진행을 해주셨기에 이에 대해서는 간단한 설치 방법만 공유 드리고자 합니다.

HBase 설치

Pinpoint를 사용하기 위해서는 호환되는 HBase을 다운로드 해야 합니다.
설치한 Pinpoint 버전은 2.3.3 이므로 HBase 1.2.x 버전이나 1.4.x 버전을 설치하면 됩니다. 핀포인트 클라우드

  • Hbase 다운로드
    $ wget http://archive.apache.org/dist/hbase/1.2.7/hbase-1.2.7-bin.tar.gz
    $ tar -zxvf hbase-1.2.7-bin.tar.gz 
    

Pinpoint Collector, Web 설치

Pinpoint Collector, Web은 jar 파일을 받아 실행하면 되는데 별도의 WAS 설치 필요없이 스프링 부트 기반으로 단독 실행이 가능합니다.

  • Pinpoint Collector, Web 다운로드
    $ wget https://github.com/pinpoint-apm/pinpoint/releases/download/v2.3.3/pinpoint-collector-boot-2.3.3.jar
    $ wget https://github.com/pinpoint-apm/pinpoint/releases/download/v2.3.3/pinpoint-web-boot-2.3.3.jar
    


도커 기반 환경에서 Pinpoint Agent 설치하기

저희 팀에서 관리하는 애플리케이션들은 운영 환경에서 도커 컨테이너로 실행되기 때문에 Pinpoint Agent 파일을 도커 기반에서 적용하는 방법을 시도하였습니다.

처음에는 Pinpoint Agent 파일을 다운로드 받아 애플리케이션의 도커 이미지를 빌드하는 과정에 이를 복사해서 넣는 방식을 사용했습니다.

  • Pinpint Agent 파일 다운로드
    $ wget https://github.com/pinpoint-apm/pinpoint/releases/download/v2.3.3/pinpoint-agent-2.3.3.tar.gz
    $ tar -zxvf pinpoint-agent-2.3.3.tar.gz
    

    하지만 이 과정에서 도커 이미지를 빌드하는데 시간도 오래 걸리고 이미지의 크기도 증가하여 결과적으로 배포하는 시간도 오래 늘어나게 되었습니다. 그래서 다른 방법을 찾게 되었습니다.

다음 방법으로는 공식 Pinpoint Agent 도커 이미지를 사용하였습니다.

  • 공식 Pinpoint Agent 도커 이미지 다운로드
    $ docker pull pinpointdocker/pinpoint-agent:2.3.3
    

배포가 진행되면 Pinpoint Agent를 도커 컨테이너로 띄우고 호스트의 볼륨과 공유하도록 했습니다.

Pinpoint Agent 컨테이너는 파일을 생성한 후 프로세스로 계속 동작할 필요가 없었기에 자동으로 종료 되었습니다.

애플리케이션 또한 Pinpoint Agent 파일이 저장된 호스트 볼륨을 공유하였고 JVM javaagent 옵션으로 Pinpoint Agent jar 파일 $AGENT_PATH/pinpoint-bootstrap-$VERSION.jar을 설정해 주었습니다.
JVM 인수를 지정하는 방법은 JAVA_TOOL_OPTIONS를 이용해 외부에서 동적으로 환경변수로 지정해주었습니다.

실제 선언된 docker-compose.yml는 아래와 같습니다.

# docker-compose.yml

version: "3.8"
services:   
  application:
    - JAVA_TOOL_OPTIONS=${JAVA_TOOL_OPTIONS}
    ...
  volumes:
    - ./pinpoint/profiles:/pinpoint-agent/profiles:rw
    - pinpoint-volumes-2.3.3:/pinpoint-agent
    ...
  depends_on:
    - pinpoint-agent
    ...
  pinpoint-agent:
    image: pinpointdocker/pinpoint-agent:2.3.3
    volumes:
      - pinpoint-volumes-2.3.3:/pinpoint-agent
    ...
  
  volumes:
    pinpoint-volumes-2.3.3:
  • JAVA_TOOL_OPTIONS의 환경 변수 값으로는 Pinpoint Agent 실행을 위해 필요한 설정들이 들어가게 됩니다.
    -javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar 
    -Dpinpoint.applicationName=  
    -Dpinpoint.agentId=
    -Dpinpoint.profiler.profiles.active=
    
  • 테스트 환경마다 Pinpoint 서버도 달랐기에 환경 변수 -Dpinpoint.profiler.profiles.active= 옵션에 따라 Pinpoint 서버를 구별해 주었습니다.

  • 애플리케이션이 Pinpoint Agent 파일을 조회하기 위해 Pinpoint Agent 컨테이너가 먼저 동작할 수 있도록 depends_on 옵션으로 의존성을 추가 하게 되었습니다.

  • 호스트의 볼륨으로는 도커에서 관리하는 도커 볼륨을 사용하여 Pinpoint Agent 파일을 공유하도록 했습니다.

Pinpoint 도입 후기

Pinpoint를 도입한 후 Pinpoint Web을 통해서 Server Map, Call Stack, Inspector 정보 등을 확인할 수 있었습니다.

  • Server Map을 통해서는 서버 간의 상호 관계를 한눈에 파악할 수 있었습니다.
    주문 서비스의 서버 맵의 예시 [주문 서비스의 Server Map 예시]

  • Call Stack으로는 코드 수준의 정보를 확인할 수 있어서 병목 지점이나 장애 발생 구간을 확인할 수 있었습니다.
    주문 서비스의 특정 API의 호출 계층 예시 [주문 서비스의 Call Stack 예시]

  • Inspector를 통해서는 CPU 사용량, 메모리 사용량, 스레드 개수 등 서버의 실시간 운영 환경 정보를 확인할 수 있었습니다.
    주문 서비스의 특정 시점의 서버 현황 [주문 서비스의 Inspector 예시]

Pinpoint를 활용한 사례

Pinpoint를 도입 후 활용했던 사례를 소개하고자 합니다.

트렌비에서는 구매한 상품의 리뷰를 작성할 수 있고 다른 사람이 작성한 리뷰를 확인할 수 있습니다.

이 리뷰 API에서 병목이 심하게 발생하였고 느린 응답시간 때문에 트래픽이 몰리게 되면 오류가 발생하기도 하였습니다.

Pinpoint 도입으로 리뷰 API에서 병목이 발생하는 구간을 쉽게 파악할 수 있었고 수정을 통해 성능을 개선할 수 있었습니다.

Pinpoint를 활용한 병목 구간 확인

리뷰 API를 개선하기 전의 요청/응답 차트의 모습입니다.

평균 응답 시간이 2초 정도로 다른 API에 비해 상대적으로 느린 응답 시간을 가지는 것을 확인할 수 있었습니다.

느린_서비스_모니터링

아래의 Call Stack을 통해서는 모든 트랜잭션에 대한 코드 수준의 정보를 볼 수 있어서 구체적인 병목 구간과 오류 발생지점을 확인할 수 있었습니다.

리뷰 API는 외부 서비스의 호출이 N번 반복 되고 있다는 것을 파악할 수 있었고 이에 대한 개선을 진행하였습니다.
리뷰_지연_1
리뷰_지연_2

외부 서비스를 1번만 호출하도록 개선을 한 후에는 수치를 통해서 개선된 정도를 확인할 수 있었습니다.
지연_쿼리 개선
지연_쿼리 개선

마치며

서비스를 출시하고 관리하는 데 있어서 모든 기능에 대해 완벽한 동작을 보장하기는 어렵습니다.

그렇기 때문에 모니터링을 통해 문제점을 발견하고 해결해 나가는 과정이 중요합니다.

이런 부분에서 Pinpoint와 같은 모니터링 도구는 문제점을 쉽게 찾을 수 있도록 도와주고 해결의 실마리를 제공해 줄 수 있습니다.

앞으로도 Pinpoint를 통해 서비스 운영 시 장애 상황에서 문제의 원인을 빠르게 파악하고 서비스의 품질을 높이는 포인트를 찾는 데 많은 도움이 될 수 있을 것으로 생각됩니다.