[DB] 데이터베이스 마이그레이션 및 클러스터 설정

레디스 클러스터 설정

0image.png

Redis, MySQL 서비스에서 인스턴스로 마이그레이션하기

기존에는 레디스를 NCP 에서 제공하는 서비스 자체를 사용했기 때문에 굳이 할 필요가 없었지만 레디스 클러스터를 샤딩까지 포함해서 서비스로 빌리면 요금이 어마어마하게 들어가게 된다.

1Redis 요금표

ncp 서버 인스턴스는 사용하지 않고 꺼두면 비용이 절감되는 방식이기 때문에 Redis 서비스를 직접 쓰기보다 서버 인스턴스에서 올려서 사용하는것이 비용 측면에서 이점이 많을 것 같아서 사용하던 MySQL 과 Redis 를 내리고 전부 서버 인스턴스로 올리고 개발/리팩토링 하려고 한다.

Public Subnet, Private Subnet

Redis 나 MySQL 은 모두가 접근할 수 있는 Public 으로 접근가능하게 하기 보다는, Private Subnet 으로 관리하면서 같은 VPC 에 있는 인스턴스에서 접근하도록 하는 것이 보안에 훨씬 좋다.

2image.png

실제 서버들이 배포되는 public subnet 인 web22-subnet-all 과, Redis 와 MySQL 이 돌아갈 private subnet 으로 분리했다.

NCP 인스턴스 생성

우선 새로운 NCP 인스턴스를 하나 생성했다.

현재는 가장 싼 단계로 하나를 생성하고, Redis 와 MySQL 을 하나의 인스턴스에 설치해서 운용할 계획이다.

이렇게되면 인스턴스 하나가 문제가 생기면 두 개의 DB가 전부 동작할 수 없다는 매우 큰 단점을 가지게 된다. 그렇기 때문에 나중에 반드시 DB 를 분리하는 것이 좋다.

지금은 인스턴스의 비용을 최소화하면서 리팩토링하고 싶어서 위와 같은 방식을 선택했다.

이후에는 위에서 만들어둔 private subnet 에 할당해주면 된다.

Private Subnet 이다보니까 외부와 통신이 아예 안되어야 하는데 신기하게 sudo apt update 같은 명령어가 동작했다.

3image.png

apt 저장소가 http://repo.ncloud.com/ubuntu 로 되어있고 아마 이 주소는 내부망에 포함되는 모양이다.

내부망이 맞는지 한 번 확인해보자.

nslookup repo.ncloud.com

4image.png

내부망(사설망) 이라면 10.x.x.x, 192.168.x.x, 172.16.x.x~172.31.x.x와 같은 사설 IP 대역이어야 하는데 169.254.xxx.xxx 였다.

그러면 169.254.xxx.xxx 는 무슨 대역인가 하니

bash
169.254.xxx.xxx 대역의 IP 주소는 **Link-Local Address(링크 로컬 주소)**라고 불리며, 
네트워크 설정 시 DHCP 서버를 통해 IP를 받지 못할 때 자동으로 할당되는 IP 주소입니다. 
AWS/NCP 환경에서는 이 IP 대역이 AWS/NCP 내부 시스템과의 통신을 위한 특수 주소로 사용되기도 합니다.

ip route show 로 라우팅을 확인해보면

5image.png

169.254.x.x via 192.168.1.1 dev eth0 … 와 같은 라우팅이 보인다.

169.254.169.53 은 eth0 인터페이스 를 통해서 간다.

이 링크 로컬 주소는 네트워크 장치 단에서 이루어진다.

curl http://169.254.169.254/latest/meta-data/ 를 통해서 인스턴스 메타데이터도 볼 수가 있다.

당연하게도 외부로는 ping 이나 wget/curl 은 안된다.

자세한 내용은 ncp 가이드가 있다.

https://guide.ncloud-docs.com/docs/linux-os-repository-check

NAT Gateway

NCP 가 Repository 를 제공해주다보니 redis 를 설치할 수 있긴 하다. 대신 최신 버전은 없을 수도 있다.

만약 최신 버전이나 NCP Repository 에 없는 버전을 설치하고 싶다면 NAT Gateway 가 필요하다.

NCP 에서 NAT Gateway 를 사용하고 싶다면

  1. NAT Gateway 용 Subnet 생성

6image.png

  1. NAT Gateway 생성

7image.png

  1. Private Subnet 에 Route Table 설정

8image.png

을 통해서 Private Subnet 에 NAT 게이트웨이를 사용할 수 있다.

Redis 설치 및 Redis Cluster

원하는 버전의 Redis 를 설치하고 난 후에는 Redis Cluster 설정을 해야한다.

일단은 redis master 3 대에 각각 레플리카를 1개씩 설정해보자.

bash
port {PORT}
maxmemory {MAX_MEMORY}mb 
maxmemory-policy volatile-lru
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip {ip}
appendonly yes
bind 0.0.0.0

포트와 maxmemory 는 원하는대로 설정하면 된다.

maxmemory-policy 는 메모리를 비워줄 때 어떤 기준으로 비울지를 결정한다.

정책 대상 삭제 기준 적합한 사용 사례
noeviction 전체 키 삭제하지 않음 영구 데이터 저장
allkeys-lru 전체 키 LRU(오래 사용되지 않은 키) 캐시 시스템
volatile-lru TTL 설정된 키 LRU(오래 사용되지 않은 키) TTL 기반 캐시 시스템
allkeys-random 전체 키 랜덤 데이터 접근 패턴이 불규칙할 때
volatile-random TTL 설정된 키 랜덤 TTL 기반 캐시에 랜덤 제거
volatile-ttl TTL 설정된 키 TTL이 가장 짧은 키 TTL이 중요한 시간 기반 캐시

눈 여겨 볼 만한 설정값은cluster-announce-ip 인데,

Redis 클러스터는 클라이언트가 연결할 때, 노드 간에 데이터 슬롯을 분배하고 어떤 노드에 특정 키가 있는지를 알려준다.

cluster-announce-ip는 노드가 클라이언트에게 자신을 알릴 때 사용하는 외부에 노출되는 IP 주소이다.

만약 노드가 데이터를 가지고 있지 않다면,

  1. Docker 컨테이너 내부의 서버는 Redis 노드에 접속 후 슬롯 이동 명령을 받는다.
  2. Redis 클러스터가 기본적으로 bind된 내부 IP 주소를 클라이언트에 알려준다.
  3. 만약 레디스가 cluster-announce-ip를 설정하지 않았다면, 레디스 노드는 Docker 컨테이너에게 내부 IP(예: 127.0.0.1 또는 172.x.x.x)를 반환할 수 있다.
  4. Docker 컨테이너는 외부 네트워크에서 해당 내부 IP로 접근할 수 없기 때문에 연결이 끊어진다.

위와 같은 과정으로 레디스 연결이 원활하게 되지 않을 수 있다.