ProxySQL과 route53으로 MySQL 무중단 마이그레이션 및 업그레이드

2024. 11. 11. 00:10데이터베이스

반응형

  

목적

DB 버전을 업그레이드하는 작업은 단순 버전 업그레이드 이상의 주의를 기울여야 할 필요가 있습니다.
특히, 서비스 중단 없이 실시간 세션을 유지한 채로 어플리케이션 추가 배포 없이 업그레이드를 진행하려면 사전에 세심한 설계와 준비가 필수입니다. 이 글은 AWS RDS MySQL 5.7에서 MySQL 8.0으로 무중단 마이그레이션을 위한 ProxySQL과 Route53 활용 사례를 소개하기 위해 작성되었습니다. 단순 DB 한 대만 있는 시나리오가 아닌, 난이도를 높이기 위해 실무 아키텍처를 살짝 가져와봤습니다.
 
 

기술 요구사항(제약사항)

업그레이드
- 현재 운영 중인 DB(MySQL 5.7)를 MySQL 8.0으로 업그레이드하되, 어플리케이션 재배포 없이 중단 없는 무중단 세션 전환.
데이터 일치
- 마이그레이션 과정 중 MySQL 네이티브 binlog 복제를 활용해 데이터의 일관성을 보장.
Route53
- 기존에 gabia에서 구매한 퍼블릭 도메인을 AWS Route53 호스팅 영역에 등록하여 DB의 엔드포인트를 관리. 어플리케이션은 RDS의 실제 엔드포인트가 아닌 Route53 CNAME을 통해 연결되어 있어, 레코드 변경으로 무중단 세션 전환.
ProxySQL 및 NLB
- ProxySQL을 EC2 인스턴스에 설치하고, 고가용성을 위해 EC2 인스턴스를 NLB로 구성하여 IP 변경 시의 위험성을 최소화합니다.
 

이관 시나리오

1. MySQL Binlog replication을 통한 사전 데이터 동기화 (old(5.7) <-> new(8.0))
2. 도메인 구매 및 route53 호스팅 등록 + cname 레코드를 db endpoint로 사전 설정 및 application 배포 설정
3. ec2 에 proxysql 설치 및 hostgroup 등록 및 기존 db(5.7)로 라우팅하도록 설정
4. nlb 생성 및 ec2 매핑
5. route53 cname db endpoint 레코드 value를 nlb endpoint로 변경
6. ProxySQL의 라우팅 설정을 변경하여 5.7 -> 8.0으로 트래픽 라우팅 스위치
 

현재 아키텍처

업그레이드로 인한 무중단 마이그레이션을 최대한 간략하게 설명하기 위해 최소화된 구성 요소만 나열하겠습니다.

현행 DB 아키텍처

 
현행 아키텍처를 표현했습니다. 업그레이드 하려는 대상 DB는 노란색 표시가 되어있는 testDB writer와 reader DB 입니다.
reader 또한 writer와 같은 MySQL 5.7 버전을 사용하고 있을 것이기 때문에 이관 시점에 함께 업그레이드를 수행해야 합니다.
여기서 보아야 할 점은, reader에 물려있는 2개의 구성요소입니다.
 
1. Multi-Source Replication DB(MSR DB)
2. CDC (DMS, DEBEZIUM 등)
 
위의 두 구성요소는 업그레이드 작업 시 실질적인 마이그레이션이 필요하지는 않지만, Binary Log 파일, 오프셋 기반의 Replication으로 엮여있기 때문에 무작정 testDB를 마이그레이션한다면 동기화하는 데이터의 시점이 정확히 맞지 않을 수도 있게 됩니다. 따라서 이관 작업 시에 데이터의 싱크를 함께 맞춰야합니다.

 

추가적으로, reader DB에서는 read_only 파라미터가 ON으로 설정되어있습니다. 이 부분은 추후 ProxySQL에서 인스턴스가 복제본인지를 가름하는 변수이므로 꼭 설정해야 합니다.

기본값은 {TrueIfReplica} 입니다.


 


 

