카테고리 없음

Final-Project

WooKGOD 2023. 3. 24. 11:35
반응형

! 프로젝트 소개

 해당 서비스는 3티어 아키텍처로 구성된 커뮤니티를 운영하고 있습니다. 주로 K-Pop 팬들이 서로 소통할 수 있는 게시판을 운영하는 것이 사이트의 목적입니다. 특정 팬덤의 확대로 사이트의 트래픽이 늘고, 회사의 규모도 이에 따라 점점 커지다 보니, 개발 직군의 채용도 늘어났고, 운영 이슈도 더욱 많이 생기기 시작했습니다.

 

! 서비스 아키텍처

 

! 구현 화면

! 아키텍처의 각 리소스 사용 이유

route53을 사용하는 이유

먼저 route53은 AWS의 완전 관리형 DNS 서비스로 웹 애플리케이션과 웹 사이트의 도메인 이름을

관리하는 데 사용된다.

글로벌 팬 사이트이기 때문에 높은 가용성, 스케일링, 보안을 위해 선택했다.

가용성: 전 세계 여러 위치에 분산된 DNS 서버를 사용하여 DNS 쿼리를 빠르게 처리 가능

스케일링: 큰 트래픽 양 처리 가능(안티캐스트 네트워크, latency 기반 라우팅, dns 캐싱 등)

보안: 디도스 공격으로부터 방어 가능(Cloudfront, shield), DNS 쿼리 암호화(데이터 해독 불가) 가능

- 해당 서비스에서는 route53의 레코드를 생성하여 Cloudfront의 별칭으로 도메인을 연결하는 것 까지 이용되었기에

추가 공부가 필요한 상태이다.

 

cloudfront를 사용하는 이유

AWS에서 제공하는 CDN(콘텐츠 전송 네트워크)

전 세계적인 가용성: 엣지 로케이션을 이용한 안정적이고 빠른 사용자 경험 제공

높은 속도와 성능: 콘텐츠를 캐싱, 사용자의 요청에 빠르게 응답

높은 보안성: HTTPS 프로토콜 지원(사용자와 서버 간의 통신이 암호화되어 전송됨)

비용: 사용한 만큼 지불하는 요금제

Cloudfront를 이용해 정적 콘텐츠와 동적 콘텐츠를 모두 캐싱 가능하다.

- 기존의 s3와 연결하여 정적 콘텐츠를 캐싱할 수 있고 동적 콘텐츠의 경우 원본 서버로부터 응답을 받아와서 캐싱하게 되는데 TTL을 따로 설정함으로써 사용가능하고 DDOS 방어, L7 공격에서의 방어가 용이하고 비용도 사용량에 따라 할인이 되므로 이득이 된다.

하지만 현재 아키텍처 구성에서는 멀티 CDN이 아니라 동적 콘텐츠의 캐싱으로 SPOF가 발생할 가능성이 있다고 생각했고 원본의 변경 사항을 바로 적용하는 것을 목표로 생각했다, 해당 기술은 정확한 이해를 더 한 이후 추가할 예정이다.

 

S3를 사용하는 이유

데이터 저장, 백업 및 내구성: S3는 대규모 데이터 저장 및 백업이 가능하고 객체 스토리지이기 때문에 다양한 데이터 저장 가능, 수평확장 기능 제공

정적 웹 호스팅: 업로드한 파일에 대한 URL 제공

 # S3 이외에 정적 웹 호스팅 기능을 다른 서비스로 이용 가능하지만 관리,가격, 확장성, 보안, 쉬운 설정과 Cloudfront와 통합 가능하다는 점에서 채택

- 글로벌을 대상으로 한 서비스이기 때문에 방대한 리소스 추가에 대한 방안으로 선택(대규모 데이터 저장, 수평확장)

-  게시판 서비스에서 추후 영상이나 실시간 스트리밍 같은 파일 스토리지로도 이용 가능

- 글로벌을 대상으로 하고 팬 사이트의 경우 24시간 가동되야하기 때문에 비용 측면에서도 EC2 혹은 다른 인스턴스를 이용하는 것보다 효율적

 

람다를 사용하는 이유

s3에 연결하여 s3의 이벤트 혹은 트래픽에 대한 반응을 하는

이벤트 기반 아키텍쳐로 사용, 즉 불필요한 작업을 수행하지 않음

트래픽이 증가하거나 요청에 따라 자동확장 가능

가격면에서도 사용한 만큼 지불하기에 효율적

 

SNS, SQS를 사용하는 이유

