Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

소개

예전에 웹 서비스 아키텍처 ABC를 다룬적이 있다. 인터넷 웹 서비스에서 일반적으로 사용 할 수 있는 아키텍처를 묘사하고 구성요소들에 대해서 간단히 살펴봤다. 이 아키텍처를 AWS 기반으로 다시 만들어 보려 한다. 웹 서비스 아키텍처 ABC 에서 설명했던 아키텍처는 아래와 같다.

 기본 아키텍처

위 아키텍처는 Joinc 서비스에서 사용하고 있는 아키텍처다. Joinc는 wiki 문서의 작성과 관리를 서비스하고 있다. wiki 문서는 텍스트 뿐만 아니라, 이미지와 동영상을 포함하고 있다.

AWS

AWS(Amazon Web Service)는 일반인들에게는 인터넷 쇼핑몰 업체로 잘 알려진 아마존(amazon)에서 제공하는 클라우드 서비스다. AWS는 처음에는 IaaS에서 시작했지만 지금은 PaaS와 SaaS, FaaS 등 인터넷 서비스를 개발하기 위한 필요한 일체의 것들을 모두 제공한다. 이제 개발자는 어떠한 물리 장비를 구입할 필요도 없이 AWS에서 제공하는 API를 이용해서 완전한 인터넷 서비스 시스템을 구성 할 수 있다. 이를테면 "마치 프로그래밍 하듯이 인터넷 서비스 아키텍처를 설계하고, 설계한 아키텍처를 실제 서비스 가능한 상태로 배치"하는 일을 할 수 있게 됐다. AWS외에도 Microsoft 애저(Azure), GCP(Google Cloud Platform), IBM Cloud 등의 클라우드 서비스가 있다. AWS는 클라우드 서비스 시장의 절대강자로 2018년 현재 전체 시장의 40% 이상을 점유하고 있다.

결론부터 말하자면 위의 "웹 서비스 아키텍처"는 AWS로 완전하게 재 구성 할 수 있다. 아래 그림은 AWS 기반으로 설계한 아키텍처다.

 AWS 아키텍처

웹 서비스 아키텍처 ABC와 (약간의 차이가 있긴 하지만)일치하게 그렸다. 간단히 묘사한후 각 부분을 자세히 살펴보겠다.

유저는 서비스를 이용하기 위해서 브라우저로 www.joinc.co.kr 사이트에 접근한다. Amazon Route53은 AWS에서 제공하는 DNS 서비스다. 브라우저는 Route53에 질의해서 www.joinc.co.kr에 대한 IP를 가져온다.

브라우저는 로드밸런서 서비스인 Elastic Load Blancer 에 요청을 보낸다. (이미지와 텍스트를 포함하고 있는)이 요청은 로드밸런서가 관리하고 있는 웹 서버들 중 하나에 전달이 된다. 웹 서버는 이미지파일을 S3에 저장을 하고 작업 명세서를 만들어서 Amazone SQS(Simple Queue Service)에 밀어 넣는다. 그리고 클라이언트에서 "성공"을 리턴한다. 이미지에 대한 처리는 비동기적으로 진행된다.

SQS는 하나 이상의 Worker가 기다리고 있는데, 이들 중 하나가 작업 명세서를 꺼내서(POP)해서 요청을 처리한다. 이때 S3에 저장된 유저 이미지를 읽어서 자르기, 섬네일 생성, 색인 등의 작업을 한다.

유저의 모든 행동들은 Amazon Kinesis를 통해서 S3와 redshift에 저장된다. 이 데이터는 EMR등으로 분석, redshift/RDS 등에 저장해서 서비스 목적으로 사용한다.

DNS - Route53

Route53은 AWS에서 제공하는 관리형 클라우드 DNS 서비스다. Route53은 A 레코드와 CNAME 정도만을 등록해서 간단하게 사용 할 수 있도록 해주는 호스팅 서비스가 아니다. DNS 서비스를 완전 운영하기 위한 거의 모든 기능에 GLSB 수준의 응용까지를 제공한다. 지원되는 레코드만 AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SPF, SRV, TXT이다. 라우팅 정책도 단순 라우팅, 장애조치 라우팅, 지리 위치 라우팅, 지연 시간 라우팅, 다중 응답 라우팅, 가중치 기반 라우팅을 지원한다.

AWS는 도메인 이름 등록 서비스도 제공한다. 도메인 이름 등록 서비스는 Route53과 ACM(AWS Certificate Manager - SSL 인증서 관리)를 제공한다. 인증서를 자동으로 관리해줄 뿐만 아니라 Load Balancer로 offload까지 자동화 할 수 있다.

