클라이언트 or 서비스가 보내는 트래픽의 처리율을 제어하기 위한 장치입니다. ( ex. 유저는 초당 2회 이상 새 글을 올릴 수 없다. 같은 IP 주소로는 하루에 10개 이상 계정 생성 불가. 동일 디바이스로는 주당 5회 이상 리워드 요청 불가, 3시간 동안 300개 트윗만 생성 가능, 분당 300회의 read 연산만 가능 등.. )
2. 처리율 제한 장치의 이점
DoS 공격에 의한 자원 고갈을 방지할 수 있습니다.
불필요 요청을 제거하면 비용을 절감할 수 있습니다.
3. 처리율 제한 장치 알고리즘
여러 알고리즘을 사용해 구현할 수 있으며 그 각각은 고유한 장단점이 있습니다.
(1) 토큰 버킷 알고리즘
버킷에 토큰을 원하는 시간에 추가합니다. API 요청이 오면, 버킷에 토큰이 있으면 응답을 하고, 없으면 응답하지 않습니다. 버킷에 토큰은 특정 시간마다 지속적으로 채워지며 꽉 차면 버립니다. 사용자의 요청이 빠르게 많이 오면 버킷에 토큰이 채워지는 시간보다 줄어드는 게 빨라지므로 토큰 고갈 시 응답이 제한되는 원리입니다.
(2) 누출 버킷 알고리즘
토큰 버킷 알고리즘과 비슷하지만 요청 처리율이 고정되어 있다는 점이 다릅니다. 큐 크기가 꽉 차지 않으면 요청을 큐에 추가합니다. 큐에 있는 데이터 처리는 정한 임의의 시간에 일정하게 처리합니다. 일정 시간 처리되는 요청보다 요청이 많이 들어오면 자연스레 큐에 요청이 들어가지 않기 때문에 요청이 버려지는 원리입니다.
(3) 고정 윈도 카운터 알고리즘
정해진 시간 구간 동안 허용 임계값 만큼의 요청만 처리하고, 임계값 이상의 요청들은 새로운 시간 구간이 올 때까지 버리는 방식입니다. 1초에 3건 처리라면, 1초에 5건이 들어왔을 때, 먼저 온 순서대로 3건만 처리하고 2개는 버리고, 1초 후 새 윈도우 생성하여 요청받고 처리하기를 반복합니다.
(4) 이동 윈도 로깅 알고리즘
로그를 지속적으로 쌓아 나가다가, 현재 시간 기준에서 시작하여 원하는 제한 시간 범위까지 뒤로 가서 그 윈도우 구간 동안 온 요청을 처리하되, 시간 범위를 벗어나거나, 처리 가능 개수를 벗어나는 것은 버리는 방식입니다.
(5) 이동 윈도 카운터 알고리즘
고정 윈도 카운터 알고리즘과 이동 윈도 로깅 알고리즘을 결합한 것입니다.
4. 처리율 제한 장치 구현 4단계
1단계 : 문제 이해 및 설계 범위 확정
질문 예시
어떤 종류의 처리율 제한 장치를 설계해야 하나요? 클라이언트 측 제한 장치인지, 서버 측인가요? ( 답변 : 서버 측 )
어떤 기준을 사용해 API 호출을 제한해야 할까요? IP 주소를 사용해야 하나요? 아니면 사용자 ID나 다른 기준이 있나요? ( 답변 : 불명확, 유연한 시스템 )
시스템 규모는 스타트업 기준인가요 아니면 대기업 기준인가요? ( 답변 : 대기업 기준 )
시스템이 분산 환경에서 동작해야 하나요? ( 답변 : Yes )
처리율 제한 장치는 독립된 서비스인지, 애플리케이션 코드에 포함되는지 알려주세요 ( 답변 : 마음대로 설정 )
사용자의 요청이 처리율 제한에 걸러지면 사용자에게 알려야 하나요? ( 답변 : Yes )
2단계 : 개략적 설계안 제시 및 동의 구하기
처리율 제한 장치는 어디 둘 것인가?
클라이언트나, 미들웨어, 서버에 두는 것을 결정합니다. 클라우드 마이크로 서비스의 경우, 제한 장치는 보통 API 게이트웨이 컴포넌트에 구현됩니다.
정답은 없고, 현재 기술 스택, 엔지니어 인력, 우선순위, 목표에 따라 달라집니다.
사업 필요에 맞는 처리율 제한 알고리즘을 찾습니다. 서버 측에서 모두 구현해도 되지만, 제3자 제공 서비스 이용 시 이 부분은 제한됩니다.
API 게이트웨이가 이미 있다면 게이트웨이에 처리율 제한 장치를 둡니다.
처리율 제한 장치를 직접 개발 시 인력과 시간이 들기에 그럴 여력이 없다면 상용 API를 써야 합니다.
개략적인 아키텍처
처리율 제한 알고리즘의 기본 아이디어는 단순합니다. 얼마나 많은 요청이 접수되었는지를 추적할 수 있는 카운터를 추적 대상별(API, IP, 서비스 단위)로 두고 이 카운터의 값이 어떤 한도를 넘으면 요청을 거부하는 것입니다. 카운터 보관에 DB는 느리기 때문에 보통 캐시를 쓰며 Redis를 많이 사용합니다.
순서 : 클라이언트 → 처리율 제한 미들웨어 → 레디스에서 확인 → 결과에 따라 Drop or 서버 API 전달
3단계 : 상세 설계
처리율 제한 규칙은 어떻게 만들어지고 어디 저장되는가?
처리율 제한 규칙은 디스크에 보관하고, 작업 프로세스는 수시로 규칙을 디스크에서 읽어 캐시에 저장합니다.
처리가 제한된 요청들은 어떻게 처리되는가?
요청이 한도 제한에 걸리면 HTTP 헤더에 429 응답을 보내며 헤더에 처리 가능 요청 수나 클라이언트가 전송할 수 있는 요청의 수, 언제 다시 요청을 할 수 있는지 등을 반환할 수 있습니다.
분산 환경에서의 처리율 제한 장치의 구현
여러 서버와 병렬 스레드를 지원하도록 구현할 때 처리율 제한 장치는 경쟁 조건(race condition)과 동기화(synchronization) 을 고려해야 합니다.
경쟁 조건 해결 : 루아 스크립트 사용, 레디스 자료구조인 정렬 집합 사용
동기화 이슈 해결 : 분산 환경에서 여러 대의 처리율 제한 장치를 사용하는데, 이때 동기화 이슈를 해결해야 합니다. 고정 세션으로 해결 가능하나 보다 나은 해결책은 레디스와 같은 중앙 집중형 DB를 쓰는 것입니다. 데이터 동기화 시 최종 일관성 모델(Eventual Consistency model)을 사용합니다.
모니터링
처리율 제한 장치 설치 후 효과적인 동작을 보기 위해 모니터링이 필요합니다. 많은 요청이 버려지거나 효율적이지 못한 경우 수정해야 합니다.
시스템 설계 면접은 두 명의 동료가 모호한 문제를 풀기 위해 협력해 그 해결책을 찾아내는 과정에 대한 시뮬레이션입니다.
설계 기술을 시연하며, 그 과정에서 내린 결정들에 대한 방어 능력을 보이는 자리며 면접관의 피드백을 건설적인 방식으로 처리할 자질을 보이는 자리입니다.
면접관의 입장
지원자의 설계 기술적 측면 평가, 협력에 적합한 사람인지, 압박이 심한 상황도 잘 헤쳐 나가는지, 모호한 문제를 건설적으로 해결할 능력이 있는지, 좋은 질문을 던지는 능력이 있는지를 평가합니다.
순수하게 설계에만 집착하고, 트레이드오프를 도외시하고 오버 엔지니어링 하지 않는지 판단합니다.(오버 엔지니어링은 비용 상승을 유발)
성격을 파악(완고함, 편협함)
2. 시스템 설계 면접의 해야 할 것, 말아야 할 것
해야 할 것
질문을 통해 확인합니다. 스스로 내린 가정이 옳다 믿으면 절대 안 됩니다. 질문을 통해 문제 요구사항을 이해해야 합니다.
정답이나 최선의 답안 같은 경우는 절대 없다 생각해야 합니다.
면접관과 깊게 소통하여 면접관이 우리의 사고 흐름을 이해할 수 있게 해야 합니다.
가능하면 여러 해법을 제시해야 합니다.
개략적 설계에 면접관이 동의하면, 가장 중요한 컴포넌트부터 세부사항을 설명합니다.
면접관에게 자주 질문하고 면접관의 아이디어를 이끌어 내야 합니다.
하지 말아야 할 것
전형적인 면접 문제들도 대비하지 않은 상태에서 면접장에 절대 가지 않습니다.
요구사항이나 가정들을 분명히 하지 않은 상태에서 설계를 제시하지 않습니다.
처음부터 특정 컴포넌트의 세부 사항을 너무 깊이 설명하지 않습니다. 개략적 설계를 마친 뒤 세부사항으로 나아가야 합니다.
침묵 속에 설계 진행을 절대 하지 않습니다.
3. 효과적 면접을 위한 4단계 접근법
1단계 : 문제 이해 및 설계 범위 확정(가장 중요)( 20% 시간 사용 )
요구사항을 완벽히 이해하지 않고 답을 내놓는 행위는 아주 엄청난 감점 요인입니다. 바로 답을 하지 말고 깊이 생각하고 질문하여 요구사항과 가정들을 분명히 해야 합니다.
요구사항에 대해 반드시 메모를 해놓습니다. 추후 관련 내용을 사용하게 됩니다.
뉴스피드 시스템 설계의 순차적인 질문 예시
모바일 앱과 웹 앱 가운데 어디를 지원해야 하나요? 둘 다인 가요?
가장 중요한 기능은 뭔가요?
뉴스 피드 정렬은 시간 역순인가요? 아니면 특별한 정렬 기준이 있나요? 질문의 이유는 포스트마다 다른 가중치가 부여돼야 하는지 알기 위함입니다. 가령 가까운 친구의 포스트가 사용자 그룹에 올라가는 포스트보다 더 중요하다거나 하는.
한 사용자는 최대 몇 명의 사용자와 친구를 맺을 수 있나요?
사이트로 오는 트래픽 규모는 어느 정도인가요 ?(답 : DAY 천만 명입니다)
피드에 이미지나 비디오도 올릴 수 있나요? 아니면 오로지 텍스트인가요?
2단계 : 개략적인 설계안 제시 및 동의 구하기( 20% 시간 사용 )
이 과정은 면접관과 협력하며 진행해야 합니다. 개략적 설계안을 제시하고 면접관에게 동의를 얻어야 합니다.
면접관과 마치 팀원처럼 대화하며 화이트보드나 종이에 핵심 컴포넌트를 포함하는 다이어그램을 그립니다. 그리고 클라이언트(모바일/웹), API, Web Server, DB, Cache, CDN, 메시지 큐 같은 것들을 포함시킵니다. 또한, 이 최초 설계안이 시스템 규모에 관계된 제약 사항들을 만족하는지 계략적인 추정치를 면접관에게 묻고 그것을 토대로 계산합니다. 계산 과정은 소리 내어 설명해야 합니다.
이 단계에서 API 엔드 포인트나 DB 스키마도 보여야 하는가는 요구 질문에 따라 다릅니다. 구글 검색 엔진 설계와 같은 경우엔 너무 지나칠 것이고, 포커 게임 백엔드 설계는 가능할 것입니다.
3단계 : 상세 설계( 50% 시간 사용 )
여기 오기 전까지 4가지를 달성해야 합니다.
1 ) 시스템에서 전반적으로 달성해야 할 목표와 기능 범위 확인
2 ) 전체 설계의 개략적 청사진 마련
3 ) 해당 청사진에 대한 면접관의 의견 청취
4 ) 상세 설계에 집중해야 할 영역들 확인
3단계에서 설계 대상 컴포넌트 사이의 설계 우선순위를 정해야 합니다. 이는 면접에서 시간이 없으므로 면접관이 집중적으로 설명 듣고자 하는 내용을 파악하고 그 내용 위주로 설명해야 합니다. 특정 알고리즘의 동작 방식 같은 불필요한 부분은 제거합니다.
피드 발행과 뉴스 피드 가져오기를 설계한 그림은 각각 아래와 같습니다.
4단계 : 마무리( 10% 시간 사용 )
시스템 병목구간이나 개선 사항에 대한 질문이 올 수 있습니다.
내가 만든 설계를 다시 한번 요약해 주는 것도 도움이 될 수 있습니다.
오류 발생 시 무슨 일이 생기는지(서버 오류, 네트워크 장애 등) 따져보는 것도 좋습니다.
운영 이슈 논의도 좋습니다. (메트릭 수집이나 모니터링은 어떻게 하고, 로그나 시스템 배포에 대한 설명)
QPS, 최대 QPS, 저장소 요구량, 캐시 요구량, 서버 수 등을 추정하는 것이다. 이를 잘 풀기 위한 팁은 아래와 같습니다.
근사치를 사용 : 999.99 / 9.4 와 같은 복잡한 값은 1000 / 10과같이 줄입니다.
가정들을 적어 두어야 합니다.
KB, MB와 같이 단위를 붙여야 합니다.
시스템 설계 면접 시 시스템 용량이나 성능 요구사항을 개략적으로 추정해 보라는 요구가 있습니다. 개략적 규모 추정을 효과적으로 해 내려면 규모 확장성을 표현하는데 필요한 기본기에 능숙해야 합니다. 특히 2의 제곱수, 응답 지연 값, 가용성에 관계된 수치들을 기본적으로 이해하고 있어야 합니다.
2의 제곱수
데이터의 양 계산은, 데이터 볼륨의 단위를 2의 제곱수로 표현하면 어떻게 되는지를 우선 알아야 합니다.
1KB : 2^10
1MB : 2^20
1Gb : 2^30
1TB : 2^40
1PB : 2^50
응답 지연 값
컴퓨터로 특정 일을 할 때 응답 지연 값을 정리해놓은 표를 보면 아래와 같은 요약이 가능합니다.
메모리는 빠르지만 디스크는 아직도 느리다.
디스크 탐색(Seek)은 가능한 한 피해라
단순한 압축 알고리즘이 빠르다.
데이터를 인터넷으로 전송하기 전에 가능하면 압축한다.
데이터 센터가 여러 지역에 분산돼있으면, 센터 간 데이터를 주고받는 데 시간이 소요됨.
가용성에 관계된 수치들
가용성은 퍼센트(%)를 사용해 표현합니다. 100%는 시스템이 단 한 번도 중단된 적이 없음을 의미하며 자세한 내용은 아래와 같습니다.
가용율
하루당 장애 시간
주당 장애 시간
개월당 장애 시간
연간 장애 시간
99%
14.40분
1.68시간
7.31시간
3.65일
99.9
1.44분
10.08분
43.83분
8.77시간
99.99
8.64초
1.01분
4.38분
52.60분
99.999
864.00ms
6.05초
26.30초
5.26분
99.9999
86.40ms
604.80ms
2.63초
31.56초
추정치 계산 예시
가정
월간 능동 사용자 3억 명 / 50%의 사용자가 매일 사용
평균적으로 각 사용자는 매일 2건의 게시물을 올림
미디어를 포함하는 게시물은 10%
데이터는 5년간 보관
추정
QPS(Query Per Second) 추정치(초당 요청 수) : 일간 사용자는 3억 * 50%로 1.5억이며, 2건의 게시물을 올리면 매일 3억 건의 게시물이 올라옴. 이를 초당 환산하면 약 3500건이 되고, 읽고 쓰는 연산 세트를 1개로 보면 곱하기 2 해서 7000건.
저장소 : 평균 게시물 크기(아이디에 64바이트, 텍스트에 140바이트, 미디어 1MB), 미디어 저장 소 요구량만 1.5210%*1MB = 30TB/일. 그러므로 5년간 미디어 저장은 약 55PB임.
이 장을 통해, 규모 확장성과 관계된 설계 문제를 푸는 데 쓰일 유용한 개념들을 배웁니다.
단일 서버의 개념
웹 앱, DB, Cache 등이 전부 서버 한대에서 실행됩니다.
서버의 통신 순서
사용자가 DNS에 도메인에 대한 IP를 요청한다 → DNS로부터 IP를 수신 받고 해당 IP 주소로 HTTP 요청을 전달한다 → 요청받은 웹 서버는 HTML or JSON 형태의 응답을 반환
데이터베이스
사용자가 늘면 서버 하나로 충분치 않아 여러 서버를 두는데, 하나는 웹/앱 트래픽 처리 용도로 쓰고, 하나는 데이터베이스 용도로 써야 합니다. 이렇게 웹/모바일 트래픽 처리 서버와 데이터베이스 서버를 분리하면 각각을 독립적으로 확장해 나갈 수 있습니다.
데이터 베이스는 관계, 비관계로 나뉘는데 보통 관계형 데이터베이스(RDBMS)를 많이 쓰지만 특정 상황에 비 관계형 데이터 베이스를 써야 할 수 있습니다.
비 관계형 데이터베이스 고려 상황
아주 낮은 응답 지연시간이 요구될 때.
다루는 데이터가 비정형이라 관계형 데이터가 아닐 때
데이터(JSON, YAML, XML ..)를 직렬화하거나 역 직렬 화할 수 있기만 하면 될 때
아주 많은 양의 데이터를 저장할 필요가 있을 때
수직적 규모 확장 vs 수평적 규모 확장
수직적 규모 확장 : Scale Up이라 하고, 서버를 더 고사양 자원( 고사양 CPU, RAM 등)을 추가하는 행위입니다.
장점 : 서버 유입 트래픽이 적을 때 단순하게 성능 향상 가능
단점 : Scale Up에는 한계가 있음 / 장애에 대한 자동복구(FailOver) 방안이나 다중화 방안을 제시할 수 없음
수평적 규모 확장 : Scale Out이라 하고, 더 많은 서버를 추가하여 성능을 개선하는 행위
장점 : 대규모 애플리케이션을 지원하는데 적합
로드밸런서
역할
요청 트래픽 부하를 여러 서버에 고르게 분산하는 역할을 합니다.
서버 접속 순서
사용자는 DNS로부터 로드밸런서의 공개 IP 주소를 받고 로드밸런서에 접속 요청을 보냅니다.
특징
로드밸런서를 통해 트래픽을 처리하면, 웹 서버는 클라이언트의 접속을 직접 처리하지 않습니다.
보안을 위해 서버 간 통신에는 사설 IP 주소가 사용됩니다. 이는 같은 네트워크에 속한 서버 사이의 통신에만 쓰일 수 있는 IP 주소로, 인터넷을 통한 접속이 불가합니다. 이렇게 같은 서버를 여러 개 띄워 놓고 로드 밸 랜서로 트래픽을 분산 처리하면 자동복구 문제가 해결됩니다.
데이터베이스 다중화
데이터베이스 다중화의 필요성
웹서버는 여러 개 띄워서 로드밸런서로 해결했지만 데이터베이스는 하나뿐인데 이를 해결하기 위해 데이터베이스 다중 화가 필요합니다.
데이터베이스 다중화 방법
많은 DB가 다중화를 지원하며, 보통 서버 사이에 주-부 관계를 설정하고 데이터 원본은 [주-데이터베이스]에, 사본은 [부-데이터베이스]에 저장합니다. 쓰기는 [주-데이터베이스]만 가능하고 [부-데이터베이스]는 그 사본을 전달받고, 읽기 연산만을 지원합니다. 보통 서버는 조회 연산이 많으므로 [주-데이터베이스]보다 [부-데이터베이스] 가 많습니다.
주-DB : insert, update, delete 연산
부-DB : select 연산
다중화 장점
성능 향상 : 읽기 연산이 [부-데이터베이스]로 분산되기 때문에 성능이 좋아집니다.
안정성 : 재해 등으로 DB 일부가 상해도 지역을 다르게 다중화 할 경우 보다 안전합니다.
가용성 : 데이터를 여러 지역에 둠으로써 하나가 고장 나도 다른 서버에서 가져와 쓸 수 있습니다.
주-데이터베이스 손상 시
[부-데이터베이스]가 [주-데이터베이스] 역할을 하는데, [부-데이터베이스]의 데이터가 최신이 아닐 수 있습니다. 이때 복구 스크립트를 돌리거나, 다중 마스터, 원형 다중화 방식을 도입하면 이런 상황에 대처할 수 있습니다.
캐시
캐시란?
값비싼 연산 결과나 자주 참조되는 데이터를 메모리 안에 두고 요청이 빨리 이뤄질 수 있게 하는 장소입니다.
캐시 계층
별도의 캐시 계층 사용 시 데이터 베이스 부하가 줄고, 캐시 계층의 규모를 독립적으로 확장할 수 있습니다.
캐시 우선 읽기 전략 : 웹 서버가 요청을 받으면 캐시를 먼저 확인하고 데이터가 있으면 바로 반환하고 없으면 DB에서 읽어와 캐시에 저장하고 사용자에게 반환합니다.
캐시 사용 시 고려할 점
어떤 상황에서? : 데이터 갱신은 자주 일어나지 않지만 참조는 빈번하게 일어날 때 필요
어떤 데이터를? : 캐시는 휘발성이라 영속성이 필요한 데이터는 불가
만료 시간은? : 만료된 데이터는 캐시에서 삭제해야 함. 너무 길면 원본과의 차이가, 너무 짧으면 DB를 자주 접근하는 문제 발생
일관성은? : 저장 원본을 갱신하는 연산과 캐시 갱신 연산을 같이 해놓으면 일관성 유지 가능
장애 대처는? : 캐시 서버가 한 대만 있으면 SPOF(single point of failure)가 돼버릴 가능성이 존재하기에, SPOF을 피하기 위해 여러 지역에 걸쳐 캐시 서버를 분산 가동해야 함
캐시 메모리 크기는? : 너무 작으면 데이터가 밀려나버려 성능이 저하됨. 캐시 메모리 크기는 과 할당(overprovision) 하는 것이 좋음
캐시 데이터 방출 정책은? : 캐시가 꽉 찼는데 데이터를 더 넣어야 할 때, 기존 데이터를 삭제해야 하는데 이를 데이터 방출 정책이라 함. 보통 LRU를 쓰고, LFU, FIFO도 사용.
콘텐츠 전송 네트워크(CDN)
CDN 이란?
정적 콘텐츠(JS, CSS, Image 등)를 전송하는 데 쓰이는, 지리적으로 분산된 서버의 네트워크입니다.
작동 방식
사용자가 웹사이트 방문 시 그 사용자에게 지리적으로 가까운 CDN 서버가 정적 콘텐츠를 전달합니다.
CDN 사용 시 고려할 점
비용은? : CDN은 보통 제3 사업자(Cloudflare)에 의해 운영되며, CDN으로 들어오고 나가는 데이터 전송 양에 따라 과금됩니다. 자주 사용하지 않으면 이득이 없으므로 빼도록 합니다.
적절한 만료 설정이 중요
장애 대처 방안 : CDN 자체가 죽었을 경우 웹/애플리케이션이 어떻게 동작해야 하는지 고려해야 합니다. CDN 서버가 응답하지 않으면 해당 문제를 감지하여 원본 서버에 요청을 보내도록 클라이언트를 구성해야 합니다.
로드밸런서, 다중 서버, DB 다중화, 캐시, CDN이 적용된 사진입니다.
무상태(stateless) 웹 계층
웹 계층을 수평적으로 확장하기 위해서는 상태 정보(사용자 세션 데이터 등)를 웹 계층에서 제거해야 합니다. 상태 정보를 RDBMS나 NoSQL 같은 저장소에 보관하고 필요시 가져오는 것으로 해야 합니다.
상태 정보를 각 서버에 저장하면, 서버가 여러 개일 때 요청이 특정 서버에 보내져야만 응답이 가능한 문제가 있습니다. 로드밸런서가 고정 세션이라는 기능을 통해 이 문제가 해결되나 로드밸런서에 부담이 갑니다.
무상태 웹 계층의 구성도
데이터 센터
데이터 센터의 필요성
가용성이 높고, 전 세계 어디서든 쾌적하게 사용할 수 있도록 하기 위해 여러 데이터 센터를 지원하는 것은 필수입니다.
다중 데이터센터 아키텍처 구현의 난제
트래픽 우회 : 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야 합니다. GeoDNS는 사용자에게 가장 가까운 데이터센터로 트래픽을 보냅니다.
데이터 동기화 : 데이터 센터마다 별도의 DB를 둘 경우 데이터 센터마다 데이터가 다르게 됩니다. 이를 해결하기 위해 데이터를 여러 데이터센터에 걸쳐 다중화 합니다.
테스트와 배포 : 웹/애플리케이션 수정 시 여러 위치에서 테스트해 보는 것이 중요하며 자동화된 배포 도구는 모든 데이터 센터에 동일한 서비스가 설치되는 데 도움을 줍니다.
메시지 큐
메시지 큐란?
시스템을 더 큰 규모로 확장하기 위해서는 시스템의 컴포넌트를 분리해 각기 독립적으로 확장될 수 있도록 해야 합니다. 메시지 큐는 이 문제를 풀기 위해 사용하는 핵심 전략입니다.
메시지 큐는 메시지의 무손실을 보장하는 비동기 통신 지원 컴포넌트입니다.
메시지 큐 아키텍처
생산자 : 메시지 생성 후 발행(publish) 하는 역할
소비자/구독자 : 메시지를 받아 동작을 수행하는 역할
메시지 큐 장점
메시지 큐 사용 시 서버 간 결합이 느슨해져 규모 확장성이 보장되어야 하는 안정적인 애플리케이션 설계가 가능합니다.
생산자는 소비자가 다운되어도 메시지 발행이 가능하고, 소비자는 생산자가 가용상태가 아니더라도 메시지를 수신할 수 있습니다.
로그, 메트릭, 자동화
로그
에러 로그를 서버 단위로 모니터링할 수도 있지만, 로그를 단일 서비스로 모아주는 도구를 활용하면 편리하게 조회/검색이 가능합니다.
메트릭의 종류( 특정 데이터를 측정하는 것 )
호스트 단위 메트릭 : CPU, 메모리, 디스크 I/O에 관한 메트릭
종합 메트릭 : DB 계층의 성능, 캐시 계층 성능에 관한 메트릭
핵심 비즈니스 메트릭 : DAU(Daily Active User), 수익(rev-enue), 재방문(retention) 메트릭
자동화
생산성 향상을 위해 CI/CD를 도입할 수 있습니다.
데이터베이스의 규모 확장
수직적 확장
Scale UP이라 하며, 기존 서버에 고성능 자원을 증설하는 방법입니다. 이 방법에는 한계가 있으며 SPOF(Single Point Of Failure)로 인한 위험성이 있으며, 비용도 많이 듭니다.
수평적 확장
샤딩(Sharding) : 더 많은 서버를 추가함으로써 성능을 향상시키는 것으로 대규모 데이터베이스를 샤드(Shard)라 부르는 작은 단위로 분할하는 기술을 말합니다. 모든 샤드는 같은 스키마를 쓰지만 샤드에 보관되는 데이터 사이에는 중복이 없습니다.
아래는 user_id를 샤딩 키로 하여 해시 함수를 통해 저장할 샤드를 구해 저장하는 방식의 예시 사진입니다.
샤딩 키(Sharding key) : 샤딩 키는 파티션 키라 고도 부르며 데이터가 어떻게 분산될지 정하는 하나 이상의 컬럼으로 구성됩니다. 샤딩 키를 정할 때는 데이터를 고르게 분할할 수 있도록 하는 게 가장 중요합니다.
샤딩의 문제점
데이터 재 샤딩 문제
데이터가 너무 많아 기존 샤드로 불가능할 때 혹은 샤드 간 데이터 분포가 고르지 못해 하나의 샤드가 꽉 찬 경우 샤드 키 계산 함수를 변경하고 데이터를 재분배해야 합니다. 이 문제는 안정 해시(Consistent Hashing) 기법을 통해 해결합니다.
유명 인사 문제
핫스팟 키 문제라고도 하며 특정 샤드에 질의가 집중돼 서버 과부하가 일어나는 것을 의미합니다. 데이터를 적절히 분배하는 게 중요합니다.
조인과 비정규화 문제
DB를 여러 샤드 서버로 쪼개면 여러 샤드에 걸친 데이터를 조인하기 힘들어지기 때문에 DB를 비정규화하여 하나의 테이블에서 질의가 수행될 수 있도록 해야 할 필요가 있습니다.