SNS는 발행, SQS는 처리하는 역할로 아키텍처를 분리시킴으로써 메시지 처리를 안정적으로 수행가능

SNS, SQS 모두 확장 가능한 시스템으로 발행량이 증가하거나 처리량이 증가하면 자동으로 확장

SNS, SQS 모두 비동기 처리를 지원(높은 처리량, 응답시간, 확장성, 오류처리 면에서 유리)

- 동기 처리가 요청과 결과간의 관계를 명확하게 알 수 있고 디버깅에 용이하지만 처리속도에서 단점이 생김

- FIFO를 사용하여 이벤트 발생하거나 추가된 리소스에 대해 앞단에 배치될 수 있도록 함

  ex) 게시판 서비스의 경우 공지사항이나 새로운 글이 앞단에 먼저 보이게 배치

- SQS의 대기열 증가, 처리속도 등을 참조해 스케일 아웃이 가능할 것으로 예상

 

IGW를 사용하는 이유

인터넷과의 연결: IGW를 통해 VPC 내의 인스턴 인터넷 간의 통신이 가능

보안: VPC내의 인스턴스들을  보안그룹과 ACL 등으로 보호 가능

확장성: IGW는 인스턴스 수나 트래픽 증가에 따른 수평확장이 가능

비용: 다른 서비스에서 비해 인터넷으로 데이터를 전송하는데 드는 비용이 효율적, VPC를 사용하면 인프라 관리 비용도 절감 가능

- ACL은 서브넷 레벨(보안그룹은 인스턴스 레벨)에서 작동하며  수신 및 전송되는 트래픽에 대한 허용 규칙을 구성 보안그룹과 같이 적용하여 보안 향상

 

NAT Gateway를 사용하는 이유

보안: NAT Gateway 에 연결된 프라이빗 서브넷의 인스턴스 들은 퍼블릭 IP를 부여받지 않으므로 외부에서 연결 불가능

비용: 프라이빗 서브넷에서 인터넷에 접근하는 각각의 인스턴스에 퍼블릭 IP를 부여해 직접 접속하는 것보다 비용측면에서 효율적

확장성: NAT Gateway는 수평 확장이 가능

- 결론적으론 비용 측면에서 NAT 인스턴스가 효율적이지만 최소 두 개의 인스턴스 관리가 필요하고 확장성에 불편함이 생김

 

bastion 호스트를 사용하는 이유

nat gateway와 별도로 bastion 호스트를 두어 사용자와 관리자가 각각 다른 경로로 VPC에 접속하도록 하여 네트워크 접근성과 관리성 면에서 이점을 가지도록 함

네트워크 접근성: 각각 다른 경로로 접속하기에 보안성이 향상되고 트래픽 분산으로 인한 효율성도 개선관리성: 사용자와 관리자를 구별하여 로그 추척에 용이하고 관리 복잡도 감소(권한 관리 등)

system manager(원격관리 및 자동화에 이점)와 같은 다른 방안이 있지만 구성에 있어 Bastion host가 ssh 터널링을 통해 접근하기 때문에 쉽다고 인지함

또한 Bastion host의 보안그룹으로 접근 제어가 가능함

 

NAT gateway와 Bastion 호스트를 퍼블릭 서브넷에 두는 이유

고가용성을 위해 퍼블릭 서브넷을 2개 생성하고 NAT gateway와 Bastion 호스트는 인터넷에 연결되는 역할을 함

 

ALB를 사용하는 이유

웹 애플리케이션 서비스이므로 HTTP/HTTPS 요청에 대한 로드밸런싱ECS 서비스 내의 있는 컨테이너 인스턴스들을 로드밸런싱하고 트래픽을 분산하여 네트워크 성능 향상에 기여

동적 포트매핑으로 포트 충돌을 방지하고 애플리케이션을 쉽게 확장하고 배포할 수 있게 함

ECS 서비스에 대한 자동 스케일링 지원 

- ECS 서비스가 늘어나거나 줄어들 때 자동으로 적절한 대상그룹에 할당되도록 해줌

 

Fargate를 사용하는 이유

#ECS의 다양한 배포 옵션중 Fargate를 채택

관리성: EC2 인스턴스처럼 직접 관리할 필요가 없으므로 컨테이너 실행에만 집중 가능

확장성: 컨테이너 단위로 자동으로 스케일링 가능

비용: 서버리스 아키텍처를 사용하므로 인스턴스 운영비용이 절감 됨

 

Aurora를 사용하는 이유

성능: 기존의 mysql 보다 최대 5배 빠른 처리속도, 빠른 응답시간

