본문 바로가기
Dev/[넘블] 2023 백엔드 챌린지

[Numble] Spring으로 타임딜 서버 구축 - 트러블 슈팅과 회고 4 (핀포인트, nGrinder)

by javapp 자바앱 2023. 4. 17.
728x90

 

 

10. Pinpoint 설치


약 8시간 삽질

pinpoint는 대규모 분산 시스템에서의 성능 모니터링과 분석을 위한 도구로, 다양한 기능과 통계 정보를 제공합니다.

 

10.1. 핀포인트 설치

pinpoint-apm/pinpoint-docker: Official Dockerized components of the Pinpoint (github.com)

깃허브에 설치하는 방법이 나와있다.

java 와 도커가 설치돼있기 때문에 docker-compose를 통해 설치할 것입니다.

 

설치전 현재 아키텍처에 대해 보여주자면

젠킨스를 통해 배포 서버를 원격으로 배포중이기 때문에 

*(중요)배포 서버에 root 가 아닌 배포 사용자로 접속후 설치 진행해야됨 (이것때매 삽질,, 나중에 agent가 jar파일을 root로 설치되면 인식하지를 못함)

우선 서버 계정으로 로그인

$ su - timedeal

 

핀포인트 설치 진행

$ git clone https://github.com/pinpoint-apm/pinpoint-docker.git
$ cd pinpoint-docker

 

pinpoint-agent와 pinpoint-quickstart 부분을 제거한다.

$ vi docker-compose.yml

 

docker-compose 다운로드

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

실행권한

$ sudo chmod +x /usr/local/bin/docker-compose

설치확인

$ docker-compose --version

 

docker compose 실행

$ docker-compose pull && docker-compose up -d

 

핀포인트 관련 프로그램들이 도커 컨테이너에서 실행 중

특히 pinpoint-web을 통해서 사이트에 접속할 수 있음

현재 port가 8080으로 설정되어 있고 접속하기 위해 해당 포트를 열어주면 됨

http://공인IP:8080

 

애플리케이션 목록은 아직 보이지 않을 것이다.

 

 

 

10.2. Pinpoint Agent를 NaverCloud Server 에 설치

현재 배포서버에 pinpoint가 설치되어 있는 상태,

젠킨스 서버에서 배포서버에 timedeal 계정으로 무중단 배포를 하고 있는 상태

# agent 설치
$ wget https://github.com/pinpoint-apm/pinpoint/releases/download/v2.5.0/pinpoint-agent-2.5.0.tar.gz

# 압축 해제
$ tar xvzf pinpoint-agent-2.5.0.tar.gz

# 이동
$ cd pinpoint-agent-2.5.0

 

여기서 중요한데 127.0.0.1을 공인IP로 바꿔주어야 해당 인스턴스에서 실행되는 서버(서비스)들이 핀포인트에 인식된다.

# config 파일 수정
$ sudo vi pinpoint-root.config

# 127.0.0.1 로 되어있을 텐데, 공인IP 수정해줍니다.
profiler.transport.grpc.collector.ip=공인IP

 

dockerfile 작성

spring boot 와 함께 agent도 같이 실행되도록 하는 게 포인트

FROM adoptopenjdk/openjdk11
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["nohup","java","-jar",\
"-javaagent:./pinpoint/pinpoint-bootstrap-2.5.0.jar",\
"-Dpinpoint.agentId=gjgs01","-Dpinpoint.applicationName=gjgs",\
"-Dpinpoint.config=./pinpoint/pinpoint-root.config"\
,"-Dspring.profiles.active=prod","app.jar","2>&1","&"]

-Dpinpoint.agentId=gjgs01","-Dpinpoint.applicationName=gjgs

agentId, applicationName 은 서로다르게 자유롭게 설정 가능

 

 

chmod +x gradlew
./gradlew clean build -x test
docker build -t llsrrll96/timedeal:timedeal-0.0.1-SNAPSHOT .
docker push llsrrll96/timedeal:timedeal-0.0.1-SNAPSHOT

$ docker run -d --name timedeal -p 8011:8011 -v /home/timedeal/pinpoint-agent-2.5.0:/pinpoint llsrrll96/timedeal:timedeal-0.0.1-SNAPSHOT

 

도커로 실행 확인

 

서버 상태 확인 가능 ㅠㅠ

 


 

$ docker-compose up --force-recreate -d

핀포인트가 터져서 모니터링이 안됐었다.

그래서 docker-compose로 핀포인트를 설치했었기 때문에 강제로 다시 생성

 

 

 

 

