주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 - 2장 느려진 서비스, 어디부터 봐야 할까
이 장에서는 백엔드의 핵심인 성능이나 병목 등 문제 해결을 하기 이전에 그 기준이 되는 값을 측정하는 내용을 다룬다. 각 요소의 어떤 값을 기준으로 측정할지 알려주면서 서버의 전체 구조를 포함해서 설명한다.
처리량과 응답 시간
앱을 실행했을 때 로딩이 길어지면 성능이 나쁘다고 말한다. 너무 오래 걸리면 심지어 타임아웃이 발생하기도 한다. 실제로 성능에 관한 다양한 지표는 여러가지가 있다.
- 네트워크 속도
 - 디스크 I/O 속도
 - 메모리 크기
 - 디바이스의 CPU 속도
 - 응답 시간과 처리량
 
응답 시간(Response Time)
응답 시간은 사용자의 요청을 처리하는 데 걸리는 시간이다.
클라이언트가 서버로 요청을 보내는 과정은 서버에 연결 -> 데이터 전송이다. 그런데 응답 데이터가 큰 경우(e.g. 파일 다운로드) 첫 바이트와 마지막 바이트의 도착 시간이 차이가 클 수 있으므로 TTFB, TTLB같은 측정 기준도 있다.
응답 시간은 중요하다. 검색 지연 시간이 길어질수록 사용자당 검색 횟수가 줄어드는 경향이 확인되었다.
응답 시간의 구성은 다음과 같다.
- 로직 수행
 - DB 연동 -> 느림
 - 외부 API 연동 -> 느림
 - 응답 데이터 생성(전송)
 
보통 API 호출에서 응답 시간의 대부분을 차지하는 부분은 외부 연동과 DB 연동이다. 따라서 응답 시간을 줄이려면 이 두 가지에 유념해야한다.
처리량(Throughput)
처리량은 단위 시간당 시스템이 처리하는 작업량이다. 측정 단위는 주로 TPS(Transaction Per Second)나 RPS(Request Per Second)이다. 특정 시점(초 단위)의 동시 요청 수가 7개인데 최대 TPS가 5인 경우에는 초과한 요청 2개를 나중에 처리한다.
처리량의 개선방법은 두 가지이다.
- 서버가 동시에 처리할 수 있는 요청 수를 늘려 대기 시간 줄이기
 - 처리 시간 자체를 줄여 대기 시간 줄이기
 
TPS를 확인하는 가장 간단한 방법은 모니터링 시스템을 활용하는 것이다. 스카우터, 핀포인트, 뉴렐릭, 또는 데이터독 같은 유료 도구도 있다. 하지만 꼭 대시보드를 제공하는 도구가 아니더라도 애플리케이션에 미들웨어를 통해서 측정값을 기록할수도 있다. 예를 들면, 스프링부트에서 필터를 작성해서 TPS를 측정할 수 있다.
서버 성능 개선 기초
서비스 초기에는 성능 문제가 잘 발생하지 않지만, 사용자 수가 늘어나면 트래픽이 증가함에 따라 성능 문제가 발생하기 마련이다. 대표적인 증상은 다음과 같다.
- 순간적으로 모든 사용자 요청에 대한 응답 시간이 매우 느려진다. 이어서 커넥션 타임아웃이 빈번해진다.
 - 서버를 재시작하면 잠시 괜찮다가 다시 응답 시간이 느려진다.
 - 트래픽이 줄어들 때까지 심각한 상황이 계속된다.
 
이 문제의 주된 원인은 수용가능한 최대 TPS를 넘어서 트래픽이 유입되기 때문이다. 가장 직접적인 방법은 최대 TPS를 높이는 것이다. 하지만 대부분의 성능 문제는 DB나 다른 API와 연동할 때 발생한다. 따라서 이 부분을 비동기로 끊어내거나 동시성을 활용하여 직접적으로 성능개선을 해보면 효과적이다.
수직 확장(Scale-up)과 수평 확장(Scale-out)
성능을 개선하기 위해서 가장 먼저 떠올릴 수 있는 방법이 서버의 스펙을 업그레이드하는 것이다. 하지만 슈퍼컴퓨터가 아닌 이상 하나의 컴퓨터(서버)로 늘어나는 트래픽을 감당해내기는 어렵다. 따라서 수평 확장으로 컴퓨터를 여러 대로 늘리면 대응이 가능하다. (사실, 슈퍼컴퓨터라도 네트워크, DB 등의 성능도 다 따라서 맞추어 주어야하므로 쉽지않다.)
서버를 두 대 이상으로 늘리게 되면 로드 밸런서(Load Balancer, LB)가 필요하다. 참고로, AWS에서는 네트워크 레벨의 NLB도 있고, 애플리케이션 레벨의 ALB도 있다.
이때 주의할 점은 수직 또는 수평 확장으로 성능의 이점을 볼 수 있는게 맞는지 확실히 해야한다는 것이다. 외부 API 성능이 느리거나 DB가 느린 경우에는 이런식의 수평 확장은 전혀 도움이 되지않는다. 따라서 정확히 맥을 짚어서 문제가 되는 지점을 파악한 다음에 그 부분을 대상으로 성능개선을 해야한다.
DB 커넥션 풀
DB의 사용 단계는 다음과 같다.
- DB에 연결한다. -> 느림
 - 쿼리를 실행한다.
 - 사용이 끝나면 연결을 종료한다. -> 느림
 
네트워크에서 DB를 연결하고 종료하는 시간은 전체 응답 시간에 영향을 준다. 응답 시간이 길어지면 전체 처리량은 떨어진다.
이 문제를 해결하기 위해서 DB 커넥션 풀을 사용한다. DB에 연결된 커넥션을 미리 생성해서 보관하고, 애플리케이션은 DB 작업 시 풀에서 커넥션을 가져와 사용하고, 끝나면 다시 풀에 반환한다.
커넥션 풀의 중요한 설정은 다음과 같다.
- 커넥션 풀 크기
 - 커넥션 대기 시간
 - 커넥션 유지 시간