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

[3차 과제] 톰캣, 스프링 설정값, 성능 테스트 이론 공부 #164

Open
lreowy opened this issue Jan 24, 2025 · 0 comments
Open

Comments

@lreowy
Copy link
Member

lreowy commented Jan 24, 2025

서버 3차 과제 3번

🍰
  • 우리 서비스가 TPS 1000 이 된다 가정하고, 톰캣, 스프링 설정 값 고민해보기
    • 어떤 구간이 병목지점이 될지 고민하기
    • 스케일 아웃하는 서버 수 혹은 스케일 업을 어떤 스펙으로 등 어떻게 트래픽을 받아볼 수 있을지 고민하기
    • 톰캣 워커 쓰레드 수, db 커넥션 수에 대해 고민하기 (모른다면 리서치 수준이라도)

우리 서비스가 TPS 1000 이 된다 가정하고, 톰캣, 스프링 설정 값 고민해보기

어떤 구간이 병목지점이 될지 고민하기

→ 과제 4번 이슈의 지하철역 정보 리스트 조회 API를 TPS 1000으로 테스트 했을 때 트랜잭션 과정에서 병목 발생 (성능테스트 참고)

스케일 아웃하는 서버 수 혹은 스케일 업을 어떤 스펙으로 등 어떻게 트래픽을 받아볼 수 있을지 고민하기

  • 톰캣 워커 쓰레드 수, db 커넥션 수에 대해 고민하기
💡

Scale Up - 기존 서버의 성능을 향상시키는 방법

Scale Out - 서버의 수를 늘리는 방법

Scale Up

  • 스케일 업은 기존 서버의 하드웨어 성능을 향상시키는 방법
  • CPU의 성능 높이기, 메모리 용량 증가시키기 등
  • 구성이 비교적 간단하고 관리가 용이함
  • 하드웨어의 물리적 한계에 도달하면 성능을 향상시키기 어려움

Scale Out

  • 스케일 아웃은 서버의 수를 늘려 처리 능력을 증가시키는 방법
  • 로드 밸런서를 사용하여 여러 서버에 트래픽 분산시키기 등
  • 서버의 수를 유연하게 조정 가능 및 서비스 성장에 따라 확장성이 뛰어남
  • 서버 수 증가에 따라 네트워크 복잡도와 관리 비용이 증가한다는 단점 존재

→ 현재 휘피 서버는 AWS의 EC2 t2.micro 인스턴스 하나를 사용하고 있음

Scale Up 적용 시

  • 현재 인스턴스인 t2.micro에서 만약 TPS 1000이 주기적이고 짧은 시간 동안만 높은 성능이 요구된다면 t3.medium 혹은 t3.large 같은 인스턴스를 사용하면 됨
    • EC2의 t시리즈는 버스트 가능한 성능을 지니고 있어 짧은 시간동안 높은 성능을 처리하는데에는 문제가 없음
  • 그러나 고정된 성능이 요구되는 경우 m5 시리즈 인스턴스를 사용하는 것이 더욱 안정적임
    • EC2의 m5 시리즈는 균형 잡힌 성능을 가진 범용 인스턴스이기 때문에 t시리즈에 비해 지속적으로 안정적인 성능을 제공할 수 있음

Scale Out 적용 시

  • 로드 밸런서를 사용하여 여러 인스턴스에 트래픽을 분산시켜 각 서버가 적당한 부하만 처리하도록 설정
    • AWS의 ELB(Elastic Load Balancer)를 통해 로드밸런싱을 구현할 수 있음
  • Auto Scaling을 설정하여 트래픽이나 시스템 부하에 따라 자동으로 서버를 추가하거나 제거
    • TPS 1000이 평균적으로 발생 시 부하를 처리할 수 있도록 EC2 인스턴스를 자동으로 확장하고, 부하가 낮아지면 인스턴스를 줄이도록 함
💡

TPS - Transaction Per Second의 약자로, 1초 동안 발생하는 트랜잭션의 개수를 말함

동시에 여러 요청을 효율적으로 처리하기 위해서는 톰캣의 worker thread와 DB connection 수에 대해 고민을 해보아야 함

Tomcat

  • Spring boot 내장 Servlet 컨테이너 중 하나로, Java 기반의 WAS임
  • 자바의 스레드 풀 클래스와 매우 유사한 자체 스레드 풀 구현체를 가지고 있음
//application.yml

