일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 데이터베이스
- C++
- 문제풀이
- 스프링
- 코딩교육봉사
- 시나공
- 백준
- 소프티어
- 자바
- 공부일지
- python
- MYSQL
- BFS
- CJ UNIT
- 코딩봉사
- 코틀린
- SW봉사
- 알고리즘
- 파이썬
- 프로그래머스
- 회고
- programmers
- java
- softeer
- 백준 알고리즘
- 백준알고리즘
- SQL
- 1과목
- 정보처리산업기사
- kotlin
- Today
- Total
JIE0025
가상 면접 사례로 배우는 대규모 시스템 설계 기초 1장 : 사용자 수에 따른 규모 확장성 본문
가상 면접 사례로 배우는 대규모 시스템 설계 기초
1장 : 사용자 수에 따른 규모 확장성
모든 컴포넌트가 단 한대의 서버에서 실행되는 간단한 시스템부터 설계하며 점차 복잡한 시스템을 설계해보자.
✅ 단일서버
웹/ 앱/ 데이터베이스/ 캐시 등이 전부 서버 한대에서 실행된다.
1. 사용자는 도메인 이름으로 웹사이트 접속 시도
2. DNS (Domain Name System) 을 통해 IP주소를 반환받는다.
3. 해당 IP 주소로 HTTP 요청이 전달된다.
4. 요청받은 웹서버가 응답으로 HTML/ JSON을 반환한다..
✅ 데이터베이스
RDBMS : 관계형 DB (JOIN이 가능하다)
NOSQL : 비관계형 DB (JOIN불가능)
대부분은 RDBMS로 해결이 가능하지만,
비관계형 데이터베이스가 바람직한 경우가 있음
- 아주 낮은 응답 지연시간이 요구되는 경우
- 다루는 데이터가 비정형인 경우
- 데이터를 직렬화/역직렬화 할 수 있기만 하면 되는 경우
- 아주 많은 양의 데이터를 저장할 필요가 있는 경우
✅ 규모확장
수직적 규모 확장 (스케일 업) : 서버에 고사양 자원을 추가
* CPU, RAM 등
수평적 규모 확장 (스케일 아웃) : 더 많은 서버를 추가
- 트래픽의 양이 적은 경우 > 수직적확장
- 수직적 확장에는 한계가 있음
- 무한대로 증설할 수 없다.
- 서버 장애시 자동복구/ 다중화 방안이 없음 > 장애시 웹앱이 완전히 중단됨
이러한 이유로 대규모 애플리케이션 지원에는 수평적 규모 확장법이 더욱 적절함.
✅ 로드밸런서
부하 분산집합에 속한 웹서버들에게 트래픽부하를 고르게 분산하는 역할
* 쉽게 예를 들어보자.
임영웅 콘서트 예매를 위한 서버가 1대만 있으면 과부하가 걸릴 것을 예상해
서버를 10대로 증설해놓았다.
같은 ip주소로 들어오는 모든 요청에 대해 서버 10대로 트래픽을 나눠주는 역할을 로드밸런서가 처리한다.
아래를 보면 DNS는
사용자는 로드밸런서의 Public IP를 통해 접속한다. 웹서버는 직접 클라이언트의 요청을 처리하지 않고,
서버간 사설 IP주소(private IP address) 를 이용한다.
* 사설 IP주소 : 같은 네트워크에 속한 서버 사이의 통신만 쓰일수 있는 IP주소
>> 인터넷 통해 접속 불가능
⏺ 장애 자동복구 문제를 해결
로드밸런서를 사용함으로써 웹서버를 두대 이상 증설하면, 장애 자동복구 문제를 해결할 수 있다.
- 서버1 서버2가 있는 상황이다.\
- 서버 1이 다운되면 모든 트래픽이 서버2로 전송된다.
- 서버2개만으로는 트래픽을 감당할 수 없는 시점이 오는데 로드밸런서가 있으므로 웹서버 계층에 서버를 추가해주기만 하면 자동으로 로드밸런서는 트래픽을 분산할것이다.
✅ DB 다중화
많은 데이터베이스 관리 시스템은 다중화를 지원한다.
서버 사이에 주(master), 부(slave)관계를 설정하여 원본은 주서버에, 사본은 부서버에 저장하는 방식
- 쓰기 연산 = 주서버만 가능
- 주서버로부터 전달받기만 함 = 부서버 (읽기 연산만 가능)
대부분의 Application은 읽기가 쓰기보다 많이 발생하기 떄문에
부서버 개수 > 주서버 개수
⏺ DB 다중화의 장점
- 주 부 다중화모델에서 모든 데이터 변경은 주데이터베이스 서버를 통해, 읽기 연산은 부데이터베이스 서버들로 분산된다. >> 병렬 처리 될 수 있는 질의가 늘어나, 성능이 좋아진다.
- 자연재해 등의 이유로 서버 일부가 파괴되어도 데이터베이스는 보존될 수 있다 (지역적으로 떨어진 장소에 다중화 시켜 놓을수 있기 때문)
- 가용성 : 데이터를 여러 지역에 복제해두어 하나의 서버에 장애가 발생해도 다른 서버에서 가져와 계속 서비스 할수 있다.
만약 부서버가 한대뿐인데 다운된 경우
> 주서버에게 읽기 연산이 모두 전달됨
그러나 부서버가 여러대인 경우1대가 다운되었을때 다른 부서버에 읽기 연산이 분산됨
주서버가 다운되면, 한대의 부서버만 있을때 > 해당 부서버가 주서버가 될것
* 부서버가 최신 상태가 아닐 수 있기 떄문에 없는 데이터는 복구 스크립트를 돌려 추가해야한다.
- 사용자는 DNS로부터 로드밸런서의 공개 IP주소를 받는다.
- 사용자는 공개IP주소를 이용해 로드밸런서에 접속한다.
- HTTP 요청이 서버1/ 서버2 중으로 전송된다.
- 웹서버가 사용자의 데이터를 부DB서버에서 읽는다.
- 웹서버가 데이터 변경 연산을 주DB서버로 전달한다.
✅ 응답 시간의 개선 : 캐시 (Cache)
캐시를 붙이고, 정적콘텐츠를 콘텐츠 전송 네트워크 (CDN)으로 옮기면 개선할 수 있다.
⏺ 캐시
값비싼 연산 결과, 자주 참조되는 데이터를 메모리 안에 두고
뒤이은 요청이 더 빨리 처리될 수 있도록 하는 저장소
웹페이지를 새로고침할 때마다 표시할 데이터를 가져오기 위해 1번의 DB 호출이 발생하는데
애플리케이션 성능은 얼마나 자주 DB를 호출하느냐에 크게 좌우된다 !!!
캐시계층 : 데이터가 잠시 보관되는 곳 > DB보다 훨씬 빠름
요청을 받으면 가장먼저 캐시를 확인하여 응답이 저장되어 있는지 확인한다.
1 : 만약 저장되어 있다면 캐시에서 읽고, 반환
2 : 없으면 DB 쿼리로 데이터 찾아 캐시에 저장후 반환
* 캐시는 일반적으로 널리 쓰이는 프로그래밍 언어로 API를 제공하기에 사용하기 쉽다.
SECONDS = 1
cache.set('myKey', 'hi there', 3600*SECONDS)
cache.get('myKey')
사용 시 유의할 점 / 고려할 점
- 데이터 갱신이 자주 일어나지는 않으면서, 참조가 번번히 일어나는 경우
- 영속적으로 보관할 데이터는 바람직하지 않음 . 캐시서버가 재시작되면 모든 데이터가 사라지기 떄문에 중요한 데이터는 지속적 저장소에 저장해야한다.
- 캐시에 보관된 데이터는 어떻게 만료시키는가?
- 만료정책이 없으면 >> 캐시가 계속 남게 된다.
- 만료 기한이 너무 짧으면 >> DB를 너무 자주 읽게 된다
- 만료 기한이 너무 길면 >> DB원본과 차이가 날 가능성이 높아진다.
- 일관성 : DB원본과 캐시사본이 같은지 여부
- 원본 갱신 연산 및 캐시 갱신 연산이 단일 트랜잭션으로 처리되지 않으면 일관성이 깨진다.
- 캐시 서버가 한대만 있으면, 단일 장애 지점 (SPOF Single Point of Failure) 이 될 가능성이 있음
- 캐시메모리 크기 :
- 너무 작으면 데이터가 캐시에서 밀려나버림 > 성능이 떨어진다.
- 캐시메모리 과할당으로 방지할 수 있다 (갑자기 데이터가 늘어나는 경우 발생할 문제)
- 데이터 방출 정책 : 캐시가 꽉 차면 기존 데이터를 내보내어야 함.
- 가장 널리 쓰이는 것 : LRU (Least Recently Used) 사용된시점이 가장 오래된 데이터를 내보내는것
✅ CDN (Content Delivery Network)
정적 콘텐츠를 전송하는데 쓰이는
지리적으로 분산된 서버의 네트워크
이미지, 동영상, CSS 파일등을 빠르고 효율적으로 전달하기 위해 만들어진 시스템이다.
# 지리적으로 가까운 서버를 사용하여 빠르게 보내준다. - 웹사이트의 이미지 파일이 미국에 저장되어있다면 시간이 오래 걸릴것- CDN은 전세계 여러 서버에 이 이미지를 미리 복사해둔다.- 서울 서버에서 이미지를 바로 보내줄 수 있다.
- 사용자는 이미지 url을 이용해 image.png에 접근한다.
- CDN서버 캐시에 해당 이미지 가 없으면, 서버는 원본 서버에 요청해 파일을 가져온다.
- 원본서버는 CDN서버로 이미지를 반환한다. 이때 반환하는 응답의 HTTP 헤더엔 해당 파일이 얼만큼 오래 캐싱될수 있는지 TTL(Time To Live) 값이 들어있다.
- CDN서버는 이 이미지를 캐시하여 사용자에게 반환한다.
- 사용자B가 같은 이미지에 대한 요청을 CDN 서버에 전송하게되면
- 바로 CDN 캐시를 통해 반환받을 수 있다. (만료되지 않은 이미지에 대해서)
CDN 사용시 고려사항
- CDN은 대부분 3사용자에 의해 운영된다. (추가요금발생)
- 자주 사용되지 않는 콘텐츠를 캐싱하면 이득이 없으므로 빼야함
- TTL 시점을 잘 정해야한다.
- 너무 길 경우 콘텐츠 최신화가 안된다.
- 너무 짧은 경우 원본 서버에 자주 접속해서 좋지 못함
✅ 무상태 웹 계층 (stateless)
웹계층을 수평적으로 확장하는 방법의 고민이다.
사용자의 세션 데이터 같은것을 웹계층에서 제거하면
바람직한것은 사용자 상태 정보를 DB = 지속적인 저장소에 보관하여 필요시 가져오는것.을 무상태 웹계층이라고 말한다.
⏺ 왜 상태정보를 웹계층에서 제거해야할까?
상태 정보를 웹계층이 갖고 있으면
- A사용자가 서버1에 요청 . B사용자가 서버2에 요청했다고 가정하자
- 서버1엔 B사용자의 상태가 없고, 서버2엔 A사용자의 상태가 없다.
- A사용자의 요청은 서버 1로만 가야하는 상황이 된다.
- 로드밸런서- 이를 지원하는 고정세션이라는 기능이 있지만 부담이 된다.
무상태 아키텍처를 통하면
사용자로부터 들어오는 HTTP요청이 어떤 웹서버로도 전달 될수있다.
이 때 상태정보가 필요한 웹서버는 공유저장소로부터 데이터를 가져오면된다.
세션데이터를 RDBMS / NoSQL/ Cache (ex Redis) 등에 저장될수도 있는데
상태정보가 웹서버에서 제거되었기 때문에
트래픽의 양에 따라 웹서버를 추가 / 삭제 하기만 하면 자동으로 규모가 확장될수 있다.
✅ 데이터센터
: 서버 컴퓨터와 네트워크 회선 등을 제공하는 건물이나 시설
⏺ 데이터센터는 왜 필요할까?
서비스가 무럭무럭커서 전 세계의 사용자가 모두 사용한다고 가정하면
가용성을 높이고 어디에서든 접근이 쉽게 되어야한다.
이때 여러 위치에 데이터센터를 두면, 가장 가까운 데이터센터의 서버를 통해 응답할수있다. (지리적 라우팅)
geoDNS : 사용자의 위치에 따라 도메인 이름을 어떤 IP주소로 변환할지 결정할 수 있는 DNS 서비스
서버 컴퓨터 1-100까지 데이터센터 A 에 존재
서버 컴퓨터 101-200까지 데이터센터 B 에 존재
geoDNS는 사용자의 위치를 기반으로 데이터센터에 해당하는 VIP를 반환한다.
VIP에 들어온 요청은 로드밸런서를 통해 실제서버 1-100 / 101-200 서버로 분배되어 매핑된다.
⏺ 데이터센터 2개중 1개에 접속할 수 없는 상황이 된다면
정상작동하는 데이터센터로 트래픽을 보내는 방법을 찾아야함
데이터센터 DB가 별도로 존재한다면 동기화 (다중화) 해두어야한다.
시스템을 더 큰 규모로 확장하기 위해선 시스템의 컴포넌트를 분리하고독립적으로 확장할 수 있어야한다.
✅ 메시지 큐
: 메시지의 무손실 (일단 보관된 메시지는 소비자가 꺼낼때까지 안전히 보관된다는 특성을 보장하는) 비동기 통신 지원 컴포넌트
생산자/발행자 (producer/publisher)
메시지를 만들어 메세지 큐에 발행한다.
소비자/구독자 (consumer/subscriber)
메시지를 받아 그에 맞는 동작을 수행한다.
서비스 서버간의 결합이 느슨해져서 규모 확장성이 보장되는 안정적 애플리케이션을 구성하기에 좋다.
ex 사진 보정 애플리케이션
보정이라는 작업이 시간이 오래 걸릴 수 있기 때문에 비동기적으로 처리하면 편리함
웹서버는 사진보정작업을 메세지 큐에 넣는다
사진 보정작업 프로세스들은 작업을 메시지큐에서 꺼내어 비동기적으로 완료한다.
>> 생산자/소비자 서비스의 규모가 각기 독립적으로 확장될 수 있다
ex 주문 처리 시스템
고객이 상품을 주문했을때
결재 확인, 재고,확인, 배송 요청, 주문확인 및 메세지 전달
이것이 주문 버튼 클리과 함께 동기적으로 실행되면 응답시간이 길어지며 사용자 경험이 나빠질 것이다.
이럴 때에 메시지 큐를 도입하여 작업을 비동기처리해준다.
{
"orderId": "3322156",
"userId": "4467998",
"items": [
{"productId": "A001", "quantity": 2},
{"productId": "B002", "quantity": 1}
],
"totalAmount": 30000
}
위와 같은 메세지를 큐에 넣었다고 하자.
consumer1 : 결제 시스템과 통신해 결제된것 확인한다.
consumer2 : 재고 시스템과 통신해 재고를 1 감소시킨다.
consumer3 : 배송 시스템과 통신해 배송요청을 만든다.
consumer4 : 메세지 시스템과 통신해 문자/카톡 등 메세지 전송 요청을 한다.
✅ 로그, 메트릭 그리고 자동화
소규모 웹사이트에선 필수가 아니지만,,
비즈니스 규모가 커질수록
로그, 메트릭, 자동화 도구에 필수로 투자해야한다.
로그 : 에러 로그의 모니터링 > 서버 단위로 모니터링도 되지만, 로그를 단일 서비스로 모아주는 도구를 활용하면 더 편리하게 검색할 수 있음
메트릭 : 시간이 지남에 따라 변화하는 데이터를 의미
- 호스트 단위 메트릭 : 메모리 사용률, CPU사용률, 스레드 사용률
- 종합 메트릭 : DB계층의 성능, 캐시 계층의 성능
- 핵심 비즈니스 메트릭 : 일별 능동 사용자 / 수익 . 재발문 데이터 등
> 시스템의 현재 상태를 손쉽게 파악 가능하다.
✅ 데이터베이스 규모 확장
저장할 데이터가 많아지면 DB에 대한 부하가 증가하는데
Applcation 서버처럼 스케일업 / 스케일 다운이 가능하다.
✔ 수직적 규모확장 : (CPU RAM 디스크 자원증설)
>> AWS RDS는 24TB RAM 갖춘 서버도 상품으로 제공함>> 스택오버플로는 2013한해의 사용자 전부를 마스터 데이터베이스로 처리했음
* 단점
- 서버 하드웨어에 한계가 있어서 무한 증설할 수 없고, 결국 감당하기 어려워짐
- SPOF 싱글 포인트 실패
- 비용이 많이 듬
✔ 수평적 규모확장 : (서버 증설) >> DB에 더 적절한 확장
>> 데이터베이스의 수평적 확장은 샤딩이라고 한다.
◼ 샤딩
데이터베이스를 샤드라는 작은 단위로 분할하는 기술
사용자 데이터를 어느 샤드에 넣을지는 사용자 ID에 따라 정한다.
user_id % 4 로 해시 함수로 사용하면
데이터가 보관되는 샤드가 정해진다.
샤딩키 : 데이터가 어떻게 분산될지 결정하는 하나이상의 컬럼 (위는 user_id)
샤드가 결정되면 위의 이미지처럼 데이터가 저장된다.
최종 결론
✅ 백만 사용자, 그리고 그 이상!
- 웹계층은 무상태 계층으로
- 모든계층에 다중화 도입
- 가능한한 많은 데이터를 캐시할것
- 여러 데이터 센터 지원
- 정적 콘텐츠는 CDN 통해 서비스할것
- 데이터 계층은 샤딩을 통해 그 규모를 확장할것
- 각계층은 독립적 서비스로 분할할것
- 시스템은 지속적으로 모니터링하고 자동화 도구들을 활용할것.
이미지 출처 (나중에 제 그림으로 변환하겠습니다 감사합니다)
'백엔드 > 웹, 배포' 카테고리의 다른 글
[원티드] 8월 백엔드 챌린지 - Docker (0) | 2023.07.19 |
---|---|
[AWS] EC2 무중단 배포 (linux - nohup) (0) | 2023.06.23 |
[AWS] 웹 프론트, S3 저장소를 통해 배포하자 (0) | 2023.06.21 |
우분투 시스템 환경변수 설정과 applicaiton.yml에서 해당 값 사용 (0) | 2023.06.20 |
EC2 인스턴스에 git clone(with ssh)후, 서버 실행 (0) | 2023.06.19 |