공부하다보면 트래픽 대응이 어느 정도 패턴화 되어있다는 생각이 든다. 내용을 정리도 할 겸, 이와 관련된 고민을 하는 누군가에게 도움이 되었으면 해서 글을 작성해본다.
정답이 아니며, 어떤 문제들이 발생하며 비상 사태가 발생했을 때 평소 어떤 부분에 관심을 가져야 문제 해결을 빠르게 할 수 있을지 힌트가 되었으면 한다.
3-tier architecture를 배경으로 가정하고 글을 작성하였다.
트래픽이라고 묶어서 호칭하지만, 서비스에 가해지는 부하는 읽기/쓰기에 따라 해결책이 나뉘어 진다.
문제를 인지할 수 있어야 하고, 이를 위한 모니터링 환경이 필수로 준비되어 있어야 한다.
모니터링을 토대로 서비스의 병목 지점을 찾아야 한다.
읽기 부하 해소하기
서버 스펙을 어떻게 구성했냐에 따라 다르겠지만, 소규모 서비스에서도 마주할 수 있는 읽기 부하 문제는 데이터베이스에서 발생하는 문제였다.
쿼리 튜닝
별도의 인프라나 구조 변경 없이 시도할 수 있는 해결책으로는 쿼리 튜닝이 있다.
쿼리 튜닝은 데이터베이스 쿼리의 효율성을 높여 응답 속도를 개선하고 시스템 부하를 줄일 수 있는 효과적인 방법이다.
이를 위해 인덱스를 점검하고, 서비스 쿼리에 적합한 인덱스가 존재하는지, 실제 쿼리 실행 시 해당 인덱스가 제대로 활용되고 있는지를 확인해야 한다.
적절한 인덱스만으로도 쿼리 속도와 조인 성능을 크게 개선할 수 있으며, 잠금 경합을 줄여 데이터베이스의 동시성 문제를 완화할 수 있다.
캐시(cache)
캐시는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 이를 활용해 읽기 부하를 완화하는 접근도 가능하다.
A라는 요청에 대한 응답을 보내기 위해 10초의 연산 과정을 거쳐 응답을 만들어 반환해야 된다고 가정해보자. 특정 input에 대해 동일한 output을 반환하고, 특정 input이 반복되는 경우, 반복마다 매번 10초간의 연산 작업을 수행하는 것은 매우 비효율적이다. 그래서 이 연산 결과를 저장해두고, 해시맵에 접근하듯 꺼내어 사용하면 응답 시간 10초와 연산을 위한 컴퓨팅 자원을 아낄 수 있다.
이를 저장하는 공간을 캐시, 저장하는 행위를 캐싱이라 부른다.
여기서 발생할 수 있는 문제는, 중간에 연산 결과가 바뀌어야 하는 경우이다. 그래서 이를 막기 위해 적절한 TTL(Time To Live) 시간을 설정해 캐시가 일정 시간 유지 후 만료되고 다시 계산할 수 있도록 해야한다.
한 마디로 캐시에 저장된 결과를 사용함으로써 작업 과정을 생략할 수 있다.
데이터베이스 혹은 다른 외부 인프라에 접근하여 얻은 결과를 저장하여 사용할 수도 있다. 데이터베이스 접근 횟수가 줄어들면 자연스레 부하가 줄어들게 된다.
비동기 처리
작업이 오래 걸리는 부분에 대해 비동기 작업으로 돌리고, 요청 처리 스레드는 먼저 완료하는 방식도 있다.
단, 이 해결 방식은 프로세스가 바뀌어야 하는 단점이 있다. 작업이 오래걸리는 부분에 대해 비동기 처리하고, 응답을 먼저 돌려주는 형태이기에, 즉각적으로 내가 실행한 요청의 작업 상태에 대해선 알 수 없다. 단지 내 요청이 정상적으로 전달되었는가에 대해서만 응답을 받는다.