server:
  tomcat:
    threads:
      max: 200 # 생성할  있는 thread의  개수
      min-spare: 10 # 항상 활성화 되어있는(idle) thread의 개수
    accept-count: 100 # 작업 큐의 사이즈
    max-connections: 8192 # 수립 가능한 connection의  개수
    connection-timeout : 20000 # timeout 판단 기준 시간, 20
  • 그러나 자바의 스레드 풀과 비교 시 알아야 하는 점이 2가지 존재

    1. Max-Connections (큐로 구현)
      • 톰캣이 동시에 처리할 수 있는 최대 커넥션의 개수
      • 웹 요청 → Tomcat의 connectorconnection 생성 → 스레드 풀의 thread에 연결
      • 이때 동시에 연결해서 처리할 수 있는 커넥션의 개수가 MaxConnections
    2. Accept-Count
      • Max-Connections 이상의 요청이 들어왔을 때 사용하는 대기열 큐의 사이즈
      • Max-Connections와 Accept-Count 이상의 요청이 들어왔을 때 추가적으로 들어오는 요청은 거절될 수 있음
    • server.tomcat.threads.max : Thread Pool에서 사용할 최대 스레드 개수, 기본값은 200
    • server.tomcat.threads.min-spare : Thread Pool에서 최소한으로 유지할 Thread 개수, 기본값은 10
      • 기본 생성 시 min-spare 숫자로 스레드 풀을 생성하다가, 요청이 min-spare 스레드 숫자로 감당하기 어려워 요청이 밀리게 되면 max까지 스레드 수 증가 시킴
    • server.tomcat.max-connections : 동시에 처리할 수 있는 최대 Connection 개수, 기본값은 8192 (서버가 처리 가능한 동시 요청 처리 개수라고 볼 수 있음)
    • server.tomcat.accept-count : max-connections 이상의 요청이 들어왔을 때 사용하는 요청 대기열 큐의 사이즈, 기본값은 100
      • 너무 크게 설정 - 대기열이 커지면서 메모리 문제 유발 가능
      • 너무 작게 설정 - 요청이 몰릴 시 들어오는 요청들을 거절해버릴 수 있음
    • server.tomcat.connection-timeout : 클라이언트가 서버에 요청을 보내기 전까지 소켓 연결을 유지하는 최대 시간

    max-connections > max thread - 모든 연결이 즉시 처리되는 것은 아니라서 보통 max-connections 를 더 크게 해놓음

  • spring boot 3.2.7 (현재 사용 버전)의 내장 tomcat은 10.x 버전을 사용하는데, tomcat 8.x 버전 이상부터는 **Non-blocking I/O**를 지원함

  • **Non-blocking I/O**에서는 최대 Thread 개수 보다 적거나 같은 수의 connections를 설정하면 비효율적인 설정이 될 수 있음

    → NIO 기반의 Connector는 하나의 Connection이 하나의 스레드를 할당받는 BIO Connector에 비해 Selector를 활용해 Socket를 관리하므로 더 적은 스레드를 사용함 (Poller라는 별도의 스레드가 커넥션 처리)

DB Connection Pool

Hikari CP

  • connection pooling을 제공하는 JDBC DataSource의 구현체

  • 다른 connection pooling 보다 가장 빠름 (기술 최적화, 간결한 설계)

  • Connection Pool

    • connection - DB 연결 객체, DB로의 연결 기능을 제공함
      • 보통 Connection 하나 당 트랜잭션 하나를 관리함
    • 미래에 데이터베이스 요청이 올 때 다시 사용되는 데이터베이스 커넥션 캐시
    • 커넥션 풀 관리가 중요한 이유는 커넥션을 맺는 과정이 상당히 복잡하고 자원을 많이 사용하기 때문
    • Hikari는 미리 connection을 pool에 담아두고, 요청이 들어오면 thread가 pool을 요청하고 Hikari는 connection을 제공함
    • 이 과정에서 이전에 사용했던 connection이 존재하는지 확인하고 이를 우선적으로 반환하는 특징이 있음
  • Spring boot 2.0 버전부터 Hikari를 사용해 spring-boot-starter-data-jpa, spring-boot-starter-jdbc에 의존성이 포함되어 있음

  • Hikari CP wiki의 DeadLock을 피하기 위한 풀 크기 계산 공식은 다음과 같음

    $$ PoolSize = Tn * (Cm - 1) + 1 $$

    • Tn = 최대 스레드 수, Cm = 단일 스레드가 보유하는 최대 동시 연결 수
    • 반드시 최적의 풀 크기라고 할 수는 없지만 교착 상태를 피하기 위해 필요한 최소한의 크기
    • 이 공식을 기반으로 조절하면 더 나은 방향으로 조절 가능
@sjk4618 sjk4618 changed the title [3차 과제] 우리 서비스가 TPS 1000 이 된다 가정하고, 톰캣, 스프링 설정 값 고민해보기 [3차 과제] 톰캣, 스프링 설정값, 성능 테스트 이론 공부 Jan 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant