본문 바로가기
BE 📙/주니어백엔드개발자가반드시알아야할실무지식

[CH02] 느려진 서비스, 어디서부터 봐야 할까

by 경아ㅏ 2025. 5. 20.

 

처리량과 응답시간

 

서버 성능과 관련된 중요한 지표 2가지: 응답시간, 처리량

 

 

응답 시간

 

1) 앱에서 API 서버로 요청

- 서버 연결

- 서버로 데이터 전송

2) API 서버 실행
- SQL 실행

- 응답 생성

 

3) 클라이언트로 데이터 전송

- JSON 응답

 

 

응답 시간의 측정

 

  • TTFB (TIme To First Byte): 응답 데이터 중 첫번째 바이트가 도착할 때까지 걸린 시간
  • TTLB (Time To Last Byte): 응답 데이터 중 마지막 바이트가 도착할 때까지 걸린 시간
  • 응답시간은 보통 1초보다 짧고 ms(밀리초 - 1/1000초) 단위를 사용하여 측정

 

서버 처리 시간에서 확인할 것

 

  • 로직 수행 (it, for문)
  • DB 연동 (SQL 실행)
  • 외부 API 연동
  • 응답 데이터 생성 (전송)

네 가지 요소 중에서 DB 연동, 외부 API 연동 비중이 크므로 먼저 살펴 볼 것

 

 

처리량

 

단위시간 당 시스템이 처리하는 작업량

 

  • TPS(초 당 트랜잭션)
  • RPS (초 당 요청수)

 

동시에 들어오는 요청 수가 최대 TPS 초과 시 다른 요청은 대기한 후 처리하게 되어 응답 시간이 증가
서버의 동시에 처리할 수 있는 요청량을 증가 시키거나 vs 요청의 처리 시간을 단축시켜 성능 개선

 

 

 

서버 성능 개선 기초

 

병목 지점

 

서버 성능 문제가 있을 때 관찰 가능한 점

 

  • 모든 사용자 요청에 대한 응답 시간이 느려지면서 시간초과 발생
  • 서버를 재시작하면 괜찮아졌다가 다시 동일한 현상 발생
  • 트래픽이 줄어들 때까지 느려지는 현상 지속
  • (시스템이 수용할 수 있는 최대 TPS 를 초과한 트래픽이 유입되어 문제가 발생하는 것이므로 서버가 감당 가능한 TPS를 증가시키거나 처리 시간 단축 필요)
  • (DB, API 연동 지점을 살펴보기)

 

수직 확장과 수평 확장

 

수직 확장

- CPU, 메모리, 디스크 등의 자원을 증가/개선

- 서버, DB 등의 메모리 크기를 늘리기만 해도 TPS 를 증가 가능

수평 확장

- 서버 수를 늘리고 + 로드밸런서 활용

- (DB 성능에 문제가 있는데 서버를 수평확장하는 것은 오히려 마이너스, 외부 API 성능이 문제인데 수평 확장하는 것은 효과가 없음)

 

DB 커넥션 풀

 

서버에서 DB를 사용할 때 거치는 3단계

- DB 연결

- 쿼리 실행

- 연결 종료

DB 연결/종료 시간은 전체 응답 시간에 영향을 주기 때문에 DB 커넥션 풀 사용 + 다음 사항들의 설정 필요

- 커넥션 풀 크기 (최소, 최대 크기)

- 풀에 커넥션이 없을 때 대기 시간

- 커넥션 유지시간 (최대, 최소 유휴시간)


커넥션 풀 크기

 

커넥션 풀을 늘리면?

- 커넥션 풀 크기가 5이고, 한 요청 쿼리 실행 시간이 0.5초 일 때: 50개의 요청을 처리하려면 5초 필요
- 커넥션 풀을 50으로 늘이면: 50개의 요청을 처리하는데 0.5초 필요

 

DB 서버의 CPU 사용률이 높을 경우 커넥션 풀 크기를 키우는 것은 주의 필요

 

 

커넥션 대기 시간

 

커넥션 대기 시간은 0.5초 - 3초 이내로 짧게 설정하자

 

커넥션 풀 크기 10개 / 한 요청당 수행시간 10초 / 커넥션 대기시간 30초 / 전체 요청 30개 / 5초 후...

- 요청 10개 -> 쿼리 5초간 실행 중
- 요청 20개 -> 5초간 대기 중

- 대기 하던 사용자들 10명이 재요청 했다면 -> 대기 시작

- 커넥션 대기시간이 30초이기 때문에 30개이던 요청이 -> 40개로

커넥션 대기 시간을 1초로 변경하면

- 요청 10개 -> 쿼리 실행

- 요청 20개 -> 1초 후 오류 응답

- 대기 시간을 1초로 변경하면 안정적으로 서버 운영 가능

 

최대 유휴 시간, 유효성 검사, 최대 유지 시간

 

최대 유휴 시간

- 사용되지 않는 커넥션을 풀에 유지할 수 있는 최대 시간

 

유효성 검사 지원

- 커넥션이 정상적으로 사용할 수 있는 상태인지 여부를 확인하는 절차

 

최대 유지 시간

- 커넥션이 생성된 시점 부터의 유지 시간

 

 

서버 캐시

 

(키, 값)을 저장하는 Map 형태의 데이터 저장소

동일한 데이터를 요청할 때 DB가 아닌 캐시에서 읽어와 응답 시간 단축
DB 서버를 확장하지 않고 응답 시간과 처리량 개선 가능

 


적중률과 삭제 규칙

 

적중률

- 캐시에 존재한 건수/캐시에서 조회를 시도한 건수

 

적중률이 높을 수록 좋은 것은 맞지만, 그렇다고 모든 데이터를 캐시에 저장해놓기 어렵기 때문에 삭제 규칙 필요(메모리 이슈)
- LRU, LFU, FIFO

- 일반적으로 캐시 유효 시간(만료 시간)을 지정하여 해당 시간이 지정하면 자동으로 데이터 제거


로컬 캐시와 리모트 캐시

 

로컬 캐시

 

  • 서버 프로세스와 동일한 메모리를 캐시 저장소로 사용
  • Caffeine(Java), go-cache(Go), node-cache(Node.js)
  • 장점: 서버 프로세스와 캐시가 동일한 공간에 있기 때문에 데이터에 빠르게 접근 가능 / 구조가 단순
  • 단점: 메모리 한계로 저장할 수 있는 데이터 크기에 제한이 존재, 프로세스가 재시작할 때마다 캐시 초기화

 

리모트 캐시

 

  • 별도 서버의 프로세스를 캐시 저장소로 사용
  • Redis
  • 장점: 캐시 자체도 수평 확장하면서 데이터 규모 확대 가능, 서버 프로세스가 재시작되어도 레디스 캐시 데이터는 유지
  • 단점: 로컬 캐시에 비해 구조가 복잡하고(별도의 장비, 프로세스 필요), 네트워크 통신이 필요하여 상대적으로 느림

배포 빈도가 높고 대규모 데이터를 사용한다면 리모트 캐시를 사용하자

 

 

캐시 무효화

 

- 변경에 민감한 데이터라면: 리모트 캐시에 저장하고, 데이터 원본이 변경될 때 캐시에 저장된 데이터도 변경/삭제가 필요

- 변경에 민감하지 않은 데이터라면: 캐시 유효시간을 설정하여 주기적으로 갱신(10분,,, 1분,,,)

 

가비지 컬렉터와 메모리 사용

 

가바지 컬렉터

- 자바, Go, 파이썬

- 힙 메모리 사용량이 일정 비율을 초과할 때 혹은 일정 주기에 따라 사용하지 않는 메모리를 찾아서 반환

- 가비지 컬렉터가 실행될 동안은 애플리케이션이 일시 중지 됨
- 메모리 사용량을 줄이면 탐색해야 하는 메모리가 줄어들고 가비지 컬렉터 수행 시간 단축 가능 (함부로 메모리를 줄여서는 안되지만...)

한번에 많은 메모리를 사용하지 않도록 제한

- 대량으로 객체가 생성되어 반환되는 것을 막기 위해 컨텐츠 등의 조회 범위를 제한

파일 다운로드 구현시 스트림 활용

- 대량의 파일 등을 다운로드 할 때 한번에 메모리에 로딩하는 방식 지양

- 스트림을 이용하여 일정 메모리 크기 만큼 끊어서 읽기


정적 자원과 브라우저 캐시

 

이미지, JS 파일을 매번 다운로드하면 트래픽(비용)이 매번 발생하므로 클라이언트 캐시에 응답 데이터를 일정 시간동안 저장

ex. 응답 헤더에 Cache-Control: max-age=60 와 같이 지정되어있으면 60초 이내에 요청시 로컬에 보관한 데이터를 그대로 사용

 

 

정적 자원과 CDN

 

CND(Content Delivery Network)

- 컨텐츠 전송 네트워크

- 컨텐츠 제공을 위한 별도의 네트워크

- 사용자는 CDN이 제공하는 URL을 통해 컨텐츠에 접근하고, 요청한 컨텐츠가 없으면 오리진 서버에서 읽어와 제공

- 오리진 서버에서 읽어온 컨텐츠는 캐시(엣지 서버)에 보관했다가 동일한 요청이 들어오면 에지 서버에서 응답

- 오리진 서버를 트래픽으로 부터 보호하고 가까운 엣지 서버로 부터 컨텐츠를 빠르게 제공 가능


대기 처리

 

전체 서비스 시간 중 짧은 시간에만 트래픽이 몰릴 때, 그 때만을 위해서 서버 성능을 높여놓는 것은 비효율적
대기열을 통해 서버가 수용할 수 있는 트래픽만 받아들이고 나머지는 대기 처리

서버를 증설하지 않고도 안정적으로 서비스 제공 / 무한 새로고침에 대한 방어 (새로고침시 대기가 뒤로 밀리게 되므로 ^^)

 

 

댓글