MSR DB가 뭔가요?

 
일반 MySQL Replication은 많이 알고 계실 것이라고 생각합니다. 발생하는 Binary Log 를 통해 하나의 데이터베이스 서버(주 서버, Source)에서 발생한 데이터를 다른 서버(복제 서버, Replica)로 복사하여 데이터의 일관성을 유지하는 기술입니다. 이를 통해 읽기 부하 분산, 데이터 백업, 고가용성 등을 실현할 수 있습니다.
 
MySQL Multi-Source Replication은 조금 더 확장된 MySQL Replication이라고 생각하면 됩니다. 하나의 복제 서버가 여러 개의 주 서버로부터 데이터를 복제하는 방식입니다. 즉, 여러 곳에서 발생하는 데이터를 한 곳으로 통합하여 관리할 수 있습니다. 기존 MySQL Replication이 1:1 관계라면, MSR은 N:1 관계로 복제를 구성하는 기술입니다.
https://dev.mysql.com/doc/refman/8.0/en/replication-multi-source.html

출처: https://nareshmote.wordpress.com/2016/03/21/mysql-5-7-multi-source-replication/

실무에서는 MSR DB를 따로 구축하게 된다면 성능, 비용과 관리 측면에서 큰 이점이 있습니다.
 
- 데이터 통합: MSA 구조의 여러 DB에 흩어진 데이터를 따로 하나의 통합 DB에 적재할 수 있습니다.
- 개발 쿼리 분리: 실제 서비스와 관계없는 개발자의 롱쿼리 등을 분리된 환경에서 실행할 수 있게 되어 HLL 상승으로 인한 성능 저하, 혹은 metadata lock 등의 문제에서 많이 벗어나게 도와줍니다.
- 백업과 아카이빙: 실제 운영 DB에서는 서비스 쿼리 성능과 스토리지 비용 등의 이유로 삭제하지만 비즈니스 요건 상 필요한 데이터를 적재하는 장소로 사용할 수 있습니다.
- 계정 관리 포인트 감소: 개발팀에서 MSR DB에서만 조회를 수행할 수 있게 된다면 각 서비스 DB에 각각 계정을 생성/관리/파기 할 리소스가  절약됩니다. 개발팀 입장에서도 여러 DB 의 URL과 패스워드를 기억하지 않아도 되니 간편합니다.
 
 


 
 
이제 이관 시나리오를 하나씩 자세히 살펴보겠습니다.
 

1. MySQL Binlog replication을 통한 사전 데이터 동기화 (old(5.7) <-> new(8.0))

이관 할 신규 new testDB에서도 기존 데이터를 사용해야하기 때문에, 데이터를 가져와서 old <-> new 간의 데이터를 실시간으로 일치화시켜야 마이그레이션을 진행할 수 있습니다.
AWS RDS 환경에서의 시나리오이기 때문에, new testDB의 초기 데이터를 구성하는 방법은 크게 2가지가 있습니다.
 
1-1. rds 인스턴스 clone (snapshot 생성 및 restore)
1-2. mysqldump 혹은 mysqlshell 등을 사용한 데이터 덤프&로드
 
클라우드 환경이고, 인스턴스의 스토리지 사용 용량이 크다면 논리적 백업보다는 인스턴스의스냅샷 수동 생성 후 restore해서 사용하는 것이 매우 좋은 선택입니다. 
여기에서는 mysqldump를 사용해서 데이터 실시간 동기화를 해보겠습니다.
mysqldump를 이용해서 복제본을 구성할 때 고려해야 할 점이 있습니다. old(5.7) DB에는 여전히 application의 DML이 수행되고 있기 때문에 Binary Log 파일과 position이 계속 변경됩니다. 
 
aws rds mysql 환경에서 --master-data옵션을 사용해서 binary log 의 포지션을 기록하는 것은 불가능합니다. RDS는 관리형 서비스이기 때문에 SUPER 권한을 제공하지 않기 때문입니다.

