Stateful Web App(MyClothes.com)
상태 유지 웹 애플리케이션을 다뤄보자
MyClothes.com은 온라인으로 옷을 사고 장바구니가 있다.
동시에 수백명의 사용자가 있고, 모든 사용자들이 웹사이트를 둘러본다.
확장 가능해야하고 수평 확장성을 유지해야하고
웹 티어를 최대한 무상태(서버가 클라이언트의 상태를 보존하지 않음)로 유지하고 싶다.
-> 비록 장바구니의 상태가 존재하지만 웹 애플리케이션을 최대한 쉽게 확장하고 싶다.
-> 사용자가 웹사이트를 둘러볼 때 장바구니를 잃어버리면 안된다.
주소 등의 사용자 정보를 효과적으로 보관하고 어디에서나 접근할 수 있는 DB 필요
솔루션 아키텍트 과정
고정성(세션 선호도 도입)

- 사용자가 있고 Route 53과 다중 AZ ELB가 있고, 오토 스케일링 그룹과 3개의 AZ가 있다.
- 애플리케이션이 ELB에 접근하고, ELB가 인스턴스에 전달해준다.
1번 인스턴스에 장바구니를 생성하고 다음 요청은 다른 인스턴스에 요청하면 장바구니가 사라진다.
- 이 상황이 일어나지 않게 세션 선호도를 도입하자.
ELB의 Stickiness 활성화
-> 사용자가 장바구니에 담고 다음 요청도 같은 인스턴스로 연결
-> 그러나 인스턴스가 종료되면 장바구니를 잃어버린다.
사용자 쿠키

- 장바구니 내용을 인스턴스가 저장하는 대신 사용자 쪽에서 장바구니 내용을 저장하도록 하자.
로드 밸런서에 접속할 때마다 장바구니 리스트에 무엇이 있는지 알 수 있다.
- 쿠키를 사용하면 1번 인스턴스이든 2번, 3번 인스턴스에 접속해도 사용자가 직접 인스턴스로 장바구니 리스트를 보내줌.
-> 다른 인스턴스에 연결해도 같은 장바구니 내용을 잃지 않는다.
- 이것으로 각각의 인스턴스가 이전에 있었던 일을 알 필요가 없는 무상태를 달성 했다.
그러나 HTTP 요청이 점점 더 무거워지는 문제가 있다.
-> 웹 쿠키를 통해 내용을 보낼때 장바구니에 추가할 수록 점점 더 많은 데이터를 보내기 때문
-> 또한 쿠키가 공격자에 의해 변경됨으로 사용자의 장바구니가 수정될 수도 있다.
- 그래서 인스턴스가 반드시 사용자 쿠키의 내용을 검증해야 한다.
- 전체 쿠키의 크기는 4KB 이하까지만 가능하다
작은 정보만 저장 가능하다.
웹 쿠키는 크기가 작아 ElastiCache 이용하자(서버 세션 도입)

- 전체 장바구니를 웹 쿠키로 보내는 대신 세션 ID만 보내자.
-> 사용자에 대한 세션 ID를 백그라운드에 있는 ElastiCache 클러스터에 저장
- 세션 ID를 보낼때 인스턴스에게 '장바구니에 추가'라는 작업이 일어났다.
그러면 인스턴스는 장바구니 내용을 ElastiCache에 추가
이후 이 장바구니 내용을 불러올 수 있는 ID가 세션 ID가 된다.
- 사용자가 세션 ID와 함께 두 번째 요청을 보내면 이는 다른 인스턴스로 가게 된다.
그 인스턴스는 세션 ID를 이용해 장바구니 내용을 찾아 세션 데이터를 불러온다.
- ElastiCache말고 세션 데이터 저장하기
DynamoDB를 이용하자.
- 이제 ElastiCache가 정보를 제공하고 공격자는 ElastiCache 내부를 수정할 수 없다.
사용자 데이터를 DB에 저장하기

- 사용자 데이터를 저장하기 위해 RDS 사용
EC2 인스턴스와 RDS 인스턴스와 통신
- RDS는 장기적인 저장을 위한 것
RDS와 직접 통신해 주소,이름등의 정보를 저장하거나 불러온다.
각각의 인스턴스가 RDS와 통신할 수 있고,
다중 AZ 무상태 솔루션을 효과적으로 얻을 수 있다.
읽기 전용 복제본

- 트래픽이 늘어나고 사용자가 늘어났다.
- 사용자들이 대부분 웹사이트를 둘러보며 보낸다는걸 알게 된다.
읽어서 제품 정보를 얻는 행위
- 쓰기를 수행하는 RDS 마스터를 사용하고 읽기 전용 복제본 생성.
뭔가를 읽을땐 읽기 전용 복제본으로 읽는다.
이는 RDS DB의 읽기를 확장할 수 있게 해준다.
또 다른 패턴

- 캐시를 사용하는 쓰기 모드
사용자가 인스턴스와 통신하는 방식으로 작동한다.
- 동작 방식
캐시를 살펴보고 정보를 갖고 있는지 물어본다.
- 가지고있지 않으면 RDS로부터 읽어 들여서 ElastiCache에 저장한다.
-> 이 정보가 캐싱 되는 것.
- 가지고 있다면 캐시 히트되어 즉시 응답을 받는다.
- 이 패턴을 통해 RDS상의 트래픽을 줄일 수 있다.
CPU 사용량과 성능을 향상
- 이 방식은 캐시 유지 보수가 필요하다
캐시 유지 보수는 어려운 일이고, 애플리케이션 쪽에서 이루어져야 한다.
다중 AZ(재난 상황 대비)

- 이 애플리케이션은 확장가능하고 많은 읽기도 수행 가능하다.
- 이제 재난 상황에 대비해보자
- 사용자가 Route 53과 통신을 하는데 다중 AZ ELB를 사용
로드 밸런서를 다중 AZ로 만들 것이다.
오토 스케일링 그룹도 다중 AZ이다.
RDS도 다중 AZ 기능이 있다.
- 다른 방법으로는 인계 받을 수 있는 대기 복제본이 있는것.
Radis를 사용한다면 ElastiCache도 다중 AZ 기능을 갖는다.
보안 그룹 설정

- 가용성이 확장되었으니 보안 그룹을 설정하자.
- ELB쪽 어디에서나 HTTP, HTTPS 트래픽을 열 수 있다.
인스턴스 측면에서는 로드 밸런서로부터 오는 트래픽만 제한하고
ElastiCache 측면에서는 EC2 보안 그룹으로부터 오는 트래픽만 제안하려 한다.
RDS도 EC2 보안 그룹으로부터 오는 트래픽을 제안하기 원한다.
생각해보자
- ELB 고정 세션
- 쿠키 저장을 위한 웹 클라이언트 웹 앱을 무상태로 만들기
- ElastiCache
세션 ID와 세션 캐시 사용 (or DynamoDB)
읽기의 경우 RDS로부터 데이터 캐시를 위해 ElastiCache 사용
재해 상황 대비를 위해 다중AZ 사용
- RDS
사용자 데이터를 저장하기 위해 RDS 사용
읽기 전용 복제본으로 읽기 확장 (or ElastiCache)
재해 복구를 위한 다중 AZ
- 서로 참조하는 보안 그룹을 위해 철저한 보안 추가