확장성: 수평확장 가능(쓰기 처리를 처리하는 노드 수를 자동으로 확장)

가용성: 다중AZ를 사용하여 고가용성을 보장, 여러 가용영역에 걸쳐 6개의 복제본 유지

내구성: 자동 복제 및 백업을 지원하여 데이터 손실 방지

# ASM을 연동하여 보안 강화

- 암호 같은 민감 정보를 보다 안전하게 관리

- 애플리케이션 코드 간소화, RDS 데이베이스 암호를 자동으로 로테이션 가능

- 암호화 및 보안정책 관리에 대한 복잡성감소, 운영 간소화

 

ECR을 사용하는 이유

통합: ECR은 다른 AWS 서비스와 통합되어 있어 ECS를 사용하여 ECR 이미지를 간편하게 배포 가능

확장: 필요에 따라 이미지 저장소의 크기를 확장 가능, 저장소를 여러 지역에 복제 가능

 

오픈서치를 사용하는 이유

비용: 오픈서치는 무료 제공되는 오픈소스 소프트웨어

확장성: 분산형 아키텍처로 데이터가 증가해도 수평확장이 가능

다양성: 다양한 데이터 유형 지원

통합성: aws의 클라우드 워치 같은 서비스와 통합이 용이

- 대규모 분산시스템에서 안정적으로 작동하도록 설계되었고 검색 작업을 처리하는데 용이하다는 부분이 있습니다.

하지만 이번 프로젝트에서 처음 써보았기에 오픈 서치의 경우 아직 더 이해가 필요할 것 같다.

 

cloudwatch를 사용하는 이유

통합 모니터링: aws 서비는 cloudwatch와 통합되어 있어 대시보드에서 모든 서비스를 한눈에 볼 수 있음

유연한 모니터링: 다양한 데이터 유형을 수집할 수 있고, 경보를 설정하여 자동화된 조치 가능

자동화된 대응: cloudwatch는 람다와 함께 사용하여 이벤트 기반 작업 자동화를 제공

 

k6를 사용하는 이유

부하테스트는 실제 요구되는 부하를 서비스가 수용할 수 있는지를 확인하기 위한 작업

간편한 사용성: k6는 Go 언어로 작성되어 있고,  간단한 명령어로 테스트 가능

높은 확장성: 여러개의 가상 사용자를 동시에 시뮬레이션 가능

다양한 프로토콜 지원: Web socket, HTTP, gRPC 등CI/CD 연동: 자동화된 성능 테스트 가능

Web socket과 gRPC에 대한 경우에 대해 더 공부가 필요하다.

 

# 내용을 작성하다보니 사용하는 이유라기 보다 각 리소스들의 기능 설명이 된 거 같다...

위의 모든 내용은 AWS 공식문서를 참고하여 작성되었습니다.

 

 

! 트러블 슈팅

1. 게시판 리소스 무한 렌더링 발생

const [viewContent, setViewContent] = useState([]);

useEffect(() => {
  Axios.get('http://localhost:3333/api/get').then((response) => {
    setViewContent(response.data);
  });
}, [viewContent]);

다음과 같이 실행했을 때 무한루프가 발생하는 오류

useeffect의 훅이 viewContent의 state가 변경될때마다 실행되므로 get 요청이 계속해서 발생하고 이로 인해 무한루프가 발생하여 컴포넌트가 계속해서 재렌더링 되고 있음

useeffect가 한번만 실행되도록 [viewContent]를 [] 이나 [setViewContent]로 변경하여 해결

 

 

 

2. 백엔드를 ECS로 배포하는 과정에서 반복된 배포실패 발생

 

모듈을 전부 설치해주었지만 대상그룹이 unhealthy로 인해 계속 재배포를 하면서 반복적인 에러가 발생중이다.

배포실패를 계속하는 이유로 VPC를 콘솔에서 생성된 라우팅 테이블의 연결에서 terraform 코드의 누락으로 NAT gateway와의 연결이 존재하지않아 발생한 문제였다 NAT gateway 연결을 해준뒤 업데이트하면 배포가 성공하는 것을 볼 수 있다.

 

 

 

3. 배포 완료 후 백엔드 서버에 접속이 거부되는 상태

ecs fargate로 배포한 후 로드밸런서 DNS name으로 접속해 보았지만 연결이 되지 않는 상황이다.

 

대상그룹에 ecs 서버의 3000포트를 리스너로 열어두었지만 http 요청이므로 80 포트를 리스너로 지정