11. nGrinder 테스트


구매에 대해 테스트를 해보았습니다

 

서버 사양 

[Standard] 2vCPU, 8GB Mem, 50GB Disk [g2]

 

optimistic Lock 일 경우 에러가 많이 발생하기 때문이기도 하고

확실히 구매에서는 동시성 문제가 발생하는 구간임을 알 수 있기 때문에 비관적인 락을 사용하여

동시성 처리를 하겠습니다.

 

 

구매 테스트

- 1만개의 재고가 있다고 가정

- 비관적 락을 걸어 동시성 처리

- 1만번의 테스트 설정

 

Vuser : 500

TPS : 184.4

 

핀포인트

Active Request

Fast: 대부분 1초 이하에 요청이 처리되고 CPU사용도 여유가 있는 모습

 

Full GC가 너무 자주 발생하거나 실행시간(Stop-The-World)이 긴 경우는 튜닝이 필요하다는 것을 판단할 수 있습니다.

 

 

 

Vuser : 1000 (이전보다 2배로 늘려보았습니다.)

TPS : 127.4

Error 도 발생하기 시작

 

핀포인트

 

실패한 부분이 있었고 추적결과 약 30초간 기다렸다가 실패한 것으로 보인다.

수강신청이나 예약사이트에 보면 기다리는 시간이 30초보다는 길게 잡히던데 그것처럼 길게 잡아놓으면

자신의 차례가 와서 요청이 처리되지 않을까,,

 

커넥션 에러 줄이기

    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      connection-timeout: 300000
      idle-timeout: 600000
      validation-timeout: 5000
server:
  tomcat:
    threads:
      max: 100
더보기

Spring Boot에서 HikariCP 커넥션 풀을 사용할 때, 커넥션 풀과 데이터베이스 연결 시간 초과 설정을 하는 방법입니다.

  • maximum-pool-size: 커넥션 풀에서 사용할 수 있는 최대 커넥션 수를 설정합니다. 이 값을 적절하게 조절하여, 커넥션 수를 최적화할 수 있습니다.
  • minimum-idle: 유지할 최소한의 유휴 커넥션 수를 설정합니다. 이 값은 커넥션 수를 최적화하는 데 중요한 역할을 합니다.
  • connection-timeout: 커넥션을 얻을 때까지 대기할 최대 시간(밀리초 단위)을 설정합니다. 이 값이 작으면 커넥션을 얻는 데 걸리는 시간이 짧아지지만, 대기하는 클라이언트 수가 증가할 수 있습니다. 따라서 이 값을 적절히 조절하여 최적의 성능을 얻을 수 있도록 해야 합니다.pool에서 커넥션을 얻어오기전까지 기다리는 최대 시간, 허용가능한 wait time을 초과하면 SQLException을 던짐
    설정가능한 가장 작은 시간은 250ms (default: 30000 (30s))
  • idle-timeout: 유휴 커넥션이 폐기되기까지 대기할 최대 시간(밀리초 단위)을 설정합니다. 이 값은 너무 짧으면 커넥션을 자주 만들어야 하므로 성능에 악영향을 미칠 수 있습니다. 반면, 너무 길면 유휴 커넥션을 재사용하는 데 부담을 줄 수 있습니다. 이 값을 적절히 조절하여 최적의 성능을 얻을 수 있도록 해야 합니다.
  • validation-timeout: 데이터베이스 연결 유효성을 검사하는 데 사용되는 최대 대기 시간(밀리초 단위)을 설정합니다. 이 값이 초과되면 연결 시간 초과 예외가 발생합니다. 이 값을 적절히 조절하여 최적의 성능과 안정성을 얻을 수 있도록 해야 합니다.

그래서 connection-timeout을 대폭 늘렸다.

threads-max 값을 줄여서 컨텍스트 스위칭 시간을 줄여보았다.

 

결과

TPS: 134.4 

다행히 timeout에 대한 에러는 나지않았다.

TPS도 미약하게 증가한 모습이다.

 

 

쓰레드 max를 200으로 다시 올렸다.

TPS: 160.5으로 올랐다.

 

 

쓰레드 max를 300으로 다시 올렸다.

TPS가 120으로 나왔는데, 

쓰레드 간 경합으로 쓰레드 최대값을 늘리면 쓰레드 간 경합이 발생할 가능성이 높아지고 여러 쓰레드가 같은 자원에 접근하면 경합이 발생하여 cpu 느리게 처리되는 것 같다.

 

 

 

 

참고:

블로그1

Spring - Pinpoint 적용하기 | Backtony

댓글