Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

인터파크 0.002% Spike 테스트 보고서 #144

Closed
junha-ahn opened this issue Nov 19, 2023 · 2 comments
Closed

인터파크 0.002% Spike 테스트 보고서 #144

junha-ahn opened this issue Nov 19, 2023 · 2 comments
Labels
documentation Improvements or additions to documentation performanceTest

Comments

@junha-ahn
Copy link
Member

junha-ahn commented Nov 19, 2023

Description

인터파크 기준 0.002% Spike 테스트 보고서

  0.002% 인터파크 기준
User per minute 500 20만
Request per minute 6,000 300만

테스트 요약

  1. Thread Pool 전략 수정으로 쓰레드 생성에 따른 CPU 리소스 사용 개선
  2. DB Connection Pool 전략 수정으로 Pending Connection 개선
  3. Redis 캐싱 적용으로 Latency 개선

시나리오

  1. 이벤트 페이지 조회 (GET /events?sort=id,asc&size=20&page=0)
    • 총 13번 조회한다.
    • 매 반복마다 page += randomInt(1, 10)
  2. 이벤트 상세 조회 (GET /event/{ID})
    • 이때 사용하는 EventID는 미리 정해진 ID이다. (대다수의 유저가 예약에 성공할 수 있는 max_attendees 를 가진 이벤트를 사용)
  3. 대기열 티켓 생성 (POST /ticket)
  4. 대기열 티켓 조회 (GET /ticket/{eventId}/{userId})
    • 대기열에 입장할때까지 계속 반복 조회
  5. 예약 (POST /reservations)

Enviroment

NodeGroup  NodeType Running Pods
Ingress [t3.small] Nginx Ingress 팟 1대
Backend [t3.small, t3.small, t2.small, t2.small] 백엔드 1대 (기타 모니터링 등)
테이블명  데이터 수
User 100만
Event 1,000만

Thresholds

thresholds: {
  http_req_failed: ['rate<0.01'], // http errors should be less than 1%
  http_req_duration: ['p(95)<300'], // 95% of requests should be below 300ms
}

100ms는 connection time으로 가정 (자세한 내용)

@junha-ahn junha-ahn added documentation Improvements or additions to documentation performanceTest labels Nov 19, 2023
@junha-ahn junha-ahn changed the title 인터파크 0.01% Spike 테스트 보고서 인터파크 0.005% Spike 테스트 보고서 Nov 19, 2023
@junha-ahn
Copy link
Member Author

junha-ahn commented Nov 19, 2023

VU 500 Test

성능 및 오류 원인 분석을 위해 조금 더 낮은 VU를 사용한다

  • Nginx 재시작
  • Backend 재시작

K6

image

Cluster

Backend Node의 CPU의 사용량이 두번에 걸쳐 뛰는걸 확인 가능하다

image

Spring

image

해당 패널은 f-lab-clone/ticketing-infra#84 을 통해 추가

thread 를 10개에서 200개까지 한 순간에 증가시키는데, 그래프상 첫번째 CPU 사용량 증가 이유로 추측된다.

두번째 CPU 증가포인트는 Request 처리로 예상한다.

# Thread Pool에서 사용할 최대 스레드 개수 
server.tomcat.threads.max: 200

# Thread Pool에서 최소한으로 유지할 Thread 개수
server.tomcat.threads.min-spare: 10

# 최대 Connection 개수 (동시에 몇개의 Connection이 처리될지는 threads.max에 따라...)
server.tomcat.max-connections: 8192

# max-connections 이상의 요청이 들어왔을 때 사용하는 요청 대기열 Queue의 사이즈 (이상의 요청은 거절한다)
server.tomcat.accept-count: ...

참고

현재 VU 1000명으로는 max-connections에 도달하지 못함으로 accept-count는 의미가 없다.

Thread 최소 개수 단순 증가 후 테스트

일단 테스트를 위해 단순 증가시켜본다.

테스트 환경

  • Thread 최소 개수: 10 => 200 (즉 Thread 생성 작업이 발생하지 않는다)
  • Test VU 500 동일
  • nginx, backend pod 재시작 완료

Cluster

2번에 걸쳐 튀던 CPU Usage 중 초반부분 (Thread 생성) 이 없어졌다.

image

Spring

image

Thread Pool 최적화 필요

Tomcat 스레드풀 최적화가 필요하다. 한마디로 적정 스레드 개수를 찾아야 한다.

  • 예를들어 Thread의 Max 개수가 증가하고, Thread를 생성하는데 CPU가 안정적으로 대응한다면 더 낮은 Latency를 제공할 수 있다.
  • 참고로 min-sparewarm-up등 으로 스레드를 강제로 생성시켜서 대응가능할 수 있으나, 일단 어느정도 증가시킬 필요가 있어보인다.

DB Connection Pool 변경

image

하나의 팟에서 보는 DB Connection

Pending Connection이 발생하므로, DB 부하가 발생하지 않는 선에서 Connection Pool 을 증가시켜 본다.

물런 CPU 사용률과는 직접적 연관 없는 문제지만 개선포인트라는 생각이 든다.

datasource:
  hikari:
    maximum-pool-size: 20 # 기존 10
    minimum-idle: 20 # 기존 0 

총 Pod 4대이므로, 80개의 Connection이 생성된다.

아래와 같은 이유로, DB 설정 등을 잘 살펴야 한다

HHH000342: Could not obtain connection to query metadatajava.sql.SQLNonTransientConnectionException: Too many connections
image
  • Pending Connection이 사라졌다.

@junha-ahn junha-ahn changed the title 인터파크 0.005% Spike 테스트 보고서 인터파크 0.002% Spike 테스트 보고서 Nov 19, 2023
@junha-ahn
Copy link
Member Author

junha-ahn commented Nov 19, 2023

Global Cache 적용 테스트 (Pod 4대)

캐시 적용에 따른 성능개선 확인을 위해 로직을 변경

  • 이벤트 페이지 조회 (GET /events?sort=id,asc&size=20&page=0)
  • 총 13번 조회한다.
  • 매 반복마다 page += 3 (> cache hit을 위해 랜덤 값에서 고정값으로 변경)

K6 (적용 이전)

image

K6 (캐시 적용 이후)

image

성능 변화가 없다.

1000 Virtual User가 동시에 요청을 하면서 Redis Cache 저장 이전에 모든 요청이 이루어지기 때문에 캐싱 활용이 안된 것으로 추정된다.

K6 (로직 수정)

모든 VU가 동시에 요청을 하는 것이 아니라 아래와 같이 Redis Data 저장을 기다릴 수 있도록 로직 수정

for (let i = 0; i < 13; i++) {
+    sleep(randomInt(0, 10))
     check(req.getEvents(query), {"Success Get Events": isSuccess});
     query.page = query.page + 3
}
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation performanceTest
Projects
None yet
Development

No branches or pull requests

1 participant