Elastic Load Balancer

AWS는 Elastic Load Balancer 이라고 하는 로드밸런서 서비스를 제공한다. 로드밸런서는 일반적인 HTTP,HTTPS 요청을 처리하는 Application Load Balancer와 TCP 요청을 처리하는 Network Load Balancer 두 개 타입을 제공한다. Classic Load Balancer라고 해서 선택할 수 있는 로드밸런서 타입이 하나 더 있기는 한데, Application Load Balancer로 대체되고 있다.

OSI 모델에 따르면 로드밸런서는 Layer 4(네트워크)와 Layer 7(애플리케이션) 두 개의 타입이 있다.

L4 로드밸런서는 네트워크 프로토콜(보통 TCP와 UDP)레벨에서 요청을 다룬다. L4 로드밸런서는 패킷내용은 살펴 보지 않기 때문에, HTTP, HTTPS, FTP와 같은 특정 애플리케이션 프로토콜을 인지해서 지능적으로 밸런싱 할 수는 없다.

L7 로드밸런서는 HTTP, HTTPS 의 헤더에 접근해서 지능적으로 분산 작업을 할 수 있다. Joinc는 이미지 업로드를 위한 POST /wiki/image, 위키 문서 업로드를 위한 POST /wiki/doc API를 제공한다. 두 개 API는 컴퓨팅자원을 사용하는 특성이 서로 다르기 때문에, /wiki/image는 "이미지 서버" 에서 위키 문서는 데이터베이스 작업을 하는 평범한 "애플리케이션 서버"로 분리하기로 했다.

ALB가 제공하는 Path-Based Routing 기능을 이용하면, 하나의 로드밸런서에서 요청을 처리 할 수 있다. 아래 그림을 보자.

 ALB

  • 이미지 처리를 위한 고성능 VM 으로 구성된 "Target Group - Image" 를 만들었다.
  • 위키 문서의 저장/읽기를 위한 표준 성능의 VM 으로 구성된 "Target Group - App"를 만들었다.
하나의 서비스 도메인을 가짐으로써 도메인 일관성을 가질 수 있다. 그리고 API의 특성에 맞게 그룹을 나눔으로, 각각의 요소에 맞는 컴퓨팅 자원, 모니터링, 스케일링, 보안정책등의 관리를 할 수 있다.

ElasticCache

ElasticCache는 완전관리형의 Redis와 Memcached를 제공한다. Joinc는 아래의 서비스에 ElasticCache의 Redis를 사용한다.

세션관리 : 올바른 유저이고 로그인한 유저인지 등에 대한 정보는 데이터베이스 조회를 통해서 알아낼 수 있다. 하지만 데이터베이스 조회에는 많은 비용이 들어간다. 매 유저의 요청마다 데이터베이스를 조회하는 것은 좋은 방법이 아니다. 최초 유저가 로그인을 하면, Session key를 만들고 유저 정보와 함께 Redis에 저장한다.

 REDIS를 이용한 세션 관리

ElasticCache Redis는 완전관리형으로 고가용성 시스템을 구성 할 수 있다. 하지만 인메모리(in memory) 데이터베이스인 만큼 안전성을 보장하지는 않는다. 데이터가 유실될 수 있으로 이 경우를 대비해서 MySQL 데이터베이스에서 세션 정보를 복원 하도록 장치를 마련해야 한다. Redis의 서비스 응용은 Redis 데이터모델들문서를 참고하자.

웹 애플리케이션 서버

웹 애플리케이션 서버는 AWS에서 제공하는 가상 컴퓨팅 서비스인 EC2로 만들 수 있다. Joinc의 웹 애플리케이션 서버는 REST API 형태로 인증, 이미지 업로드&다운로드, 위키 문서 저장,읽기, 업데이트와 같은 서비스를 수행한다. 웹 애플리케이션 서버는 ElasticCache, RDS, SQS 같은 다른 AWS 서비스를 이용한다.

애플리케이션 서버는 Node.js, Ruby, PHP, Scala, Golang, Java, C# 등의 언어 혹은 Ruby on Rails, Java Spring, Python flask, Django 등의 프래임워크로 개발 할 수 있다.

여기에서는 편의상 EC2로 서비스를 구성했지만, 컨테이너 서비스인 나 EKS, Serverless 서비스인 AWS Lambda로 서비스를 구성 할 수도 있다.

데이터베이스 서버