그리고 404 에러를 healthy로 지정해준 뒤 다시 get 요청을 보내면 해결된다.

 

 

4. CloudFront 으로 레코드 생성시 트래픽 라우팅 대상에 리소스가 뜨지 않는 경우

호스팅 영역에 존재하는 CNAME을 CloudFront CNAME에 추가 해주면 리소스를 선택할 수 있다.

그리고 테라폼으로 작성한 Cloudfront에서 원본 도메인 네임이 s3 이름으로 선택되어 있어 s3의 버킷 웹 사이트 엔드포인트와 달라 페이지가 뜨지 않는 경우

#s3 web
resource "aws_s3_bucket_website" "website" {
  bucket = aws_s3_bucket.teamf-FE.id

  index_document = "index.html"
  error_document = "index.html"
}

output "bucket_id" {
  value = aws_s3_bucket.teamf-FE.id
}

output "website_url" {
  value = aws_s3_bucket_website.website_domain
}

#cloudfront
...
  origin {
    domain_name = aws_s3_bucket.teamf-FE.bucket_regional_domain_name
    origin_id   = aws_s3_bucket.teamf-FE.id
...

코드를 다음과 같이 수정한 후 다시 레코드를 생성한다.

그리고 다른 계정에서 구입한 도메인을 ssl 인증서를 이용해 가져와 쓰기 때문에 레코드에 대한 트래픽 라우팅 대상이 새로 만들어진 계정의 값과 다른 것을 알 수 있다.

트래픽 라우팅 대상을 프론트엔드를 배포한 계정의 라우팅 대상들과 일치시킨 뒤 업데이트하면 연결이 되는 것을 확인할 수 있다.

 

5. 결재서와 다른 추가 요금폭탄 발생

 

프로젝트 진행중 주말동안 Aurora Mysql을 사용하던 중 월요일 미팅 시간 과도한 요금이 발생한 것을 인지

본래 사용 목적은 글로벌 팬 사이트를 겨냥한 트래픽 과부하에 대응하고, 빠른 응답 처리를 하기 위해서입니다.

아래 AWS 공식문서에서 발췌한 내용에 따르면 기존의 Mysql보다 5배, postgreSQL보다 3배 빠른 처리량을 지원하고 Aurora mysql의 병렬 쿼리처리로 인해 쿼리 속도를 100배까지 높일 수 있다고 합니다.

하지만 비용 측면에서의 글을 다시 읽어보면

Amazon Aurora는 선수금이 필요하지 않으며, 시작한 인스턴스별로 시간 요금만 지불하면 됩니다. 또한, Amazon Aurora DB 인스턴스 사용을 종료하면 쉽게 삭제할 수 있습니다. 안전상의 조치를 위해 스토리지를 과다 프로비저닝할 필요가 없으며, 실제로 사용한 스토리지에 대해서만 지불합니다.

다른 Aurora 사용자들의 요금 폭탄 사례들을 보며 병렬 쿼리로 인한 Read iops 증가와 같은 대참사는 일어나지 않아서 다행이지만.. 평소 t3 정도의 크기를 사용하다 훨씬 큰 db를 사용하는데 안일했던 자신의 모습을 반성하고 이 일을 계기로 비용 모니터링에 대한 중요성과 왜 다들 비용을 강조하는지 다시 한번 뼈저리게 느꼈다.

 

회고...

11월부터 시작한 긴 프로그램의 끝이라고 생각하니 아쉽고 많은 사람들을 화면과 목소리만으로 컨택했는데도 어느정도 정이 든 것 같다. 파이널 프로젝트를 오면서 머릿속 한켠에서는 생각한대로 서비스를 만들고 구현할 수 있을 줄 알았지만 생각보다 지식이 모자른 부분이 많았고 아키텍처 상 해당 리소스를 쓰는 것이 맞는지에 대한 확신이 들지 않는 부분도 있었다. 하지만 팀원분들이 각자 힘써주시고 다같이 힘을 모은 결과 그래도 어느정도의 완성 수준에는 다다르지 않았나 싶다.

추후 SAA나 다른 자격증을 공부하고 다시 한번 만들어보고 싶은 마음이 크다. 너무너무 아쉽다

그리고 Aurora는 개인계정에서는 다신 쓰지 않고 싶다 근래 모든 결재내역을 통틀어 가장 내기 싫은, 충격먹은 경험이었다 

영어로 장황하게 써서 실수였다고 case를 보냈지만 어떻게 될진 모르겠다. 일단은 배운 점이 있다는 것 만으로 충분하다고 생각해야겠다.

반응형