> mysqldump -uadmin -p -htest-57.cnyugyuqszqs.ap-northeast-2.rds.amazonaws.com \
--single-transaction --set-gtid-purged=OFF --master-data target_db_name1 target_db_name2 > ~/Downloads/dump.sql
WARNING: --master-data is deprecated and will be removed in a future version. Use --source-data instead.
Enter password:
mysqldump: Couldn't execute 'FLUSH TABLES WITH READ LOCK': Access denied for user 'admin'@'%' (using password: YES) (1045)

 
https://repost.aws/ko/knowledge-center/mysqldump-error-rds-mysql-mariadb

 

MySQL 또는 MariaDB용 Amazon RDS에서 mysqldump 오류 해결

MySQL 또는 MariaDB를 실행하는 Amazon Relational Database Service(RDS) DB 인스턴스를 사용하고 있습니다. mysqldump를 사용하여 데이터를 가져오거나 내보낼 때 오류가 발생합니다. 이 오류를 해결하려면 어떻

repost.aws

 
 
 

그렇다면 운영되고 있는 서비스 DB의 binary log를 특정 시점으로 명확하게 고정시킬 수 있을까요?

 
생각나는 몇가지 방법이 있습니다.
A. GTID 사용
B. replica DB의 복제를 '정지'시키고 시점이 고정된 데이터 스냅샷에서 binary log 파일과 포지션을 기반으로 dump&load
C. 복제를 멈추지 않고 binary log 의 시점을 기록, 그 이후 dump&load 한 후(혹은 스냅샷 생성 및 복원) 기록된 시점부터 복제 설정 및 시작
 
에서, 저는 C 방법을 사용해보겠습니다. 편의를 위해 복제 계정은 admin 계정으로 설정하겠습니다. (사전에 binary log는 활성화 되어있어야 합니다. aws rds mysql에서는 자동 백업을 1일 이상으로 설정하면 자동으로 binary log가 활성화됩니다.)
 


 


1. testDB 5.7 reader 에서 binary log의 파일명과 포지션을 조회하여 별도로 기록해둡니다. AWS RDS MySQL은 managed service이기 때문에 실제 사용자나 application에서 DML이 발생하지 않는 connection 0인 상태더라도 AWS의 내부 관리 함수 호출 등으로 binary log 가 지속적으로 rotate되고 증가합니다. 

-- testDB 5.7 reader
mysql> show master status;
+----------------------------+----------+--------------+------------------+-------------------+
| File                       | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------------------+----------+--------------+------------------+-------------------+
| mysql-bin-changelog.000058 |      157 |              |                  |                   |
+----------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)

 

 

 

2. CDC와 MSR의 복제를 중지합니다.

-- MSR DB
CALL mysql.rds_stop_replication_for_channel('test_db');

-- CDC
각 솔루션 별 방법에 따라 중단

 

이제 CDC와 MSR DB의 데이터는 특정 시점으로 고정되고 더 이상 변하지 않습니다.

데이터가 3까지 들어온 시점에서 중지




 

3. testDB 5.7 reader 인스턴스에서 mysqldump를 사용해 데이터를 덤프합니다. (대용량 서버의 경우 xtrabackup, mysqlshell, 스냅샷 등 다른 도구 검토가 필요합니다.) https://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.html

mysqldump \
  --login-path=test57_reader \
  --single-transaction \
  --set-gtid-purged=OFF \
  --all-databases \
  > db_dump.sql

 
 


4. testDB 8.0 writer, reader 인스턴스에 데이터를 로드합니다.

mysql --login-path=test80_writer < db_dump.sql
mysql --login-path=test80_reader < db_dump.sql

 



5. testDB 8.0 reader 인스턴스에서 8.0 testDB writer 인스턴스의 binary log 파일과 포지션 정보로 복제를 구성후 시작합니다.

-- 8.0 writer testDB
mysql> show master status;
+----------------------------+----------+--------------+------------------+-------------------+
| File                       | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------------------+----------+--------------+------------------+-------------------+
| mysql-bin-changelog.123456 |      100 |              |                  |                   |
+----------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)


-- 8.0 reader testDB
mysql> CALL mysql.rds_set_external_master ('80writer_testdb_endpoint',
3306,
'admin',
'password',
'mysql-bin-changelog.123456',
100,
0);
Query OK, 0 rows affected (0.10 sec)

