오라클 클라우드 MySQL Database Service (4) - MDS - Oracle Cloud

Last Updated on 4월 8, 2021 by 태랑(정현호)


Oracle Cloud 의 MySQL Database Service(MDS) 에 IDC 나 다른 클라우드에서 데이터를 이관(Migration) 하는 방법은 여러가지가 있을 것이고 통상적으로는 VPN 이나 전용망 그리고 오브젝트 스토리지 등이 필요 할 것 입니다.

포스팅에서는 VPN 이나 전용망, 오브젝트 스토리지 등이 없는 상황에서 타 클라우드나 IDC의 MySQL의 데이터를 이관(Migration) 하는 내용과 Oracle Cloud MDS 인스턴스를 Replica(Target) 으로 구성 하는 내용에 대해서 기술되어 있습니다.


[참조] 포스팅에서는 사전에 생성된 MDS 인스턴스를 사용합니다 MDS 의 생성 등은 이전의 포스팅에서 확인 하시면 됩니다







1. Master DB 설정

1-1 GTID 적용

MDS 인스턴스를 Replica 노드로 사용까지 할 계획임으로 먼저 GTID 적용 설정을 하겠습니다.
/etc/my.cnf  파일에 아래 파라미터를 추가 후 MySQL 재시작 합니다.

[mysqld]

log-bin=binlog
gtid-mode=ON
enforce-gtid-consistency=ON



1-2 Replication 유저 생성

Master 노드(Source) 에서 유저를 생성 합니다.

mysql> create user 'repl_user'@'%' identified by 'Repl_user12#$';
mysql> grant replication slave,replication client on *.* to 'repl_user'@'%';




2. Data Migration

먼저 IDC 나 클라우드내 있는 MySQL 의 데이터를 Dump(export) 하고 Load(import) 를 하는 과정을 진행 하겠습니다.


2-1 dumpInstance

디렉토리를 생성 후 데이터를 dump 하도록 하겠습니다.

[root]# rm -rf /root/backup/inst_dump
[root]# mkdir -p /root/backup/inst_dump

[root]# mysqlsh root@localhost -e 'util.dumpInstance("/root/backup/inst_dump",
{ocimds: true, threads: 8, showProgress: true, compatibility:
 ["force_innodb", "strip_definers","strip_restricted_grants", "strip_tablespaces"]})'

# 가로 길이를 위해서 개행을 하였지만, 실제로는 한줄로 입력 해야 합니다.


[참고] MySQL Shell dump utility 는 아래 포스팅에서 내용을 확인하시면 되며, dumpInstance 에서는 대소문자를 구별해서 사용해야 합니다.



2-2 SSH Tunneling

이전 포스팅에서 언급한 SSH Tunneling 를 통해서 진행할 것입니다. 그림으로 표현 하면 아래와 같습니다.



관련된 자세한 내용은 아래 포스팅을 참조하시면 됩니다.


bastion host 와의 SSH Tunneling 은 아래 와 같이 실행 할 수 있습니다

[root]# ssh -f -N -L 3333:10.0.1.20:3306 ubuntu@배스천호스트IP

[root]# netstat -antp | grep 3333
tcp        0      0 127.0.0.1:3333          0.0.0.0:*               LISTEN      7447/ssh            
tcp6       0      0 ::1:3333                :::*                    LISTEN      7447/ssh

* 3306 포트는 MySQL 서버가 이미 사용중임으로 다른 포트(3333) 로 생성


[참고] 베스천 호스트의 SSH 의 보안 관련 해서는 아래 포스팅을 참조하시면 됩니다.




2-3 loadDump

위에서 터널링으로 베스천 호스트를 통해 MDS 인스턴스에 접속 할 수 있는 환경은 구성이 되었으므로 export 된 데이터를 Load 하도록 하겠습니다.

[root]# mysqlsh master@127.0.0.1 -P 3333 -e 
'util.loadDump("/root/backup/inst_dump", 
{threads: 8,ignoreExistingObjects:true,
resetProgress:true,updateGtidSet:"replace"})'

