Puffin's DevLog

DB 모델링과 서비스 아키텍처 WORKSHOP: 3, 4주차

세 번째 강의와 네 번째 강의에서는 사람들이 그려온 DB 모델링을 다같이 보면서 이야기를 나누고, 성능을 향상시키기 위한 여러 기법에 대해서 공부했고, 마지막으로는 서비스에 따라 어떤 아키텍처를 채택해야 하는지를 학습했다.

DB 모델링 리뷰 & 피드백

성능 높이기: DB & SQL 튜닝

1. INDEX

  • INDEX
  • INDEX는 순서가 중요
    • cardinality가 높은 것부터 적용해야 한다
  • INDEX를 사용하지 않아도 되는 경우
    • 특정하기 어려운 경우
    • 자주 변경되지만 읽기는 거의 없는 로그성 데이터

2. ANALYZE TABLE & OPTIMIZE TABLE

ANALYZE TABLE은 DB를 스캔해서 총 column 수와 같은 메타데이터를 저장해둔다. 주기적으로 실행하면 도움이 되는데, READ lock이 걸리기 때문에 사용이 적은 시간에 수행하는 것이 좋다.

OPTIMIZE TABLE은 데이터 조각모음과 같은 역할이다. 가변 데이터는 삭제 등일 일어나면서 데이터 길이가 달라지는데, 달라지는 시점에는 크기를 줄일 수가 없다. OPTIMIZE TABLE은 빈 것을 찾아서 당겨준다.

3. EXPLAIN

쿼리 앞에 붙여두면 분석하여 결과를 미리 알려준다. 쿼리를 날려보면서 튜닝할 때 유용하다.

4. JOIN & SubQuery

JOIN이 성능에 나쁘다는 것은 오해다. SubQuery(쿼리 안에 쿼리가 있는 사례)에 비하면 JOIN이 월등히 성능 면에서 앞선다.

서비스 아키텍처

1. Single Point of Failure

하나가 고장나면 전체 시스템이 중단되는 지점을 의미한다. 가령, 네트워크를 생각해보면 네트워크 허브 장치 전원이 이 SPOF가 될 수 있다. 따라서 이러한 요소를 최대한 없애는 방향으로 아키텍처를 고민해야 한다.

이 수업을 들으면서 여러 면에서 생각이 확장된다고 느꼈다. 처음 프로그래밍을 배울 때 (특히 React에서) Single source of truth 개념을 통해서 중복을 최대한 없애는 것이 관리 측면에서 용이하다고 알고 있었다. 그런데 데이터베이스에서는 데이터를 중복해서 저장하는 역정규화라는 과정을 통하여 효율적인 관리를 고민할 수도 있고, 또 단일 장애점을 최대한 방어할 수 있도록 없애야 한다.

2. 서비스 규모 키우기

2-1. Monolithic vs. Micro

강사님이 강조했던 부분 중 하나는, 마이크로서비스 아키텍처가 새롭고 별도로 공부해야 하는 개념이 아니라는 것이었다. 서비스가 커지면 자연스럽게 monolithic에서 micro로 넘어갈 수밖에 없다는 것이었다.

새로운 서비스를 개발한다고 해보자. 이 서비스는 5초 이내에 화면이 나와야 한다.

2-2. 규모에 따른 서비스 전략

1단계: 서버+DB 컴퓨터가 1대

이용자가 많지 않은 초기 단계에서는 1대의 컴퓨터에 서버와 DB를 동시에 설치할 수 있다. 이때, 동시에 글을 쓴다면 아마도 max 2, 30명 선에서 서버가 뻗을 것이다.

2단계: 서버와 DB를 분리

유저 수가 증가하면, 디스크의 입출력이 늘어난다. 즉, 서버에 부하가 높아지게 된다. 따라서 서버와 DB를 분리한다.

3단계: 서버 증설

2단계 상태에서 한 대의 컴퓨터를 더 추가한다면 역시 서버 컴퓨터를 늘리는 것이 좋다. 서버는 횡으로 확장하는 스케일 아웃이 더 적절하고, DBMS는 사양을 한번 정하면 바꾸기가 쉽지 않으므로 사양을 좋게 선택하는 스케일 업 전략을 택하는 것이 좋다. 그리고 서버가 늘어난다면 해당 서버마다 IP가 부여되기 때문에, 하나의 도메인에서 접속할 수 있도록 로드밸런서를 설정해주는 것이 중요하다.

4단계: 정적 웹 서버 분리 / 서버 4대+DBMS 1대를 한 군으로, 여러 군을 증설

웹 서버는 온전히 비즈니스 로직만을 처리하고, HTML 등 정적파일은 따로 관리한다. 가령, JS 파일은 아예 다른 도메인에서 가지고 오는 경우가 있는데 이게 이러한 사례다. 그리고 규모가 커지면 웹 서버 4대와 DBMS 1대를 묶어 하나의 군으로 관리하면서 이 군을 차례로 늘려 나간다. 하나의 군에도 로드 밸런서가 설정되어 있고, 로드 밸런서를 또 로드밸런싱해주는 로드밸런서가 있을 수 있다.

5단계: 정적캐시 적용

지속적으로 변하는 데이터와 아닌 데이터를 구분하여 정적 캐시를 적용한다. 가령 user의 profile이라던가, friend 등은 잘 변하지 않는다. 그래서 캐시를 적용해두면 좀 더 효율적인 사용이 가능하다. Redis가 대표적인 캐시 서버다.

이런 식으로 규모를 키워나갈 수 있다.

3. 다양한 서비스 아키텍처

3-1. 모바일 서비스

유저가 어떤 패턴인지를 고려한다. 모바일 서비스는 이동시간대와 점심시간, 취침 전 시간에 증가하기 때문에 해당 시간에 서버를 증설하는 것이 좋다. 또, 앱을 선호하므로 API 형태로 서버를 만드는 것이 좋다.

모바일 커머스는 결제나 재고가 중요하므로, 결제 DB부터 분리하는 것이 일반적이다. 그리고 서비스가 커질수록 서비스와 기능 단위로 군을 나누어 서버를 운영하게 된다. 위에서도 언급했듯, 서비스 단위가 커지면 자연스럽게 마이크로서비스 아키텍처로 향하게 되어 있다.

3-2. 콘텐츠 (ex. 뉴스)

뉴스는 데이터를 일방적으로 송출하고, 해당 데이터를 읽는 사용자는 많지만 데이터를 쓰는 것은 극소수의 직원들 뿐이다. 따라서, master-slave 구조를 띄도록 DB를 설계할 수 있다. master DB에서만 업데이트가 이뤄지고, 그 내용을 다른 slave DB들에 복제하는 방식이다. 일관성이 떨어질 수도 있기 때문에 사용하지 않는 slave를 하나 더 마련할 수도 있다.

3-3. 포스 단말기

가게에 놓인 포스 단말기에는 그 안에 local DB가 존재한다. 해당 DB는 주기적으로 그 내용을 중앙 포스 사에 전송한다.

3-4. 경매/메신저

실시간 업데이트가 중요하다. 요청을 해야만 응답을 받는 HTTP 프로토콜보다는 다른 방식을 사용하는 편이다. WEBSOCKET이라는 기술은 socket이라는 통로를 계속 열어두는 방식으로, 속도가 월등히 빨라서 가장 널리 사용되고 있다.

Loading script...