AWS HA(High Availability) Architecture 구축 기록

taehee kim·2023년 1월 17일
0

1. 기술 적용 배경

  • 서비스 운영중 드물게 WAS가 실행되고 있는 EC2가 종료되는 문제가 발생했습니다.
    이 경우 현재 아키텍처에서는 fail over할 방법이 없기 때문에 Availability를 높이는 방향의 아키텍처 설계를 구축하게 되었습니다.

2. Architecture Design point

  • High Availavility
    • 적어도 둘 이상의 Availavility Zone에 instance가 분포 하도록 합니다.
    • Application Load Balancer를 통해 부하를 WAS로 향하는 요청을 분산시킵니다.
    • Auto Scaling Group을 적용하고 WAS의 Scaling 정책은 Dynamic Scaling cpu50% 이상인 경우로 적용했습니다..
    • NAT Gateway의 경우 각각의 Availability Zone에 적어도 하나 위치시킵니다.
    • RDS의 경우 Multi-az로 설정 하고 하나의 RDS만 Active하도록 설정합니다
      • failover를 위해 stand by DB를 다른 Availability zone에 설정합니다.
      • 여러 RDS를 Active로 설정해도 DB Storage 사이에 병목이 발생할 수 있기 때문에 성능 향상을 보장할 수 없습니다. 조회 부하가 크다면 Replication을 고려하는 것이 낫습니다.
  • AWS VPC Custom설정(IGW, NAT Gateway, Public/Private/DB Subnet, Route Table)
    • 보안성 강화를 위한 조치
      • WAS를 실행중인 EC2
        • Private Subnet에 위치하게 하여 외부 Network에서의 직접 접근을 방지합니다.
        • NAT gateway를 Route table에 추가하여 EC2에서 외부로 요청 시작(주로 외부 API호출 목적)은 가능하게 합니다.
      • RDS
        • DB Subnet에 위치하게 하여 외부 Network에서의 직접 접근을 방지합니다
        • Private Subnet과의 차이점은 DB Subnet은 NAT Gateway와 연결하지 않습니다.
          • DB에서 외부로 먼저 요청할 일이 없기 때문입니다.
      • Bastion Host
        • Public Subnet에 위치하여 EC2, RDS로 SSH, 3306포트로 접속할 수 있게합니다.
        • Private Subnet에 주요 컴포넌트들을 위치시키고 개발자는 Bastion Host를 통해서 접근합니다.
        • SSH포트만 열어두어야합니다.
  • Load Balancer, Auto Scaling Group
    • Load Balancer
      • 외부에서 Web Application Server로 들어오는 요청을 앞단에서 받아 EC2에 적절하게 부하를 분산할 수 있습니다.
      • HTTPS 인증을 수행하고 SSL Termination을 수행하여 WAS부터 내부 통신을 할 때에 HTTP로 내부 통신을 수행함으로서 성능을 개선할 수 있습니다.
    • Auto Scaling Group
      • EC2 Health Check를 통해 비정상적인 EC2 발견시 Termination 합니다.
      • CloudWatch를 통해 서버 부하를 체크하여(예. Dynamic Scaling CPU 사용률 50퍼이상) 필요 시 등록해 놓은 Launch Template을 통해 자동 EC2를 배포할 수 있습니다.
      • 트래픽이 몰리거나 EC2내 장애가 발생했을때 기본적인 자동 Scaling이 가능합니다.
  • MSK(Kafka)
    • 서로 다른 Availability zone에 적어도 하나의 Broker가 존재하도록 하고 insync replicas를 2이상으로 설정하여 데이터를 이중화합니다.
  • Elasticache(Redis)
    • cluster mode를 활용합니다. cluster mode에서 master node와 slave node가 각각 1, 2개씩(원래 redis cluster에서는 master가 최소 3대이상 있어야 합니다.) 존재하게 되며 master node의 경우 sharding을 통해 추가할 수 있습니다.
  • Route53, Certificate Manger
    • Route53을 통해 Domain을 제공 받습니다.
    • AWS Certificate Manger를 통해 SSL 인증서를 발급 받았습니다.
  • Nginx
    • Nginx를 Reverse Proxy로 활용합니다.
    • WAS 서버가 정적 파일을 직접 다루는것은 자원 낭비이기 때문에 Web Server를 앞단에 두어 처리하게 하는것이 바람직하다고 판단했습니다.
    • 추가적으로 캐싱, 로드밸런싱, 보안 강화 등의 역할을 할 수 있고 아키텍처 디자인 면에서 유연성을 확보할 수 있습니다.
    • Docker Compose를 활용하여 EC2내부에서 컴포넌트들을 Container화할 계획이 있습니다.