# 가로 길이를 위해서 개행을 하였지만, 실제로는 한줄로 입력 해야 합니다.



• util.loadDump 진행 로그 예시

Please provide the password for 'master@127.0.0.1:3333': ************
Save password for 'master@127.0.0.1:3333'? [Y]es/[N]o/Ne[v]er (default No): yes
Loading DDL and Data from '/root/backup/inst_dump' using 8 threads.
Opening dump...
Target is MySQL 8.0.23-u2-cloud (MySQL Database Service). Dump was produced from MySQL 8.0.23
Checking for pre-existing objects...
Executing common preamble SQL
Executing DDL script for schema `xxxx`
[Worker001] Executing DDL script for `xxxx`.`table1`
[Worker002] Executing DDL script for `xxxx`.`table2`
[Worker006] Executing DDL script for `xxxx`.`table3`
[Worker005] Executing DDL script for `xxxx`.`table4`
<....중략....>



 MySQL SQL > show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.0015 sec)


 MySQL SQL > show databases;
+--------------------+
| Database           |
+--------------------+
| xxxx               | <--- New Database
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.0014 sec)


입력 대상이 오라클 클라우드로 식별 되면 아래와 같이 메세지가 확인 됩니다.
Target is MySQL 8.0.23-u2-cloud (MySQL Database Service)



2-4 sys.set_gtid_purged

Load가 완료 되었다면 Replica 노드인 MDS 인스턴스에서 sys.set_gtid_purged 수행이 필요 합니다.

먼저 dump 된 파일에서 gtidEx 정보를 확인 합니다.

[root]# cd /root/backup/inst_dump

[root]# cat @.json | grep gtidEx
"gtidExecuted": "13abea0b-7b7b-11eb-b27b-08002761d7ed:1",



조회 후 MDS 인스턴스 에서 아래와 같이 sys.set_gtid_purged 를 수행 합니다.

mysql> show variables like '%gtid%';
+----------------------------------------------+--------------------------------------------+
| Variable_name                                | Value                                      |
+----------------------------------------------+--------------------------------------------+
| binlog_gtid_simple_recovery                  | ON                                         |
| enforce_gtid_consistency                     | ON                                         |
| group_replication_gtid_assignment_block_size | 1                                          |
| gtid_executed                                | dc6e2077-7f3f-11eb-84de-02001708c786:1-143 |
| gtid_executed_compression_period             | 0                                          |
| gtid_mode                                    | ON                                         |
| gtid_next                                    | AUTOMATIC                                  |
| gtid_owned                                   |                                            |
| gtid_purged                                  |                                            |
| session_track_gtids                          | OFF                                        |
+----------------------------------------------+--------------------------------------------+
10 rows in set (0.00 sec)


mysql> call sys.set_gtid_purged("13abea0b-7b7b-11eb-b27b-08002761d7ed:1-11");
Query OK, 0 rows affected (0.01 sec)


mysql> show variables like '%gtid%';
+----------------------------------------------+---------------------------------------------+
| Variable_name                                | Value                                       |
+----------------------------------------------+---------------------------------------------+
| binlog_gtid_simple_recovery                  | ON                                          |
| enforce_gtid_consistency                     | ON                                          |
| group_replication_gtid_assignment_block_size | 1                                           |
| gtid_executed                                | 13abea0b-7b7b-11eb-b27b-08002761d7ed:1-11,  |
|                                              | dc6e2077-7f3f-11eb-84de-02001708c786:1-143  |
| gtid_executed_compression_period             | 0                                           |
| gtid_mode                                    | ON                                          |
| gtid_next                                    | AUTOMATIC                                   |
| gtid_owned                                   |                                             |
| gtid_purged                                  | 13abea0b-7b7b-11eb-b27b-08002761d7ed:1-11   |
| session_track_gtids                          | OFF                                         |
+----------------------------------------------+---------------------------------------------+