mysql> CALL mysql.rds_start_replication;
+-----------------------------------------------------+
| Message                                             |
+-----------------------------------------------------+
| Replication started. Slave is now running normally. |
+-----------------------------------------------------+
1 row in set (3.05 sec)

-- 복제 상태 확인 (I/O 및 SQL 스레드 상태)
mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for master to send event
                  Source_Host: 80writer_testdb_endpoint
                  Source_User: admin
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin-changelog.123456
          Read_Source_Log_Pos: 100
               Relay_Log_File: relaylog.000002
                Relay_Log_Pos: 336
        Relay_Source_Log_File: mysql-bin-changelog.000064
           Replica_IO_Running: Yes                      <-- Yes 확인
          Replica_SQL_Running: Yes                      <-- Yes 확인
        Seconds_Behind_Source: 0
    Replica_SQL_Running_State: Slave has read all relay log; waiting for more updates
    ...	생략
    ...	생략
    ...	생략
1 row in set (0.01 sec)

 

 


5번까지 진행한 현재 각 DB의 데이터 상황을 그림으로 나타냈습니다.
testDB 5.7 writer DB에 데이터가 3까지 들어온 시점에서 mysqldump를 시작했다고 가정했을 때의 DB 데이터 상태입니다.

testDB 8.0 세트는 APP이나 DB에 replication으로 커넥션을 맺고있지 않기 때문에 정지된 특정 시점의 데이터만 보유하고 있습니다.
 

 


6. CDC와 MSR DB의 복제 구성을 testDB(8.0) reader 를 향하도록 변경합니다.

testDB(8.0) reader의 데이터 시점은 고정되어있으므로 따로 binlog 정보를 뽑아와서 프로시저에 대입합니다.

-- MSR DB
CALL mysql.rds_set_external_source_for_channel('testDB_80_reader', 3306, 'admin', 'password', 'mysql-bin-changelog.123456', 100, 0, 'testDB');

-- CDC
툴의 사용법 대로 재설정

MSR DB, CDC 소스 재구성

 


 
7. testDB 8.0 writer 인스턴스에서 testDB 5.7 reader 인스턴스로 복제를 구성 및 시작합니다. 프로시저의 binary log 파일과 포지션 매개변수는 1번에서 별도로 기록해둔 것에서 찾아와 입력합니다.

mysql> CALL mysql.rds_set_external_master ('test57_reader_db_endpoint',
3306,
'admin',
'password',
'mysql-bin-changelog.000058',
157,
0);
Query OK, 0 rows affected (0.10 sec)

mysql> CALL mysql.rds_start_replication;
+-----------------------------------------------------+
| Message                                             |
+-----------------------------------------------------+
| Replication started. Slave is now running normally. |
+-----------------------------------------------------+
1 row in set (3.05 sec)

-- 복제 상태 확인 (I/O 및 SQL 스레드 상태)
mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for master to send event
                  Source_Host: test57_reader_db_endpoint
                  Source_User: admin
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin-changelog.000058
          Read_Source_Log_Pos: 157
               Relay_Log_File: relaylog.000002
                Relay_Log_Pos: 336
        Relay_Source_Log_File: mysql-bin-changelog.000064
           Replica_IO_Running: Yes                      <-- Yes 확인
          Replica_SQL_Running: Yes                      <-- Yes 확인
        Seconds_Behind_Source: 0
    Replica_SQL_Running_State: Slave has read all relay log; waiting for more updates
    ...	생략
    ...	생략
    ...	생략
1 row in set (0.01 sec)

 
 
 
이제, 사용자가 입력한 데이터가 APP-> testDB(5.7) writer -> testDB(5.7) reader -> testDB(8.0) writer -> testDB(8.0) reader
으로 흐르게 됩니다.

가장 말단인 testDB(8.0) reader 서버까지 최신 데이터 6이 반영되는 것을 확인할 수 있습니다.
 


 

2. 도메인 구매 및 route53 호스팅 등록 + cname 레코드를 db endpoint로 사전 설정 및 application 배포 설정