3. HA Architecture 구현 상세

3-1. VPC

  • VPC는 virtual private cloud의 약자로 AWS서비스 사용할 내에서 private network를 의미한다고 생각하면 된다.
  • 보통 Default VPC가 존재하는데 이걸 그대로 사용하는 것 보다는 Custom하여 활용하는 것이 좋다.

3-1-1. VPC 생성

  • Name tag를 원하는 이름으로 설정해준다.
  • CIDR Block은 VPC내에서 사용할 private IP 범위라고 볼 수 있다.
    • 10.0.0.0/16으로 설정하였다.
    • IPv6는 사용하지 않는것으로 설정한다.
  • Tenancy는 VPC내부에서 사용할 Instance들을 부여 받을 때 따로 격리시킨것을 받을 지 공유되는것을 받을 지 여부이다. 격리시키면 비용이 매우 비싸기 때문에 Default로 설정해준다.

3-2. VPC Subnet

  • VPC Subnet이란 VPC Network를 분할하여 정의하는 개념으로 생각할 수 있다.
  • Public Subnet, Private Subnet, DB Subnet등으로 분리하여 각 Subnet 성격에 맞게 설정해줄 수 있으며 VPC CIDR Block 범위내에서 Subnet의 CIDR Block을 설정하여 private IP 주소범위를 지정해줄 수 있다.
  • Subnet의 CIDR Block에서 5개 주소는 이미 예약되어있다.
    • 10.0.0.0/24 CIDR Block subnet에서
    • 10.0.0.0 - network 주소
    • 10.0.0.1 - VPC router주소
    • 10.0.0.2 - AWS DNS 주소
    • 10.0.0.3 - 아직 사용 되지는 않지만 추후 이용될 것을 대비하여 예약해놓은 주소
    • 10.0.0.255 - broadcast 주소

3-2-1. VPC Subnet 생성

  • Subnet의 종류는 Private Subnet과 Public Subnet으로 구분할 것이며 Availability zone 3곳에 각각 하나씩 분포하도록 구성한다.

  • Private Subnet은 주소가 더 많이 필요하기 때문에 Netmask 크기를 20으로 하고 Public Subnet의 경우 24로 한다.

  • 각각의 Subnet의 CIDR Block이 겹치지 않도록 주의 한다.

  • Public Subnet의 경우 Subnet Settings에서

    • Enable auto-assign public IPv4 address 를 체크해준다.
    • 해당 옵션을 활성화 할 경우 EC2 생성시 public ip 할당하는 것을 Default로 설정할 수 있게 된다.

3-3. IGW(Internet Gateway) & Route Tables

  • IGW
    • IGW는 VPC내의 Instance가 외부 인터넷과 통신할 수 있도록 하며 VPC하나당 하나만 설정할 수 있다.
    • Public IP가 있더라도 IGW가 없다면 외부에서 접근할 수 없다.
    • 수평적 확장 및 가용성이 뛰어나다.
    • IGW생성이후에 추가적으로 Route tables에 IGW로 라우팅을 설정해야한다.
  • Route Tables
    • Route table이란 특정 Subnet을 대상으로 특정 ip주소로 통신이 지정된 경우 route 규칙을 지정하는 table이다.

