소개
대용량 서버를 구축하기 위해서는 어떤 것들을 알아야 할까?
- Spring, MySQL, MongoDB, Redis, Kafka, MSA….
- 서버 개발자의 핵심은 데이터다.
- 대용량 시스템이 어려운 이유는 결국 많은 양의 데이터에서 시작된다.
어떻게 많은 양의 데이터를 안정적으로 삽입, 갱신, 조회할까?
- MySQL - 정규화, 인덱스, 트랜잭션, 동시성 제어
- MySQL에서는 이 4가지 키워드가 핵심이 된다.
대용량 시스템에 대한 이해
웹의 기본 아키텍처
- 웹 서버는 HTML, CSS, JavaScript와 같은 정적인 데이터들을 주로 서빙한다.
- 웹 애플리케이션 서버는 데이터베이스에 저장된 데이터처럼 동적인 데이터들을 서빙한다.
웹 서버, 웹 애플리케이션 서버는 왜 나누어져 있을까?
- 태초에는 웹 서버만 있는 형태에서 웹의 복잡도가 증가함에 따라 바뀌게 되었다.
- 관심사의 분리 / 관측가능한 시스템 / 효율적인 리소스 사용
- 서비스가 잘 됨에 따라 클라이언트들은 무한정 늘어날 수 있다.
- 그렇다면 서버와 데이터베이스도 무한정으로 늘릴 수 있을까?
- 자원은 유한하기 때문에 한계가 있다. 특히 데이터베이스를 늘이는 일은 더욱 어려운 일이다.
- 때문에 대용량 시스템에서는 캐시나 비동기 큐 같은 것을 이용하게 된다.
왜 데이터베이스에서 병목이 일어날까?
우선 스케일 업(scale up)과 스케일 아웃(sacle out)에 대해서 알아보자.
- 스케일 업은 '수직 확장'이라고도 불린다.
- 스케일업은 기존의 하드웨어(일반적으로 서버)에 더 강력한 리소스를 추가하여 처리 능력을 향상하는 방법이다.
- 예를 들어, CPU 코어 수를 늘리거나, RAM 용량을 추가하거나, 디스크 저장 공간을 확장하는 것이 이에 해당한다.
- 이 방식은 하드웨어를 업그레이드하기 때문에 비용이 많이 들 수 있으며, 시스템의 최대 용량에 도달하면 더 이상 확장할 수 없는 한계가 있다.
- 스케일 아웃은 '수평 확장'이라고도 불린다.
- 스케일아웃은 기존 시스템과 유사한 새로운 하드웨어를 추가하여 시스템의 전체 처리 능력을 향상하는 방법이다.
- 즉, 여러 서버를 연결하여 하나의 대규모 시스템처럼 작동하게 하는 것이다.
- 스케일아웃은 더 높은 병렬 처리 능력을 제공하며, 일반적으로 효율적인 비용 관리와 더 높은 가용성을 제공한다.
- 그러나 이 방식은 복잡성이 증가하고, 데이터 일관성 및 관리에 대한 추가적인 고려 사항이 필요할 수 있다.
대용량 처리를 위해서는 스케일 아웃이 더 유리해 보인다.
서버에서 스케일 아웃은 항상 가능할까?
- 스케일 아웃을 해서 서버가 여러 대라도 클라이언트 입장에서는 하나의 서버처럼 동작해야 한다.
- 즉, 같은 입력에 대해서는 항상 같은 결과를 반환해야 한다.
- 그래서 여러 개의 서버는 하나의 데이터베이스를 바라보게 된다.
데이터베이스에서의 스케일 아웃은 어떨까?
- 스케일 아웃을 하기 위해서는 상태가 없어야 한다는 전제가 있다.
- 데이터베이스는 데이터라는 상태를 관리하고 있어 서버보다 스케일 아웃을 하기 위해서는 훨씬 많은 비용이 필요하다.
- 현대 서버 아키텍처는 상태관리를 데이터베이스에 위임하고, 서버는 상태관리를 하지 않는 방향으로 발전
- 이로 인해 서버는 자유롭게 스케일 아웃을 할 수 있는 구조가 된다.
- 하지만 데이터베이스는 스케일 아웃을 하려면 많은 비용이 들게 된다.
- 스케일 아웃 이외에도 데이터베이스는 디스크의 데이터를 접근해서 가져온다.
- 이는 메모리를 사용하는 것에 비해 당연히 느릴 수밖에 없다.
대용량 시스템 아키텍처 맛보기
대용량 트래픽 / 데이터 처리는 왜 어려울까?
- 하나의 서버 또는 데이터베이스로 감당하기 힘든 부하 때문이다.
- 다수의 서버와 데이터베이스를 마치 하나인 것처럼 동작하게 하기 위해 다양한 기법이나 최적화 방법들이 쓰인다.
- 웹 서비스들은 대부분 24시간 무중단이라는 특성을 가지고 있다.
- 잘못된 코드 한 줄이 미치는 영향의 범위가 트래픽에 따라 엄청나게 커질 수 있다.
- 잘못된 코드 한 줄이 찰나의 순간에 수백만건의 데이터들을 오염시킬 수 있다..
- 여러 마이크로 서비스들이 복잡한 의존 관계를 가진다.
정리하면,
- 하나의 서버로 감당하기 힘들어 대부분 여러 개의 서버 또는 데이터베이스를 사용한다.
- 여러 개의 서버에서 유입되는 데이터의 일관성을 보장할 수 있어야 한다.
- 코드 한 줄이 데이터에 미치는 영향범위가 굉장히 크다.
- 여러 서비스들이 얽혀있어, 시스템 복잡도가 상당히 높다.
그렇다면 대용량 시스템은 어떤 조건을 갖추어야 할까?
고가용성 - 언제든 서비스를 이용할 수 있어야 한다.
확장성 - 시스템이 비대해짐에 따라 증가하는 데이터와 트래픽에 대응할 수 있어야 한다.
관측가능성 - 문제가 생겼을 때 빠르게 인지할 수 있어야 하고 문제의 범위를 최소화할 수 있어야 한다.
간단한 대용량 시스템 발전과정
첫 번째로 가장 기본이 되는 시스템이 있다.
➜ 여기서 클라이언트가 늘어남에 따라 서버의 응답속도가 느려지고 있다.
서버를 추가하고, 부하분산이 잘 될 수 있도록 Nginx와 같은 로드밸런스도 추가해 줬다.
→ 하지만 서비스가 더 커져서 데이터베이스에서 병목이 일어났다.
데이터베이스의 부하를 최소화할 수 있는 메모리 캐시를 사용하기로 한다. 캐시에 먼저 데이터를 질의하고 없으면 데이터베이스에게 질의한 다음 캐시에 갱신하는 방식이다.
서비스에서 이메일, 푸시, 알림 등의 대외기관과의 연동이 필요한 요구사항이 추가되어 대외기간의 응답속도가 느려지고 있다.
그래서 응답속도에 영향을 미치지 않도록 대외기관 통신을 카프카나 레빗엠큐와 같은 비동기 큐를 이용해 비동기로 변경한다.
결국 이런 시스템들이 모여 하나의 거대한 서비스로 발전하게 된다.
MySQL 소개
MySQL을 학습하는 이유
왜 MySQL일까?
관계형 데이터베이스는 아직까지도 가장 범용적으로 사용한다.
백엔드 개발자라면 아주 높은 확률로 관계형 데이터베이스를 실무에서 다루게 될 것이다.
MySQL이란
- 가장 인기 많은 오픈소스 관계형 데이터베이스 (git, doc)
- 높은 접근성과 낮은 비용
- 네이버, 카카오 토스등 대부분의 국내 IT 기업에서 가장 많이 사용됨
- SQL 안식 표준을 지키고 있음
MySQL 아키텍처
서버에서 요청한 SQL은 MySQL 엔진, 스토리지 엔진을 거쳐 운영체제를 통해 디스크에 접근하여 데이터를 서버에게 전달하게 된다. 여기서 MySQL 엔진은 사람으로 비유하면 판단과 명령을 내리는 두뇌, 스토리지 엔진은 동작을 수행하는 팔과 다리라고 생각하면 된다.
MySQL 엔진은 접속을 처리하는 커넥션 핸들러, 쿼리 파서, 전처리기, 옵티마이저, 쿼리 실행기 등의 구성요소가 존재한다.
- 쿼리 파서
- SQL을 파싱 하여 Syntax Tree를 만듦
- 이 과정에서 문법 오류 검사가 이루어짐
- 전처리기
- 쿼리 파서에서 만든 Tree를 바탕으로 전처리 시작
- 테이블이나 컬럼 존재 여부, 접근 권한 등 Semantic 오류 검사
쿼리 파서, 전처리기는 컴파일 과정과 매우 유사하다. 하지만 SQL은 프로그래밍 언어처럼 컴파일 타임 때 검증 할 수 없어 매번 구문 평가를 진행
- 옵티마이저
- 쿼리를 처리하기 위한 여러 방법들을 만들고, 각 방법들의 비용정보와 테이블의 통계정보를 이용해 비용을 산정
- 테이블 순서, 불필요한 조건 제거, 통계정보를 바탕으로 전략을 결정 (실행 계획 수립)
- 옵티마이저가 어떤 전략을 결정하느냐에 따라 성능이 많이 달라진다.
- 가끔씩 성능이 나쁜 판단을 해 개발자가 힌트를 사용해 도움을 줄 수 있다.
- 쿼리 실행기
- 옵티마이저가 결정한 계획대로 스토리지 엔진에 요청하는 역할을 한다.
- 이때 Handler API를 사용하는데, 핸들러 API는 MySQL 코드에서 주로 보이는 개념으로 이를 이용해 스토리지 엔진에 요청을 보내며 이 API를 충족하는 스토리지 엔진은 직접 구현하여 추가 사용이 가능하다.
패스트 캠퍼스에서 진행한 강의(백엔드 개발자를 위한 한 번에 끝내는 대용량 데이터 & 트래픽처리)를 토대로 정리한 포스팅입니다.
자세한 내용은 링크를 참고하시기 바랍니다. 문제시 바로 삭제하겠습니다.