메뉴

목차

소개

AWS의 Private Subnet에 전개된 Mysql RDS를 외부에서 접근해야 할 일이 생겼다. 어떤 방법이 있을지 나열해보자. RDS는 개인적인 목적으로 사용하고 있는 거라서, 저렴하고 간단한 방법을 선택하기를 원했다. 프러덕트 환경이라면 VPN을 설치해야 하는게 맞겠으나 귀찮고 비싼 방법이라서 제외 했다. 배스천 호스트는 간단한 방법이지만 비용이 추가되기 때문에 제외했다.

SSH tunnel은 기존에 사용하고 있는 EC2 인스턴스와 SSH를 이용하면 되니, 비용이 추가되지도 않고 간단하게 적용할 수 있는 툴이다. 문제는 "나만 접근"하는게 아니고 "다른 사람"도 접근하도록 해야 한다는 점이다. 나는 리눅스 환경에 익숙하고 SSH 관련된 기술들을 일상적으로 사용하니 간단한 문제이지만 그렇지 않은 사람에게는 간단한 이슈가 아니다. 추가적인 학습 없이 기존에 사용하던 mysql client를 이용해서 자연스럽게 접근할 수 있는 환경을 만들고 싶었다.

그리하여 NginX를 설치하여 TCP 로드밸런싱을 하기로 했다.

NginX TCP 및 UDP 로드밸런싱

로드밸런싱은 네트워크 트래픽을 여러 서버에 효율적으로 분산하는 것을 말한다. NginX는 HTTP 프로토콜 뿐만 아니라 TCP(Transmission Control Protocol)과 UDP 트래픽을 로드밸런싱 할 수 있다.

리버스 프록시 구성

리버스 프록시는 클라이언트의 요청을 받아서 내부에 있는 서버로 전달하는 하는 것을 말한다. 외부에서 내부로 역방향으로 프록시 하기 때문에 "리버스 프록시(혹은 역방향 프록시)라고 한다. 이 시나리오에서는 MySQL 클라이언트가 3306 포트로 연결을 요청하면 RDS 서버로 연결을 프록시 하도록 NginX 설정을 변경해야 한다.

NginX 설정파일을 열어서 작업을 한다. 우분투 리눅스의 경우 /etc/nginx/nginx.conf 를 작업하면 된다.

최상위 stream { }블록을 만든다. 여기에 리버스 프록시 설정을 구성하면 된다.
stream {
}

server{ } 블록에 수신(listen)할 IP주소 혹은 포트번호를 설정한다. MySQL 프록시가 목적이므로 3306을 설정했다.
stream {
    server {
        listen 3306;
        proxy_pass rds_db_backend:
    }
}

다른 서버들로도 프록시를 해야 한다면 server 블록을 여러 개 작성하면 된다.
stream {
    server {
        listen 3306;
        proxy_pass rds_db_backend:3306:
    }
    server {
        listen 4301;
        proxy_pass backend.example.com:4301; 
    }
    server {
        listen 53 udp;
        proxy_pass dns.example.com:53; 
    }
}

upstream group은 로드밸런싱할 타겟 서버의 그룹으로 아래와 같이 만들 수 있다.
stream {
    upstream myservice {
        server 10.5.0.2:8000;
        server 10.5.0.3:8000;
        server 10.5.0.4:8000;
    }
    server {
        listen 3000;
        proxy_pass myservice;
    }
}
3000번으로 들어오는 TCP 트래픽은 myservice upstream에 설정된 3개의 서버들로 로드밸런싱 하겠다는 의미다.

TCP, UDP로의 로드밸런싱 구성

이제 TCP, UDP 로드밸런싱을 위한 필요한 정보들은 모두 수집했다.

로드밸런싱을 구성하기 위해서는

  1. 트래픽 부하가 분산될 업스트림 그룹을 만든다. stream{} 최상위 블록안에 upstream{}블록을 구성하면 된다. mysql db와 dns service를 위한 업스트림 그룹은 아래와 같이 구성 할 수 있을 것이다.
    stream {
        upstream mysql_db_backend {
        }
        upstream dns_service {
        }
    }
2. 업스트림 그룹에 부하를 분산할 서버를 설정한다. 서버의 IP 혹은 도메인 주소와 포트를 설정하면 된다.
    upstream dns_service {
        server dns1.example.com:53;
        server dns2.example.com:53;
        server dns3.example.com:53;
    }
    upstream music_stream_service {
        server 10.5.0.5:8000;
        server 10.5.0.6:8000;
        server 10.5.0.7:8000;
    }
3. 업스트림 그룹에 대한 로드밸런싱 방법을 설정한다. 아래 방법 중 하나를 선택할 수 있다.
  1. 라우드로빈 : 별도로 설정하지 않을 경우 기본적으로 적용된다. 업스트림 그룹에 설정된 서버들에 순차적으로 요청을 분산한다.
  2. 최소연결 : 활성연결수가 가장 적은 서버를 선택한다.
  3. 최소시간 : 평균대시기간이 가장 낮고 활성연결 수가 가장 적은 서버를 선택한다.
  4. 해시 기반 : 사용자가 정의한 키(예 #remote_addr : 소스 IP 주소)를 기반으로 서버를 선택한다.
# 최소연결 시간 기반
upstream stream_backend {
    least_time first_byte;
    server backend1.example.com:12345;
    server backend2.example.com:12345;
    server backend3.example.com:12346;
}

## 해시 기반
upstream stream_backend {
    hash $remote_addr;
    server backend1.example.com:12345;
    server backend2.example.com:12345;
    server backend3.example.com:12346;
}

정리

이렇게 해서 아래와 같이 MySQL 프락시 서버를 완성했다.
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}
stream {
    upstream db {
        server joinc-exampl-1.xxxxxxx.ap-northeast-2.rds.amazonaws.com:3306;
    }
    server {
        listen 3306;
        proxy_pass db;
    }
}