3-3-1. IGW 생성 및 Public Route table 설정

  • IGW
    • IGW를 생성한다.
    • 생성했던 VPC에 IGW를 attach한다.
  • Route table
    • Public Subnet route table생성한다.
    • Public Subnet route table의 Subnet associations에 Public Subnet을 추가해준다.
    • route table 생성후에 route 규칙을 보면 다음과 같은 규칙이 자동적으로 추가 되어있음을 확인할 수 있다.
    • 이 규칙은 VPC내에 사설 ip주소의 경우 local로 route시키는 조건이다.
    • 외부 인터넷으로 route시키는 규칙을 추가해주어야한다.
    • 규칙은 먼저 쓰인 것이 우선순위가 더 높으므로 뒤에 규칙을 지정해야한다.
    • Public Route table의 경우 0.0.0.0 의 모든 ip트래픽을 IGW로 route하는 규칙을 추가한다.

3-4. Private Subnet (Bastion Host & Nat Gateway)

  • Private Subnet의 경우 public Ip가 없기 때문에 기본적으로 외부와 통신이 불가능하고 특수한 경로를 통해서만 가능하도록 설정한다.

3-4-1. Bastion Host

  • Bastion Host는 public Subnet에 있는 EC2 Instance이므로 private Subnet에 있는 EC2, RDS, ElastiCache, MSK등에 접속 가능하다.
  • Bastion Host의 보안이 뚫릴 경우 매우 위험할 수 있기 때문에 Security Group의 경우 집이나 회사와 같은 특정 IP를 SSH(22)에 대해서만 추가하는 것이 보안상 유리하다.

3-4-2. Nat Gateway

  • Nat Gateway는 public IP가 없는 Instance가 인터넷에 요청을 보낼 수 있게 해준다.
  • IGW의 경우는 public IP가 있는 경우에 인터넷에 요청을 보낼 수 있다.
  • 정확한 차이는 다음 링크를 통해 확인할 수 있다.
  • Private Subnet의 EC2 Instance의 경우에 외부로 요청을 보내야하는 경우(외부 API호출이나 메일 발송)가 있기 때문에 route 설정을 해주어야한다.
  • Nat gateway의 경우 다른 instance들과 마찬가지로 가용성을 위해 적어도 둘 이상의 Availability zone에 위치해야한다.
  • BandWidth등을 스스로 조절하기 때문에 가용성이 높다.

3-4-3. Nat Gateway 설정 과정.

  • 적어도 두개의 Availability Zone의 public subnet 각각에 Nat Gateway를 각각 하나씩 생성한다. (이 글에서는 PublicSubnetA, PublicSubnetC)
  • Connectivity type을 public으로 설정한다.
    • Create Elastic IP하여 새로 eip를 생성해준다.
  • PrivateRouteTable 또한 Nat Gateway개수만큼 생성하고 subnet associations에서 Availability zone에 속한 private subnet을 지정해준다.(어처피 availability zone fail시 instance들도 fail하기 때문에 cross-zone 하지 않아도 됨.)
  • route에서 0.0.0.0 이 Nat Gateway로 가도록 설정해주는데 각각 다른 Nat Gateway로 설정해준다.
  • 3개의 RouteTable이 생성됨을 확인할 수 있다.

3-2. Elastic Load Balancer

  • Local balancer란 Backend System의 전면에 위치하면서 사용자 요청을 받아들이고 여러 instance에게 요청을 분배해주는 역할을 하는 컴포넌트이다.
  • DNS를 지정하여 domain name을 지정할 수 있고 HTTPS SSL Termination을 대리수행할 수 있다.
  • public에 위치하면서 Private Subnet에 위치한 Instance에게 요청을 전달 할 수 있다.
  • AWS에는 CLB, NLB, ALB, GWLB등의 종류가 있으며 이글에서는 ALB(Application Load
    Balancer)를 사용한다.

3-2-1. Load Balancing Algorithm

  • Round Robin: Instance 들에게 돌아가면서 요청을 할당한다.
    • 가중 Round Robin: 가중치에 따라 Instance에게 요청을 할당한다.
  • Hash: 요청 내의 IP, Request Uri의 Hash 값을 구해서 Instance를 대응해 준다.
  • Least Connection: 현재 연결이 가장 적은 Instance에 대응해 준다.
  • Least Response Time: 응답 시간이 가장 적은것으로 통계적으로 판단되는 Instance에 대응해 준다.