여기 까지 진행 되었다면 데이터 마이그레이션이 완료 되었습니다.




3.  VCN/OS 방화벽/SSH 터널링 설정

* Chapter3 에서 진행하는 내용은 Oracle Cloud -> IDC/타 클라우드 의 연결을 SSH 터널링으로 진행하기 위해서 MDS Instance 에서 베스천 호스트로 연결을 설정하는 내용입니다.
그렇기 때문에 구성하는 환경에 따라 Outbound Replication 설정에서 이 과정은 생략을 하셔도 됩니다.


3-1 VCN 설정

3-1-1 먼저 VCN 설정 -> 공용 서브넷  으로 이동 합니다.




3-1-2 Default 보안 목록 으로 이동 합니다.




3-1-3 수신 규칙 추가 를 클릭 합니다.




3-1-4 수신 규칙 에서의 소스 CIDR 은 전용 서브넷 CIDR 을 입력 하고, 포트는 SSH 터널링 으로 연결할 3333 포트를 입력 하겠습니다.





3-2 OS 방화벽 오픈

클라우드사 마다 설정이 약간씩은 다르며, 오라클 클라우드는 기본적으로 OS 방화벽이 설정되어 있습니다. CentOS 에서는 firewalld 를 Ubuntu 에서는 iptables 로 동작하고 있습니다.


• 우분투 기준 - iptables 설정

# iptables 설정에 필요한 패키지 설치
User$ sudo apt-get install iptables-persistent netfilter-persistent

# 3333 포트 오픈
User$ iptables -I INPUT -p tcp -s 10.0.1.0/24 --dport 3333 -j ACCEPT

# iptables 변경 내용 저장
User$ sudo netfilter-persistent save



3-3 SSH 터널링 설정

MDS 인스턴스에서 다른 위치의 Master DB 와의 연결을 위하여 베스천 호스트 에서 IDC 서버 호스트로의 SSH 터널링을 연결하도록 하겠습니다.

# 베스천 호스트에서 실행
ubuntu@mds-bastion:~$ ssh -f -N -L 0.0.0.0:3333:localhost:3306 opc@IDC서버IP

ubuntu@mds-bastion:~$ sudo netstat -antp | grep 3333
tcp        0      0 0.0.0.0:3333            0.0.0.0:*               LISTEN      26384/ssh





4. Outbound Replication

OracleCloud 의 MDS 에서는 Replication 은 채널 을 통해서 복제가 수행됩니다.


4-1 채널 생성

4-1-1 MDS 인스턴스 하단의 채널 -> 채널 생성 을 통해 진행 하거나 




채널 생성 시작은 DB 인스턴스 외 메뉴에서도 들어갈 수 있습니다




4-1-2 채널 이름을 입력 합니다.




4-1-3 소스 설정에 베스천 호스트 IP 를 입력하고, 터널링에 사용할 포트를 입력, 그리고 위에서 생성한 복제 유저 정보를 입력 합니다.




4-1-4 DB 시스템 선택에서 Replica 노드를 선택 후 채널 생성 을 클릭 합니다.




4-1-5 정상적으로 실행이 완료되었다면 아래와 같이 복제가 활성화 될 것 입니다.






5. Replication 확인

복제 설정이 완료 되었다면 먼저 Master 노드에서 테이블과 데이터를 입력하여 확인 및 Master 노드와 Replica 노드 에서 각각 상태를 조회 합니다.


5-1 데이터 복제 확인

# Source - Master

mysql> create database test;
mysql> use test;



# Target - Replica

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| redologs           |
| sys                |
| test               | <-------
| var                |
+--------------------+



# Source - Master

mysql> CREATE TABLE emp ( 
    empno int  NOT NULL  AUTO_INCREMENT,
    ename varchar(20),
    job varchar(20),
    mgr smallint,
    hiredate   date,
    sal numeric(7,2),
    comm numeric(7,2),
    deptno  int,
    CONSTRAINT pk_emp PRIMARY KEY ( empno )
 ) engine=InnoDB;


