NAT Gateway 대신 NAT Instance사용
AWS로 시작하는 인프라 구축의 정석
쏙쏙쏙 따라 하며 배우는 AWS 인프라 구축 A to Z 도서구매 사이트(가나다순)[교보문고] [도서11번가] [알라딘] [예스이십사] [인터파크] [쿠팡] 전자책 구매 사이트(가나다순)교보문고 / 구글북스 /
jpub.tistory.com
이라는 책을 읽으며 실습을 하다가 NAT Gateway를 사용해 요금이 부과되는 상황이 생겼다.
프리티어 범주 내에서 NAT Gateway는 무료로 사용되는게 아닌건지 모르고, 실습을 하다가 발생했다. ㅠㅠ
사용하지 않아도 돈을 내야된다. credit을 제공받는 것으로 잘 마무리 되었지만 이번 기회에 NAT Gateway와 그외의 리소스에 대해 더 자세히 알아보고
이에 대한 대안인 NAT Instance로 실습해보고자 한다.
프라이빗 서브넷에 생성된 리소스는 인터넷으로 내보낼 수는 있지만 인터넷에서 접근할 수 없어야 한다.
이런 요구사항을 구현하기 위해 NAT(Natwork address translation)라는 네트워크 주소 변환 시스템이 있다.
NAT 게이트웨이는 생성만 해도 시간당 0.059USD의 비용이 부과되어, 이를 대체하는 NAT Instance로 대체해 구현해보려 한다.
NAT Instance는 ec2인스턴스를 사용해 NAT Gateway 역할을 하도록 만든 것이다.
그럼 bastion host (이하 점프 서버)와 NAT Instance (이하 NAT 서버) 모두 private subnet 내에 있는 ec2에 접근하는 것 같은데 어떤 차이가 있을까?
점프 서버의 트래픽 방향은 사용자 -> 점프 서버 -> private ec2로, 사용자가 private 리소스에 접근하기 위한 진입점이다.
NAT 서버는 private subnet의 리소스가 인터넷으로 나가기 위한 게이트웨이 역할로, 트래픽 방향이 private ec2 -> NAT 서버 -> 인터넷 이다.
즉, NAT 서버에서는
✅ 가능: Private EC2 → NAT Instance → 인터넷
❌ 불가능: 인터넷 → NAT Instance → Private EC2
실습하는 아키텍쳐를 다이어그램으로 그리면 이렇게 된다.
Nginx의 로드밸런서
로드밸런서란?
네트워크나 어플리케이션의 부하를 분산하여 여러 대의 서버가 공평하게 작업을 처리하도록 하는 기술이다.
서버에 트래픽이 몰리면 하나의 서버로는 해당 요청을 처리하기 힘들어져, 여러 대의 서버를 놓고, 요청을 분산시키는 것이 로드 밸런싱이다. 리버스 프록시로 이 방법은 scale out이다.
그렇다면, 로드 밸런싱은 어떤 알고리즘에 트래픽을 분산시킬까?
- Round Robin
- Least Connection
- Ip Hash
우선 라운드 로빈, 운영체제의 프로세스 스케줄링에 자주 사용되는 알고리즘 중 하나이다. 프로세스에게 cpu시간을 time quantum만큼 할당하고 해당 시간이 지나면 강제로 context switch하여 다음 프로세스에게 넘기는 알고리즘이다.
이를 nginx의 라운드로빈에 적용한다면,
upstream backend {
server 10.0.0.1;
server 10.0.0.2;
server 10.0.0.3;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
순서를 기억해서 회전하며 요청을 처리한다. 서버 부하와 무관하게 순서대로 요청하기 때문에 최적의 방법은 아니다.
Least connection, 현재 연결 수가 가장 적은 서버에 요청을 보내는 방식이다. 실시간으로 각 서버에 걸린 연결 수를 추적하고, 가장 여우 있는 서버에 요청을 분산한다. cpu, 메모리 등은 고려하지 않고 오직 '연결 수'만 기준을 두기 때문에 완벽한 방법은 아니다. least connection과 서버별 가중치를 조합할 수도 있다.
upstream backend {
least_conn;
server 10.0.0.1 weight=3;
server 10.0.0.2 weight=1;
}
ip_hash, 클라이언트의 ip주소를 해시해서 항상 같은 서버로 요청을 보내는 방식이다. 같은 사용자의 요청은 항상 같은 백엔드 서버로 전달된다. 로그인 정보등 서버에 저장된 세션 데이터가 유지될 수 있다는 장점이 있다. 다만, 로드 불균형 가능성이 있어 로드 밸런서의 역할을 잘 해내지 못할 수 있다.
ec2 내부에 아래와 같이 설정한뒤,
# 8001 포트 서버 띄우기 (백그라운드 실행)
nohup python3 -m http.server 8001 &
# 8002 포트 서버 띄우기 (백그라운드 실행)
nohup python3 -m http.server 8002 &
nginx default파일에 아래 포트(8001, 8002)를 라운드 로빈 형식으로 설정했다.
upstream backend_servers {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
server {
listen 8080;
location / {
proxy_pass http://backend_servers;
}
}
결과도 번갈아 사용한 것을 볼 수 있다.
k6로 아래 케이스 별로 부하테스트를 해보자.
요청 사용자 수는 10명, 1분 동안 테스트하는 방식으로, 각 포트에 요청된 수를 집계하는 k6가 수행할 js 코드이다.
import http from 'k6/http';
import { check } from 'k6';
import { Counter } from 'k6/metrics';
//서버별 요청 수 집계
let server8001 = new Counter('server_8001_count');
let server8002 = new Counter('server_8002_count');
export const options = {
vus: 10,
duration: '1m',
};
export default function () {
const res = http.get( "http://<ec2 public ip>:8080/");
//응답 본문에서 어떤 서버가 응답했는지
if (res.body.includes('8001')) {
server8001.add(1);
} else if (res.body.includes('8002')) {
server8002.add(1);
}
check(res, {
'status is 200': (r) => r.status === 200,
});
}
1) Round Robin
각 포트마다 요청수가 비슷하게 집계된 것을 볼 수 있다.
2) least connection + 가중치 (8001: weight 10, 8002: weight 2)조합
보통 가중치는 성능이 좋은 서버에 더 높게 둔다고 한다. 확연히 차이가 나는 것을 볼 수 있다. 가중치를 10으로 둔 server 8001포트에서 2배가까이 8002포트보다 더 많은 요청이 간 것을 볼 수 있다.
위 테스트는 같은 ec2에서 돌리는 http.server로 결국 cpu, ram 등 자원을 공유하기 때문에 실제적 성능 차이는 없지만 가중치 비례로 요청 분배가 잘 되는지 확인은 가능했다. 다음에는 진짜로 다른 서버에서 돌려봐야지.