도메인 구매 및 route53 호스팅을 등록합니다. 관련해서 저는 웹사이트 도메인 관련 지식이 적으므로 다른 게시글을 참고해주시면 좋을 것 같습니다.......
 
아무튼 아래와 같이 도메인을 등록합니다. 도메인 회사 홈페이지에서 네임서버 설정도 마칩니다.

 
 
그리고, 주황색의 Create record를 클릭해서 레코드를 생성하는 화면에 진입합니다. 

 
 
 
ip가 아닌 AWS RDS MySQL의 DB DNS Endpoint를 등록할 것이기 때문에 CNAME을 선택합니다.
value 는 testDB(5.7) writer 및 testDB(5.7) reader endpoint로 입력합니다.
TTL은 60초로 설정합니다.
write/read 용 레코드, read-only 레코드 총 두 레코드를 생성합니다.

 
 
 
생성된 CNAME record를 확인합니다.

 
 
이제, APP의 DB 접속 주소를 해당 레코드로 설정합니다.
아마 이 부분은 서비스 회사라면 많이 되어 있으실 것 같습니다. 되어있지 않다면 설정 적용 후 APP 재배포가 필요할 수도 있습니다.
 
지금까지 설정한 것을 그림으로 다시 확인하겠습니다.

트래픽이 route53을 거친다.

그림이 이제 조금 복잡해보이지만, APP이 이제 route53 CNAME record의 DNS를 통해 DB에 접근하는 것만 이해했다면 넘어가도 됩니다.
 
 

3. ec2 에 proxysql 설치 및 hostgroup 등록 및 기존 db(5.7)로 라우팅하도록 설정

 
AWS ec2 인스턴스를 시작합니다.
시작된 인스턴스에 접근해서 proxysql 을 설치 및 설정합니다.

 

ProxySQL 및 관련 패키지 설치, 서비스 시작

-- proxysql 설치
wget https://github.com/sysown/proxysql/releases/download/v2.2.0/proxysql_2.2.0-ubuntu20_amd64.deb \
&& sudo dpkg -i proxysql_2.2.0-ubuntu20_amd64.deb

-- proxysql 서비스 시작
sudo service proxysql start

-- mysql-client 설치
sudo apt install mysql-client-core-8.0

 

 

ProxySQL 접속 및 계정 설정

-- proxysql 인스턴스 접속 (초기 패스워드 admin)
mysql -uadmin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '

-- 모니터링 계정 설정 (ProxySQL에서 MySQL로 원격 접속할 수 있는 계정) proxyec2 -> rds mysql 계정
UPDATE global_variables SET variable_value = 'admin' WHERE variable_name = 'mysql-monitor_username';   
UPDATE global_variables SET variable_value = 'password' WHERE variable_name = 'mysql-monitor_password';   

-- 설정 확인
SELECT * FROM global_variables WHERE variable_name LIKE 'mysql-monitor_%';

-- 설정 적용
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

 
 

Proxy 대상 DB 서버 정보 추가 및 쿼리(라우팅) 룰 설정

test 5.7 DB 들의 weight를 1000으로 두고, test 8.0 DB의 weight를 0으로 설정해서 5.7 DB에만 트래픽이 흐르도록 의도합니다.

-- MySQL 서버 정보 추가
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES 
(1, 'testDB-57-writer', 3306, 1000);
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES 
(2, 'testDB-57-reader', 3306, 1000);
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES 
(3, 'testDB-80-writer', 3306, 0);
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES 
(4, 'testDB-80-reader', 3306, 0);


-- MySQL 서버 추가 확인
SELECT * FROM mysql_servers;

-- MySQL 서버 연결 성공 확인
SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start_us DESC LIMIT 10;
SELECT * FROM monitor.mysql_server_ping_log ORDER BY time_start_us DESC LIMIT 10;

-- 계정 추가 (클라이언트에서 ProxySQL로 원격 접속할 수 있는 계정)
INSERT INTO mysql_users (username, password, default_hostgroup) VALUES ('admin', 'password', 1);

LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

 

 

쿼리 룰을 설정합니다. 쓰기와 읽기 요청을 어느 DB에 보낼지 설정하는 부분입니다.

일단 기존 5.7 DB로 트래픽이 향하도록 설정해야 하기 때문에, hostgroup_id = 1(5.7 writer), hostgroup_id=2(5.7 reader) 로 쿼리 룰을 세팅합니다.

-- 정규표현식을 통해 쿼리 종류에 따라 다른 호스트 그룹으로 전달하도록 설정 추가
INSERT INTO mysql_query_rules(match_pattern,destination_hostgroup,active) VALUES
 ('^INSERT',1,1),
 ('^UPDATE',1,1),
 ('^DELETE',1,1),
 ('^REPLACE',1,1),
 ('^SELECT',2,1);

-- 쿼리 룰 확인
SELECT * FROM mysql_query_rules;

 

 

 

설정을 디스크에 기록합니다.

proxysql 의 작업 공간은 크게 런타임, 메모리, 디스크 3개로 나뉘어집니다. 어드민을 통해 백엔드 서버, 유저 등의 설정을 변경하는 경우 변경 사항은 메모리에 저장되며 실제 서버에 바로 적용이 되진 않습니다. 이 경우 메모리에 발생한 변경사항을 런타임으로 불러와야 실제 서버에 적용이 됩니다. 디스크는 메모리의 변경 사항을 영구적으로 저장하기 위한 공간으로 proxysql 재시작 시 불러올 정보가 저장됩니다.

-- 설정 적용
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

 


 

 

4. NLB 생성 및 EC2 인스턴스 타겟 그룹 매핑

이제, AWS Network Load Balancer를 생성합니다.

왜 EC2 IPv4 DNS 말고 NLB를 사용하나요? (chatgpt)

 
1. EC2 Public IPv4 DNS 사용
• Public IPv4 DNS는 EC2 인스턴스가 퍼블릭 서브넷에 있을 때 자동으로 할당되는 도메인 이름입니다. 이는 인스턴스가 재시작될 때마다 IP 주소가 변경되더라도 항상 동일한 도메인 이름을 통해 접근할 수 있도록 합니다.
장점:
• 간단한 설정: 별도의 로드 밸런서 없이, EC2 인스턴스에 할당된 퍼블릭 IPv4 DNS로 바로 접근할 수 있습니다.
• 비용 절감: NLB를 추가로 설정하지 않기 때문에 로드 밸런서에 대한 추가 비용이 발생하지 않습니다.
단점:
• 유동 IP 문제: 퍼블릭 IPv4 DNS는 EC2 인스턴스의 IP가 변경될 때마다 새로 생성됩니다. 이는 EC2 인스턴스를 중지 후 다시 시작할 경우 퍼블릭 IPv4 DNS가 변경된다는 뜻이므로, 이 도메인을 CNAME 레코드로 사용하면 연결이 끊길 위험이 있습니다.
• 확장성 부족: 단일 EC2 인스턴스만 사용할 수 있으며, 트래픽이 증가하거나 장애 조치(failover)가 필요한 경우 유연하게 대응하기 어렵습니다.
• 고가용성 한계: EC2 인스턴스가 단일 장애 지점이 됩니다. 인스턴스에 장애가 발생하면 서비스 전체가 중단될 위험이 있습니다.

2. Network Load Balancer(NLB) 사용
• NLB는 고정 IP와 DNS 이름을 제공하는 AWS의 로드 밸런서입니다. NLB를 사용하면 여러 인스턴스를 대상으로 하는 로드 밸런싱과 장애 조치 기능을 갖춘 고가용성 아키텍처를 구축할 수 있습니다.
장점:
• 고정 IP 제공: NLB는 고정 IP를 제공하므로, EC2 인스턴스가 중지되거나 변경되더라도 NLB의 IP가 유지됩니다. 이로 인해 안정적인 CNAME 설정이 가능합니다.
• 고가용성 및 확장성: NLB는 여러 가용 영역에 걸쳐 다수의 EC2 인스턴스를 분산할 수 있으므로, 트래픽 증가와 장애 상황에 보다 잘 대응할 수 있습니다.
• 탄력적 트래픽 관리: NLB는 트래픽 분산을 통해 EC2 인스턴스 간의 로드 밸런싱을 자동으로 수행합니다. 이로 인해 성능과 안정성이 높아집니다.
단점:
• 비용 증가: NLB는 AWS 비용이 추가로 발생합니다.
• 복잡한 설정: NLB 구성과 EC2 인스턴스 연결, 보안 그룹 설정이 추가적으로 필요하여 초기 설정이 다소 복잡할 수 있습니다.