insert into emp values( 7839, 'KING', 'PRESIDENT', null, STR_TO_DATE ('17-11-1981','%d-%m-%Y'), 5000, null, 10);
insert into emp values( 7698, 'BLAKE', 'MANAGER', 7839, STR_TO_DATE('1-5-1981','%d-%m-%Y'), 2850, null, 30);
insert into emp values( 7782, 'CLARK', 'MANAGER', 7839, STR_TO_DATE('9-6-1981','%d-%m-%Y'), 2450, null, 10);
insert into emp values( 7566, 'JONES', 'MANAGER', 7839, STR_TO_DATE('2-4-1981','%d-%m-%Y'), 2975, null, 20);
insert into emp values( 7788, 'SCOTT', 'ANALYST', 7566, DATE_ADD(STR_TO_DATE('13-7-1987','%d-%m-%Y'),INTERVAL -85 DAY)  , 3000, null, 20);
insert into emp values( 7902, 'FORD', 'ANALYST', 7566, STR_TO_DATE('3-12-1981','%d-%m-%Y'), 3000, null, 20);
insert into emp values( 7369, 'SMITH', 'CLERK', 7902, STR_TO_DATE('17-12-1980','%d-%m-%Y'), 800, null, 20);
insert into emp values( 7499, 'ALLEN', 'SALESMAN', 7698, STR_TO_DATE('20-2-1981','%d-%m-%Y'), 1600, 300, 30);
insert into emp values( 7521, 'WARD', 'SALESMAN', 7698, STR_TO_DATE('22-2-1981','%d-%m-%Y'), 1250, 500, 30);
insert into emp values( 7654, 'MARTIN', 'SALESMAN', 7698, STR_TO_DATE('28-09-1981','%d-%m-%Y'), 1250, 1400, 30);
insert into emp values( 7844, 'TURNER', 'SALESMAN', 7698, STR_TO_DATE('8-9-1981','%d-%m-%Y'), 1500, 0, 30);
insert into emp values( 7876, 'ADAMS', 'CLERK', 7788, DATE_ADD(STR_TO_DATE('13-7-1987', '%d-%m-%Y'),INTERVAL -51 DAY), 1100, null, 20);
insert into emp values( 7900, 'JAMES', 'CLERK', 7698, STR_TO_DATE('3-12-1981','%d-%m-%Y'), 950, null, 30);
insert into emp values( 7934, 'MILLER', 'CLERK', 7782, STR_TO_DATE('23-1-1982','%d-%m-%Y'), 1300, null, 10);


mysql> select count(*) from emp;
+----------+
| count(*) |
+----------+
|       14 |
+----------+




# Target - Replica
mysql> use test;

mysql> select count(*) from emp;
+----------+
| count(*) |
+----------+
|       14 |
+----------+




5-2 복제 상태 확인

### Master 노드 

mysql> show master status\G
*************************** 1. row ***************************
             File: binlog.000014
         Position: 2392
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 13abea0b-7b7b-11eb-b27b-08002761d7ed:1-11
1 row in set (0.00 sec)

mysql> show replicas\G
*************************** 1. row ***************************
   Server_Id: 678801625
        Host: 
        Port: 3306
   Source_Id: 1
Replica_UUID: dc6e2077-7f3f-11eb-84de-02001708c786
1 row in set (0.00 sec)





### Replica 노드
mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for master to send event
                  Source_Host: 10.0.0.2
                  Source_User: repl_user
                  Source_Port: 3333
                Connect_Retry: 60
              Source_Log_File: binlog.000014
          Read_Source_Log_Pos: 2392
               Relay_Log_File: relay-log-replication_channel.000002
                Relay_Log_Pos: 409
        Relay_Source_Log_File: binlog.000014
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 2392
              Relay_Log_Space: 632
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File: 
           Source_SSL_CA_Path: 
              Source_SSL_Cert: 
            Source_SSL_Cipher: 
               Source_SSL_Key: 
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Source_Server_Id: 1
                  Source_UUID: 13abea0b-7b7b-11eb-b27b-08002761d7ed
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Source_Retry_Count: 0
                  Source_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Source_SSL_Crl: 
           Source_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 13abea0b-7b7b-11eb-b27b-08002761d7ed:1-11,