3-2-2. Health Check

  • 특정 uri, port를 지정하여 Health Check를 하도록 설정하면 연결된 Instance들이 정상적으로 동작하는 지를 설정된 요청지에서 200(OK)응답이 오는지 보고 확인할 수 있다.
  • Health Check간격이나 몇번 연속해서 잘못된 응답이 올 경우에 문제가 있는 EC2로 판단할 것인지를 정할 수 있고 문제가 있는것으로 판단 된 경우 load balancer가 요청을 제공해주지 않는다.

3-2-3. L4 vs L7 Load balancer

  • L4 즉 Transport layer 혹은 L7 Application layer까지의 정보를 바탕으로 balancing을 수행한다.
  • 여기서 생기는 가장 큰 차이점은 L7의 경우 Https 프로토콜에 의한 복호화 과정을 수행할 수 있고 또 해야만 한다는 점이다.
    • 이에 따른 장점은 SSLTermination을 수행할 수 있고 이후의 흐름에서 Http만으로 통신할 수 있도록 할 수 있다.
    • 또한, Http 요청 내용을 활용할 수 있기 때문에 이를 바탕으로 request uri, cookie등의 정보도 활용하여 Load Balancing을 진행할 수 있다.
    • 단점은 복호화라는 것 자체에서 overhead가 발생한다는 점이다.
    • L4의 경우 패킷을 복호화 하지않고 IP, Port, Mac Address 정보만으로도 충분히 활용 가능하기 때문에 복호화에 의한 overhead가 발생하지 않는다.
    • AWS에서 NLB(L4)의 Latency 는 ~100ms정도인 반면에 ALB(L7)의 Latency는 ~400ms로 알려져있다.

3-2-4. AWS ELB 설정 과정

설정 시 주요 결정 사항들

  • L4 vs L7
    • L7인 Application Load Balancer를 활용하는 것이 적합하다고 판단하였다.
      • 이유는 NLB를 선택하여 Https 복호화를 수행하지 않아 성능 향상이 부분적으로 이루어 질 수 있다 하더라도 어처피 이 이후의 서버단 어딘가에서 SSL Termination이 이루어져야 하기 때문이다.
      • 기존 배포의 경우 EC2내의 Reverse Proxy인 Nginx에서 이 역할을 수행하고 있었는데 ALB를 선택할 경우 Nginx가 이 역할을 수행하지 않아도 되기 때문에 여러 Instance에서 중복된 로직을 Application Load Balancer에서 응집해서 수행할 수 있다는 장점이 있다.

설정 과정

  • ALB 생성 선택.
    • Internet Facing

    • Security Group 생성

      • Inbound Rule에서 프론트엔드 서버에 대해서만 허용한다.
      • SSH 접속은 Bastion Host를 통해 이루어지기 때문에 허용할 필요가 없다.
    • subnet의 경우 Public subnet을 둘 이상을 선택한다.

      • Subnet은 ALB가 위치할 곳을 의미하므로 꼭 IGW가 Routing이 되어있는 Public Subnet으로 설정해야한다.
      • Target Group의 Instance가 위치해 있는 Availability 존에 적어도 하나 존재해야 해당 Instance에 접근할 수 있다.
    • Listener-target group 생성

      • Listner의 프로토콜과 포트는 Load Balancer로 들어오는 요청을 의미하며 이 요청을 target group으로 어떻게 전달해줄지를 의미한다.

        • HTTPS 프로토콜을 사용할 것이기 때문에 HTTPS 443으로 선택한다.
        • Target Group을 선택하고 Action에서 Forward를 선택한다. 해당 Instance의 프로토콜은 SSL Termination을 이미진행했으므로 Http를 선택한다.
      • 추후에 ASG를 생성하여 target group으로 설정할 것이다.

DNS + HTTPS (AWS Certificate Manager + Route 53)

  • Route 53을 통해 도메인을 발급받는다(보통 일년에 12달러정도의 요금이 발생하므로 무료 도메인을 외부에서 발급받아서 사용해도된다.)
  • 생성된 Hosted Zone에서 Record를 생성하고 A record, Alias를 선택한 후 Load balancer를 선택하여 도메인 주소를 발급해준다.
  • ACM에서 해당 도메인 주소에 SSL 인증서를 request하고 인증 과정을 거치면 HTTPS 구축까지 완료된다.