AWS RDS와 DynamoDB 두 개의 데이터베이스 서비스를 제공한다. RDS는 PostgreSQL, MySQL, Oracle 과 같은 RDBMS 서비스다. DynamoDB는 MongoDB와 매우 유사한 NoSQL 데이터베이스다.

RDS의 경우 서비스를 실행하면 EC2 인스턴스가 만들어진다. 모든 설정이 끝난 "MySQL 데이터베이스가 설치된 EC2"의 실행이라고 보면 된다. EC2위에서 실행된다고 해도 백업, 고가용성 구성, 읽기전용 복제 생성등의 작업을 위한 툴이 제공되므로 직접 EC2위에 MySQL을 설치하는 것과는 차원이 다른 편리함을 제공한다.

DynamoDB는 서버리스(Serverless) 데이터베이스다. RDS처럼 EC2를 관리하거나 스케일을 관리하기 위한 작업이 필요 없다. 그냥 사용하면 된다. 무제한의 처리량과 스토리지를 제공한다. 최근에는 성능향상을 위한 메모리 캐시도 지원하고 있다.

DynamoDB와 RDS 어떤 걸 사용해야 할까 ? DynamoDB는 NoSQL 스토리지이며 RDS는 관계형 데이터 스토리지로 사용한다. 애플리케이션이 사용하는 데이터의 특성, 요구사항에 따라서 선택해야 한다. 실제 많은 서비스들이 두 개 데이터베이스를 함께 사용하고 있다.

예를 들어 Key/Value 타입의 데이터이고 스키마가 없는(JSON 등)의 데이터라면 DynamoDB를 사용하면 된다. 그렇지 않고, 테이블이 복잡한 관계를 가지며, 유연한 쿼리를 만들어야 하는 데이터라면 RDS가 더 나은 솔류션일 수 있다.

그래도 선택하기가 애매모호 할 수 있을 것 같은데, 내 경험을 말해 보려 한다.

세션 데이터베이스와 같은 특정 영역에서 DynamoDB를 사용하는 것은 좋은 선택이지만 DynamoDB를 주요 데이터베이스 시스템으로 구축하는 것은 좋은 생각이 아니다. DynamoDB로 유연한 쿼리를 만드는 건 어려운일이다. 내 서비스는 그런 유연한 쿼리가 필요하지 않다라는 판단에 DynamoDB를 선택 할 수 있지만, 서비스를 하다보면 추가적인 유연성이 (매우 자주)필요할 수 있다. 서비스가 다뤄야 하는 데이터가 수테라 정도라면 왠만해서는 그냥 RDS를 사용하는게 낫다.

성능도 마찬가지다. 테이블 스키마를 잘못 설계하지 않는한 DynamoDB와 RDS에 유의미한 성능차이는 없다. 그리고 어차피 성능은 (Redis 같은)캐시로 달성하는 거지 데이터베이스로 달성하는게 아니다.

DynamoDB의 최대 장점은 성능이나 (스키마 없음)유연성이 아닌, 확장성과 내구성에 있다. 개발자는 확장과 내구성을 위해서 아무 것도 할 필요가 없다. 믿을 수 없는 확장성과 내구성을 제공한다. 하지만 단점을 보완할 정도는 아니다.

Job Queue & Worker

Job Queue는 비동기적 작업을 처리하기 위해서 사용한다. Joinc는 유저가 업로드한 동영상을 처리하기 위해서 사용하고 있다. 유저가 영상을 올리면 모바일과 PC에 맞게 변환하고 영상으로 부터 이미지 클립을 추출해서 저장하는 작업을 한다. 이 작업은 많은 시간이 걸리기 때문에, 파일 업로드가 끝나면 업로드 성공 메시지를 보내고 요청을 정리한다.

웹 애플리케이션 서버는 업로드한 이미지를 클라우드 저장소인 S3로 보내고, AWS의 Job Queue 서비스인 SQS에 작업 명세서를 Push 한다. 그러면 SQS를 바라보고 있던 Worker 중 하나가 명세서를 읽어서 영상 작업을 한다. 작업이 끝나면 Amazon SNS를 이용해서 유저 모바일에 Push 메시지를 전송한다.

 비동기 작업

Full-text Search Service