요약
• Public IPv4 DNS는 단일 인스턴스를 대상으로 간단히 사용할 때 적합하지만, 중지 후 시작 시 DNS가 변경될 위험이 있고, 고가용성이나 확장성을 제공하지 않습니다.
• NLB는 고정 IP 제공, 고가용성, 그리고 확장성을 제공하므로 프로덕션 환경에서 안정성과 확장성을 요구할 때 적합합니다.

따라서 안정성과 확장성이 중요한 환경에서는 NLB를 사용하는 것이 더 안전한 방법입니다.
 


 
Target Group을 생성합니다.
아래와 같이 설정합니다.

포트 6603
헬스 체크 프로토콜 = TCP
타겟을 proxysql이 설치된 ec2 인스턴스로 설정

 
 
EC2 Load balancers 탭에서 Create load balancer 를 클릭합니다.

 
 
가운데 Network Load Balancer를 선택합니다.

 
 
 
NLB 이름을 입력하고 internet-facing, Ipv4를 선택합니다.

 
 
 
타겟 그룹을 아까 생성한 타겟 그룹으로 설정합니다. 포트는 3306입니다.

 
 
 
지금까지 설정된 것을 그림으로 한 번 더 살펴보겠습니다.

NLB와 target group(ec2) 네트워크 흐름 추가

 
NLB -> Target Group(EC2) -> DB 의 네트워크 흐름이 하나 생겼습니다.
 
 
 
 
 
 

5.  DB Route53 CNAME 레코드의 value를 NLB endpoint로 변경

 
이제, 실제 APP의 모든 트래픽을 ProxySQL 을 거쳐서 Database에 전달하도록 바꿀 차례입니다. 앞서 했던 모든 작업은 결국 서비스의 중단을 없애고자 수행한 태스크들입니다. APP에서 처음부터 Route53의 CNAME 레코드를 바라보고 배포되어있었다면, 이 단계에서 중단 없이 ProxySQL EC2로 트래픽을 전환하는 것이 가능합니다.
 
 
레코드를 선택하고 Edit record를 클릭합니다.

 
 
 
NLB endpoint를 입력합니다.

 
Save를 누르면, 최대 60초 안에 APP이 바라보는 주소가 변경되고 ProxySQL 을 통해 SQL을 실행하게 됩니다.
 
 
 
여기까지의 네트워크 흐름을 그림으로 살펴보겠습니다.

CNAME record -> NLB

 
이제 CNAME 레코드가 NLB를 바라보고, NLB는 3306으로 받은 요청을 ProxySQL EC2 6603포트로 전달합니다. 전달된 SQL은 각 DB에 전달됩니다.
 
 
 

 

6. ProxySQL의 라우팅 설정을 변경하여 5.7 -> 8.0으로 트래픽 라우팅 스위치

 
ProxySQL의 라우팅 설정 반영은 DNS 전파와는 다르게 즉시 반영됩니다. 스위칭 딜레이가 없거나 극도로 적기 때문에 DNS 와 다르게 APP의 SQL 트래픽이 어느 DB로 향할지에 대한 불확실성을 해소시켜 데이터 불일치를 방지할 수 있습니다.

 

 

등록된 DB 서버간의 스위칭

1. 쿼리 룰 변경

2. 가중치 변경

 

update 구문을 통해 쿼리 라우팅의 가중치를 변경하는 작업과 쿼리 룰을 수정하는 작업입니다.