3-3. Auto Scaling Group

3-3-1. Launch Template 생성

  • ASG에서 EC2 최초 실행 시 실행할 Template이다.
  • 기존에 설정 해놓은 AMI(java11, code-deploy-agent, host, timezone설정등이 이미 되어있음)를 활용한다.
  • Advanced Userdata에 EC2실행시 바로 실행해줄 스크립트를 작성해준다.
    • 기본적으로 프로세스들이 정지해있는 상태이기 때문에 실행시켜주는 내용이 들어가야한다.
#!/bin/bash
mkdir /home/ec2-user/test
sudo systemctl restart nginx
sudo service codedeploy-agent start
nohup java -jar /home/ec2-user/app/42Partner-Backend/module-api/build/libs/module-api-0.0.1-SNAPSHOT.jar -Dspring.profile.active=prod > /home/ec2-user/app/42Partner-Backend/log-api.txt
  • Availability zone은 EC2 실행 시 다양하게 배포되어야 하는점을 고려하여 설정하지 않는다.

3-3-2. ASG 생성

  • Launch Template을 등록해준다.
  • EC2가 배포될 Subnet을 선택해야하는데 Private Subnet중 2 이상을 선택해주면 된다.
  • load balancing 옵션에서 Attach to an existing load balancer를 선택하고 load balancer target group을 선택한다.
  • Health Check 에서 ELB도 포함 시켜준다.
  • Group size에서 관리될 instance 개수를 조절할 수 있다.
    • minimun은 최소 개수(2)
    • desired(2)
    • Maximum은 최대 개수(2)

3-4. RDS(Relational Database Service)

  • 관계형 데이터 베이스를 AWS에서 관리해주는 형태로 사용할 수 있는 서비스이다.

3-4-1. RDS High Availability(Clustering vs Replication)

  • 관계형 데이터베이스의 가용성과 확장성을 증가시키는 방법은 크게 두 가지가 있다.
  • 설명에 앞서 데이터베이스는 DB Server와 DB Storage로 구성되어있다는 점을 먼저 알고 있어야한다.
    • DB Server는 실제 동작하는 프로세스로 DB 쿼리문등을 해석하여 DB Storage에서 적절한 데이터를 조작하는 일을 수행한다.
    • DB Storage는 SSD내에 데이터를 보관하는 저장소이다.

Clustering

  • Clustering 은 하나의 DB Storage에 DB Server를 둘 이상 구성하는 경우를 말한다.
  • DB 서버가 둘 이상이기 때문에 하나의 DB 서버가 죽었을 때 다른 DB서버로 대체할 수 있다는 장점이 있다.
  • Active-Active, Active-StandBy 구조가 있는데 차이점은 다음과 같다.
    • Active-Active의 경우 여러 DB Server가 모두 활성화 되고 있는 상태로 DB처리 속도를 더 빠르게 만들 수 있으며 failover가 매우 빠르게 이루어질 수 있다는 장점이 있따.
      • 하지만 DB Storage는 하나밖에 없기 때문에 I/O에서 병목이 발생할 수 있으므로 성능 향상이 된다는 보장이 없고 이런 경우 성능 향상을 위해서는 이후에 설명할 Replication을 활용하거나 Standby로 구성하는 것이 나을 수 있다.
    • Active-Standby는 하나의 DB Server만 활성화 시키고 나머지 DB Server는 failover하기 위해 대기하는 형태로 구성하는 방법이다.
      • 실제 동작하는 DB Server는 한대 이기 때문에 성능향상은 이루어지지 않는다.