Full-text Search 서비스는 Invert Index를 활용해서 텍스트를 색인한다. 여기에 TF * IDF와 density model, field boost와 같은 몇 가지 장치들을 이용해서 유사한 문서를 제공 할 수 있다.
  • TF - Term Frequency : 단어를 많이 포함하는 문서가 유사도가 더 높을 것이다.
  • Inverse Document Frequencey : 단어를 포함하는 문서가 많을 수록 더 낮은 유사도를 가진다. 예를 들어서 유저가 "The Linux"로 검색을 했다고 가정해 보자. 그러면 "The"와 "Linux"를 포함한 문서를 찾을 거다. 두 개 문서를 모두 포함한 문서가 가장 높은 유사도를 가질 것이고, 그 다음 "Linux"를 포함한 문서가 "The"를 포함한 문서보다 더 높은 유사도를 가질 것이다. The는 Linux 보다 일반적으로 사용하는 단어로 많은 문서에 노출 되기 때문에 "중요하지 않은 단어"라고 가정 할 수 있기 때문이다. 이는 우리의 직관과 맞아 떨어진다.
AWS는 ElasticSearch와 CloudSearch 두 개의 Full-text Search Service를 제공한다. 보통 AWS ElasticSearch는 이름 그대로 오픈소스 검색엔진인 ElasticSearch를 기반으로 하는 서비스다. 검색(특히 디버깅과 모니터링을 위한 로그 검색)에 널리 사용하는 ELK(ElasticSearch+Logstash,Kibana)스택 기술 경험을 그대로 사용 할 수 있기 때문에 CloudSearch에 비해서 널리 사용한다.

CloudSearch는 Solr를 기반으로 하고 있다. Solr나 ElasticSearch 모두 루씬(Lucene)를 기반으로 하고 있기 때문에 기술적으로 큰 차이는 없다고 하겠다.

그러면 어떤 걸 선택해야 하나 ? 어느 것을 이용해도 원하는 것을 얻을 수 있다. ElasticSearch는 사용층이 넓어서 좀 더 쉽게 접근 할 수 있을 것이다. CloudSearch는 좀 마이너이긴 한데(Solr가 ElasticSearch 보다는 사용자 층이 적다), 완전 관리형이라서 운영 & 관리 부담이 덜하다. 그리고 CloudSearch가 좀더 상세한 검색 서비스 설정이 가능하다. 인터넷 문서에 대한 검색 품질을 엄밀하게 관리하고 싶다면 CloudSearch가 더 좋은 선택이 될 수 있다. 로그 분석이라면.. 그냥 AWS ElasticSearch로 가자.

Cloud storage

S3는 AWS에서 가장 활용도가 높은 서비스 중 하나다. 모든 데이터 작업이 S3를 기반으로 이루어진다고 보면 된다. 서비스 파일의 업로드 다운로드 서비스는 당연히하며, EMR 작업도 HDFS가 아닌 S3를 기반으로 한다. 가공된 데이터를 RDS나 DynamoDB 등에 업로드 하는 것도 S3를 중심으로 이루어진다. 예를 들어 RDS Mysql Aurora 같은 데이터베이스는 S3로 부터 csv 파일을 직접 import 할 수 있다. Redshift, Athena와 같은 비정형 데이터에 대한 분석과 쿼리도 S3로 실행 할 수 있다.

S3의 특징은 완전관리형 오브젝트 스토리지다. 내부적으로 최소한 두 개 이상의 물리적인 가용 영역(AZ, 데이터 센터라고 생각하면 편하다)에 데이터를 복제해서 저장하기 때문에 99.999999999%의 내구성을 보장한다.

클라우드 스토리지 서비스를 쉽게 구현 할 수 있다는 점도 매력이다. S3는 HMAC(Hash Message Authentication code)를 기반으로 하는 signed url을 제공한다. 이 url은 특정시간만 사용하며, 안전하게 사용 할 수 있다. 개발자는 개인에게 파일 업로드, 다운로드 서비스를 제공하기 위해서 파일 중계 서버를 만들 필요가 없다.

Joinc는 아래와 같이 클라우드 스토리지 서비스 인프라를 구축했다.

 Cloud Storage

  1. 유저가 파일을 요청한다. 요청은 ELB로 전달된다.
  2. ELB는 EC2 인스턴스 중 하나에 요청을 보낸다.
  3. 인스턴스는 S3 API를 이용해서 파일의 위치를 찾은 다음에 Pre sigend URL을 반환한다. 이 Pre signed URL 은 HMAC으로 사이닝 됐으며 몇 분동안만 사용 할 수 있다.
  4. 유저는 Pre signed URL로 S3로부터 파일을 다운로드 한다.
다운로드 과정만 설명했는데, 업로드도 동일하게 구현할 수 있다. 웹 애플리케이션 서버는 유저의 파일 권한등을 확인하고 Signed URL을 만드는 작업을 할 뿐, 실제 파일 업로드와 다운로드는 S3에 맡긴다. 요청이 늘어남에 따른 걱정 없이 로직만 구현하면 된다.