dc6e2077-7f3f-11eb-84de-02001708c786:1-143
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: replication_channel
           Source_TLS_Version: TLSv1.2,TLSv1.3
       Source_public_key_path: 
        Get_Source_public_key: 1
            Network_Namespace: mysql



mysql> SELECT 
concat(conn_status.channel_name, ' (', worker_id,')') AS channel,
conn_status.service_state AS io_state,
applier_status.service_state AS sql_state,
format_pico_time(if(GTID_SUBTRACT(LAST_QUEUED_TRANSACTION, LAST_APPLIED_TRANSACTION) = "","0",
abs(time_to_sec(if(time_to_sec(APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP)=0,0,
timediff(APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,now()))))) * 1000000000000) latency,
format_pico_time((LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP -
LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP) * 100000000000) transport_time,
format_pico_time((LAST_QUEUED_TRANSACTION_END_QUEUE_TIMESTAMP -
LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP) * 1000000000000) time_to_relay_log,
format_pico_time((LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP -
LAST_APPLIED_TRANSACTION_START_APPLY_TIMESTAMP) * 1000000000000) apply_time,
conn_status.LAST_QUEUED_TRANSACTION AS last_queued_transaction,
applier_status.LAST_APPLIED_TRANSACTION AS last_applied_transaction
FROM
performance_schema.replication_connection_status AS conn_status
JOIN performance_schema.replication_applier_status_by_worker AS applier_status
ON applier_status.channel_name = conn_status.channel_name;

+-------------------------+----------+-----------+---------+----------------+-------------------+------------+-------------------------+--------------------------+
| channel                 | io_state | sql_state | latency | transport_time | time_to_relay_log | apply_time | last_queued_transaction | last_applied_transaction |
+-------------------------+----------+-----------+---------+----------------+-------------------+------------+-------------------------+--------------------------+
| replication_channel (1) | ON       | ON        |   0 ps  |   0 ps         |   0 ps            |   0 ps     |                         |                          |
| replication_channel (2) | ON       | ON        |   0 ps  |   0 ps         |   0 ps            |   0 ps     |                         |                          |
| replication_channel (3) | ON       | ON        |   0 ps  |   0 ps         |   0 ps            |   0 ps     |                         |                          |
| replication_channel (4) | ON       | ON        |   0 ps  |   0 ps         |   0 ps            |   0 ps     |                         |                          |
+-------------------------+----------+-----------+---------+----------------+-------------------+------------+-------------------------+--------------------------+




6. conclusion

Oracle Cloud의 SSH 터널링을 활용한 MDS 인스턴스에 데이터 마이그레이션 과 그리고 그 데이터를 이용한 Replication 을 구성하여 MDS 인스턴스를 Replica 로 구성하였습니다.

Read/Write 인 Master 노드는 기존의 IDC에서 사용 환경에서 백업이나 DR 형태로 클라우드에 복제 하는 형태로도 사용할 수 있거나 클라우드로 변경하기 위해서 데이터 복제를 구성 후 Application의 Connection 정보를 Replica 노드로 변경 하여 클라우드로 롤 체인지 하는 등으로 사용 할 수 있을 것 같습니다.



Ref link.
dasini.net/replicate-mysql-database-service [Link]

docs.oracle.com/replication [Link]
docs.oracle.com/Replication/GUID-94149D15 [Link]
dev.mysql.com/mysql-shell-load-dump [Link]
lefred.be/using-mysql-database-service [Link]



관련된 다른글

답글 남기기