Replication

  • Replication은 DB Server와 DB Storage를 모두 여러대 두는 방식이며 Master 와 Slave node로 분리하여 관리한다.
  • 이때, Master node는 sharding을 하지 않는 다면 단 한 대만 존재하고 Slave node는 여러 대 존재할 수 있다.
  • Master node는 CRUD 모든 작업이 가능한 반면, Slave node는 Read만 수행할 수 있다.
    • 일반적인 application의 경우 수정보다는 조회가 많은 부하를 차지하기 때문에 이 경우 Slave node를 Replication을 통해 늘려서 DB를 수평적으로 확장할 수 있다.
  • Master node에 변경이 일어날 경우 Slave node에 비동기적으로 데이터 복제가 비동기적으로 발생한다.
    • 비동기적으로 복제가 발생하기 때문에 Slave node와 Master node의 데이터 일관성이 깨지는 문제가 발생한다.
    • Spring에서 @Transactional(readOnly=True)옵션을 활용하면 이 경우 Slave node로 요청이 간다.
    • 그렇지 않은 경우에는 조회와 변경이 동시에 일어나고 이 경우 실시간 데이터 일관성이 중요하기 때문에 Master node에서 작업이 이루어지도록 되어있다.

3-4-2. AWS RDS 생성

Multi-AZ-DB-Instance vs Multi-AZ-DB-Cluster

  • AWS에서는 RDS 생성 시 single instance, Multi-AZ-DB-Instance, Multi-AZ-DB-Cluster 세 옵션에서 선택할 수 있다.
    • Single Instance는 말그대로 DB를 하나만 생성하는 경우이다.
    • Multi-AZ-DB-Instance의 설명을 읽어보면 Read Replica를 제공하지는 않는다고 되어있다. 위에서 설명한 RDB Clustering에 해당한다고 볼 수 있다.
    • Multi-AZ-DB-Cluster는 Read Replica를 제공한다고 되어있으며 이름은 Cluster이지만 실제로는 Replication이라고 이해하면 된다.
  • 필자는 Multi-AZ-DB-Instance를 선택하기로 결정하였다.
    • 이유는 HA가 주 목적이기 때문에 Clustering만으로도 충분하며 Multi-AZ-DB-Cluster의 경우 고성능의 RDS옵션을 선택해야만 하기 때문이다.

DB Parameter Group

  • RDB의 환경 변수등을 설정해 줄 수 있는 설정이다. 다음 변수들에 대해서 설정해주면 된다.
    • time_zone
      • Asia/Seoul
    • character_set*
      • utf8mb4
    • collation*
      • utf8mb4_general_ci
    • max_connetion
      • 실제 배포해보고 테스트 후 결정.
  • utf8mb4는 이모티콘이 가능한 문자 타입이다.

Enhanced Monitoring

  • 이 옵션을 켤 경우에 추가 요금이 나올 수 있는데 필자는 성능에 대한 모니터링을 할 것 이기 때문에 켜주었다.
  • Granularity로 모니터링할 시간 간격을 지정할 수 있다.

RDS Type

Security Group

  • 3306포트 ASG에 속하는 EC2의 보안 그룹에 대해서 허용해준다.
  • Bastion host를 추가적으로 허용하여 Client접속을 할 수 있도록 설정한다.

3-5.AWS Elasticache

  • Elasticache는 AWS 의 Solution으로 Redis, Memcached두 종류의 분산 캐리를 제공한다.
  • 필자는 Redis를 사용할 것이며 이유는 Redis에서 제공하는 자료구조로 인한 개발의 편의성, 백업 가능 여부 때문이다.
  • Redis는 In-memory Single Thread기반 key-value NoSQL Database로 RDB와 차이점이 있지만 기본적으로 Backup기능과 Replication기능을 제공하여 High Availability와 Scalability를 높일 수 있다.

3-5-1. Redis 기본 개념

Redis RDB와의 차이점

3-5-2. Redis 백업

Redis Backup(RDB vs AOF)

3-5-3. Redis Replication

Redis Replication

3-5-4. AWS Elasticache설정

  • 이전의 블로그 글에서 Redis 관련 내용을 정리해 놓은 내용을 위에서 링크로 남겨두었다.

Cluster-mode vs disabled

  • Cluster-mode는 Redis Clustering을 의미하고 disabled는 Sharding을 지원하지 않고 마스터가 1개인 구조를 의미한다.
  • 필자는 Cluster-mode를 선택하였다.

3-5. Kafka AWS MSK

카프카 기본 개념과 구축 포스트

profile
Fail Fast

1개의 댓글

comment-user-thumbnail
2023년 8월 10일

개잘하시네요

답글 달기