CloudFront - CDN

CloudFront는 AWS에서 제공하는 CDN 서비스다.

인터넷은 전 지구적인 네트워크로 이 위에 올라가는 인터넷 서비스 역시 어떠한 공간적인 경계도 가지고 있지 않다. 인터넷 서비스는 사용자 위치에 관계 없이 짧은 지연시간에 빠른 속도로 컨텐츠를 제공 할 수 있어야 한다.

Joinc는 글로벌 서비스다. 사용자가 이미지나 동영상을 올리면 유저와 가까운 위치에 있는 스토리지에 저장이 된다. 한국 유저의 경우 서울에 있는 AWS 시스템에 저장이 된다. 한국 유저가 컨텐츠를 소비하는데 문제는 없지만 북미 유저가 소비할 경우 응답시간과 대역폭이 문제가 된다. Joinc는 CloudFront를 이용해서 유저가 올린 데이터를 북미에 배포를 한다. 이제 북미 유저는 한국이 아닌 북미에 있는 AWS 시스템에서 데이터를 읽을 수 있다.

아래 그림은 CloudFront의 작동 방식을 묘사하고 있다.

 CloudFront

  1. 유저가 웹 브라우저등을 이용해서 이미지 파일을 요청한다.
  2. DNS는 이미지 파일을 가장 빠르게 제공할 수 있는 CloudFront edge location으로 요청을 라우팅 한다. 보통 지연시간을 기준으로 라우팅한다.
  3. Edge Location에 요청한 파일이 있는지 확인 한다. 있다면 이미지 파일을 반환하고 없다면, 원본 서버에 이미지를 요청한다. CloudFront는 원본 서버로 부터 전송되는 이미지를 클라이언트에 전달하고, 다음 번 클라이언트 요청에 응답하기 위해서 Edge Location에 이미지를 저장한다.
CloudFront는 아래와 같은 기능을 가지고 있다.
  • 정적/동적 컨텐츠 가속 서비스
  • HTTP/HTTPS 서비스
  • 쿠키/헤더를 오리진 서버에 전달
  • 통계 보고서
  • Signed URL, Signed Cookie등 컨텐츠 보안
  • CloudTrail을 연동한 API 호출 감사
  • 업로드 가속
  • GZIP 압축 지원

VPC

AWS는 퍼블릭 클라우드 서비스다. 유저는 AWS 인프라 위에 독립적인 네트워크를 구성해서 서비스 자원을 배치 할 수 있다. 인터넷 상에 IDC(인터넷 데이터 센터)를 구축할 수 있는 이 서비스가 VPC(Virtual Private Cloud)다.

 VPC

주요 구성요소들을 아주 간단히 설명하겠다.
  • VPC : 인터넷으로 부터 격리된 네트워크를 만들 수 있다.
  • Internet Gateway : VPC는 격리된 네트워크다. 인터넷으로 나가기 위해서는 Internet Gateway가 필요하다.
  • Subnet : VPC를 만들면 유저에게 16비트 네트워크가 만들어진다. 유저는 이 네트워크를 여러 개의 서브넷(subnet)으로 나눠서 자신만의 네트워크를 구성할 수 있다. 서브넷은 Private Subnet과 Public Subnet으로 나눌 수 있다. Private Subnet은 인터넷과 완전히 격리된다. Public subnet은 인터넷에서 접근 할 수 있다. 보통 Private Subnet에는 데이터베이스와 같은 인터넷에서 접근하면 안되는 자원을 두고, Public Subnet에 웹서버나 웹 애플리케이션 서버 등 유저가 직접 접근해야 하는 자원을 배치한다.
  • Router : 유저는 라우터를 설정 할 수 있다. 라우터를 이용해서 서브넷과 인터넷, 서브넷과 서브넷의 트래픽의 경로를 설정 할 수 있다. 예를 들어 subnet을 만들고 0.0.0.0/0으로 향하는 트래픽을 Internet Gateway로 향하게 하면 Public Subnet이 된다.
  • VPN Gateway : Private subnet에 데이터베이스를 두는데, 이 데이터베이스는 회사에서 접근 할 수 있어야 한다. 이 경우 VPN Gateway를 만들어서 회사 네트워크와 VPC를 연결 할 수 있다. 역시 Router 설정으로 이러한 작업을 수행 할 수 있다.
약간의 능력만 된다면, 데이터베이스 네트워크, 스토리지 네트워크, 모니터링 네트워크와 같은 독립적인 네트워크를 구성 할 수도 있다.