이제 testDB(8.0) 세트가 가중치가 높아서 항상 이 곳으로 쿼리가 전달됩니다.

쿼리 룰도 변경했기 때문에 write, read가 분리되어 전달됩니다.

start transaction;

-- 쿼리 룰 testDB 8.0 호스트그룹 으로 변경
UPDATE mysql_query_rules SET destination_hostgroup = 4 WHERE rule_id = 1;
UPDATE mysql_query_rules SET destination_hostgroup = 3 WHERE rule_id = 2;

-- 가중치 스위치
UPDATE mysql_servers SET weight = 1000 WHERE hostgroup_id IN (3, 4);
UPDATE mysql_servers SET weight = 0 WHERE hostgroup_id IN (1, 2);

commit;

-- 설정 저장
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

 

 

 

이제 아래 그림과 같이 testDB(5.7) 는 어떤 app이나 DB에서도 트래픽을 전달하지 않습니다.

DNS 로만 전환을 시도했다면 혹시 모를 캐시 때문에 일정 시간동안 트래픽이 전달될 수도 있었겠지만, proxysql을 사용했기 때문에 그에 대한 불안감 없이 스위치가 완료되었습니다.

신규 생성된 데이터 7, 8은 testDB(8.0)에만 존재하는 것을 확인할 수 있습니다.

스위칭 된 트래픽 흐름

 

 

 

 

 


 

마무리

 

이제, testDB 5.7은 더이상 사용되지 않으므로 사용한 리소스를 정리해도 됩니다.

아래 순서로 진행하면 됩니다.

 

1. testDB(8.0) writer 의 복제 정보 reset

2. testDB(5.7) 세트 삭제

3. route53 CNAME 레코드 value를 DB endpoint로 변경

4. ec2, nlb, target group 삭제
 
 
 
 
 
 
 
 
 

 
 

 


 

참조


중단 시간 최소화 데이터 이관:https://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.NonRDSRepl.html

 

가동 중지 시간을 단축하여 Amazon RDS MariaDB 또는 MySQL 데이터베이스로 데이터 가져오기 - Amazon Relat

처음에 테이블을 덤프할 때 mysqldump와 함께 데이터 서식 옵션을 사용했다면, LOAD DATA LOCAL INFILE과 함께 같은 옵션을 사용하여 데이터 파일 내용을 올바로 해석해야 합니다.

docs.aws.amazon.com

AWS RDS 내장 복제 프로시저: https://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/mysql-stored-proc-replicating.html#mysql_rds_set_external_master

 

이진수 로그(binlog) 복제 구성, 시작 및 중지 - Amazon Relational Database Service

MASTER_SSL_VERIFY_SERVER_CERT 옵션은 지원되지 않습니다. 이 옵션은 0으로 설정되어 있는데, 이는 연결이 암호화되었지만 인증서는 확인되지 않았음을 의미합니다.

docs.aws.amazon.com

https://kbit.tistory.com/192

 

ProxySQL 초기 설정

초기 구성 이 가이드에서는 ProxySQL의 기본 구성 요소를 단계별로 구성하는 방법을 설명합니다. 이 가이드에서는 사용자가 ProxySQL의 전체 아키텍처를 이해하고 있고 ProxySQL이 기본 구성으로 운영

kbit.tistory.com

https://engmisankim.tistory.com/64

 

ProxySQL 을 통한 MySQL 쿼리 라우팅 설정

지난 게시글에서는 MySQL connector for Java 의 Replication 커넥션 기능을 사용하여 쓰기/읽기 DB로 쿼리를 분산하는 내용으로 공유를 진행했습니다. 하지만 MySQL connector for Java 의 Replication 커넥션 기능을

engmisankim.tistory.com

https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/mysql-multi-source-replication.html

 

Configuring multi-source-replication for Amazon RDS for MySQL - Amazon Relational Database Service

Configuring multi-source-replication for Amazon RDS for MySQL With multi-source replication, you can set up an Amazon RDS for MySQL DB instance as a replica that receives binary log events from more than one RDS for MySQL source DB instance. Multi-source r

docs.aws.amazon.com

 

반응형