본문 바로가기
AWS Ambassador

AWS DMS를 이용한 Oracle to RDS for Oracle Migration

by 백룡화검 2025. 5. 23.

이 글에서는 AWS DMS(Database Migration Service)를 활용하여 Oracle 11g (On-Premise)에서 RDS for Oracle 19c로 데이터베이스 마이그레이션을 수행한 실제 프로젝트에서 구성했던 내용과 더불어 실제 Case들을 공유합니다.

1. AWS DMS란?

AWS DMS는 관계형 데이터베이스, 데이터 웨어하우스, NoSQL DB 등 다양한 데이터 소스를 AWS 클라우드로 마이그레이션할 수 있도록 지원하는 서비스입니다.


2. Oracle 권한 설정

소스 Oracle 데이터베이스에서 사용될 계정에 필요한 권한은 다음과 같습니다. (ASIS_DMS계정은 예시)

grants 예시:
GRANT CREATE SESSION TO 'ASIS_DMS계정';
GRANT SELECT ANY TRANSACTION TO 'ASIS_DMS계정';
GRANT SELECT ON V_$ARCHIVED_LOG TO 'ASIS_DMS계정';
GRANT SELECT ON V_$LOG TO 'ASIS_DMS계정';
GRANT SELECT ON V_$LOGFILE TO 'ASIS_DMS계정';
GRANT SELECT ON V_$LOGMNR_LOGS TO 'ASIS_DMS계정';
GRANT SELECT ON V_$LOGMNR_CONTENTS TO 'ASIS_DMS계정';
GRANT SELECT ON V_$DATABASE TO 'ASIS_DMS계정';
GRANT SELECT ON V_$THREAD TO 'ASIS_DMS계정';
GRANT SELECT ON V_$PARAMETER TO 'ASIS_DMS계정';
GRANT SELECT ON V_$NLS_PARAMETERS TO 'ASIS_DMS계정';
GRANT SELECT ON V_$TIMEZONE_NAMES TO 'ASIS_DMS계정';
GRANT SELECT ON V_$TRANSACTION TO 'ASIS_DMS계정';
GRANT SELECT ON V_$CONTAINERS TO 'ASIS_DMS계정';                   
GRANT SELECT ON ALL_INDEXES TO 'ASIS_DMS계정';

3. AWS DMS 구성

DMS 구성은 다음 5단계로 진행됩니다:

  1. Subnet Group 생성
  2. Replication Instance 생성
  3. Source/Target Endpoint 생성
  4. Task 생성 및 설정

각 항목에 대해서는 아래 구성 방법에서 예시와 함께 설명하도록 하겠습니다.

3-1) Subnet Group

  • 복제 서브넷 그룹을 생성합니다.
    :
    복제 서브넷 그룹은 Replication Instance를 생성할 때 사용할 서브넷 그룹입니다. 이 서브넷은 AWS 계정 내 존재하는 VPC와 그에 속해 있는 서브넷 그룹을 활용하여 생성하게 됩니다.

3-2) Replication Instance (RI)

  • Replication Instance에서 사용할 식별자와 설명을 작성해 줍니다. 

  • RI에서 사용할 적합한 인스턴스 클래스를 선택해주며, 고가용성 항목에서 단일 AZ로 설정한것은 장기적으로 CDC를 유지해야하는 것이 아니라 Migration 기간동안만 CDC를 사용 할 예정이기 때문에 비용 효율성을 위해서 입니다.

    • IPv4용 VPC 항목을 선택후, 3-1)에서 생성한 복제 서브넷 그룹을 선택합니다.
    • 퍼블릭 엑세스 메뉴의 경우, 민감 Data의 보호를 위해 Check 해제 합니다.
    • 마지막으로 고급 설정 부분을 확인하게 되면 VPC 보안 그룹을 선택할 수 있고, 여기에서 통신 Port가 설정되어 있는 Security Group을 선택하도록 합니다.

  • 유지 관리 메뉴의 자동 버전 업그레이드를 체크할 경우 DMS 패치작업이 있을 경우 모든 Task가 중지후 재시작 되게 됩니다. 
    때문에, Data 전송에 문제가 생길수 있기 때문에 가능하다면 [아니요]로 선택하는게 좋습니다.

      참고 문서 : https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.MaintenanceWindow.html?icmpid=docs_DMS_help_panel_hp-dms-classic-createreplication-maint

 

Working with the AWS DMS maintenance window - AWS Database Migration Service

Working with the AWS DMS maintenance window Every AWS DMS replication instance has a weekly maintenance window during which any available system changes are applied. You can think of the maintenance window as an opportunity to control when modifications an

docs.aws.amazon.com

 

3-3) Source Endpoint

  • Source EndpointSource Database와 Connection을 맺을수 있도록 환경 설정을 진행 해줍니다. 
    : Source Endpoint에서 사용할 식별자를 기재하고, 소스 엔진 부분을 Source Database에서 사용중인 DBMS Engine을 선택해 줍니다.

  • 엔드포인트 설정의 탭을 열게 되면 Source Endpoint에서 Data를 어떤 형식으로 가져올 것인가를 선택할 수 있습니다. 여러 사례에서도 많이 사용하고, 실제 Migration을 진행할 당시에는 Logminer를 사용하는 것 보다 Binary방식을 사용하는 것이 Replication InstanceCPUMemory를 적게 사용하기 때문에 BR방식을 택하였습니다. (RI 인스턴스 클래스를 낮춤으로 인하여 비용 절감)
    : 이 부분에서 주의해야 할 부분은
       1) 첫번째 붉은색으로 박스 영역(엔드포인트 설정)에서 UseBfiletrue, UseLogminerReaderfalse로 설정해도
       2) 아래 두번째 붉은색 박스 영역인 추가 연결 속성의 연결 속성 입력 inputbox에 useLogMinerReader=N;useBfile=Y;     를 다시 입력하지 않을경우, Bfile 형식으로 읽어오지 않는다. (두가지 다 설정해야만 정상적으로 동작합니다.)


  • 엔드포인트 연결 테스트는 Replication Instance와 정상적으로 연동이 되는지 확인하는 기능입니다. 테스트 실행을 클릭해서 테스트 완료 후 Sucessful이 출력되면 Source Endpoin의 생성을 완료하면 됩니다.

 

3-4) Target Endpoint

  • Target Endpoint를 생성할 때 RDS가 생성되어 있다면 IP(Endpoint), Port 등을 따로 입력하지 않고, 해당 RDS를 선택하면 됩니다. (RDS에 접석할 Account 및 Password는 입력 필요)


  • Target Endpoint 식별자 및 대상 엔진을 선택합니다.


  • 엔드폰인트 연결 테스트는 Replication Instance와 정상적으로 연동이 되는지 확인하는 기능입니다. 테스트 실행을 클릭해서 테스트 완료 후 Sucessful이 출력되면 Target Endpoin의 생성을 완료하면 됩니다.

3-5) Task 생성

  • Task에서 사용할 식별자와 3-1)~3-4)에서 생성한 정보들을 기입해 줍니다.
    Migraion 유형에는 아래와 같이 3가지가 있습니다.

    • 마이그레이션 : Full Load 1회 진행
    • 마이그레이션 및 복제 : Full Load 진행 후 CDC까지 진행
    • 복제 : CDC만 진행 

      : 이번 Case에서는 Migration에서 Full Load 후 CDC까지 적용하기 위해서 2번째 마이그레이션 및 복제를 선택해서 진행 했습니다.

Tip. 복제만 하게 될경우 Oracle의 SCN번호를 사용하거나 DMS에서 사용하는 체크포인트가 존재하는데 그것들을 사용해서 복제만 사용할 수도 있습니다. (DMS의 체크포인트는 Full Load 이후에 완료된 Task를 확인해 보면 체크포인트를 확인할 수 있습니다.)

 

  • Task 설정 중 대상 테이블의 준비 모드는 Target (RDS)에 있는 Table에 대한 작업이며, 각 옵션별 수행되는 작업은 다음과 같습니다.

    • 아무 작업 안함 : Target Table에 아무런 작업을 하지 않고 Data 적용 
    • 대상 테이블 삭제 : Task 시작 시 Target Table Drop 후 새로 Create한 뒤 Data 적용
    • 자르기 : Task 시작 시 Target TableTruncate 작업 후 Data 적용

      : 이번 Case에서는 Target RDS와 Table를 미리 생성해서 구조가 존재하는 상태이고,  테스트 도중 작성된 Data가 있을수 있기에 자르기를 선택해서 진행 했습니다.

  • LOB 컬럼 설정은 TaskLOB 컬럼이 존재하는 테이블이 있는 경우 최대 LOB 사이즈를 설정하는 부분입니다. 

    실제 Migration 수행시에는 제한적 LOB모드를 사용을 하였는데 실제 데이터 이관 시에 전체 LOB모드는 지정한 크기만큼 계속해서 할당을 하지만 제한적 LOB모드는 Max Lob 사이즈를 정해두고 그 안에서 실제 Lob 사이즈 만큼 할당을 해서 사용하기에 제한적  LOB 모드가 속도와 안정성 측면에서 우위에 있기 때문에 제한적 LOB모드를 적용 하였습니다.


  • 데이터 검증 : 데이터 검증옵션에서 Migration 테스트 기간중 에는 데이터 마이그레이션을 통해 검증을 선택하여  전송되는 Data에 대한 검증을 진행 하면서 테스트를 진행하였고, 실제 서비스 전환을 위한 Cut-Over를 위한 Task를 구성했을 때는 데이터 검증을 제외하고 진행했습니다.



  • Task의 모니터링을 위하여 Cloudwatch Log를 사용하였습니다.

    Migration 테스트 기간에는 로그 구성 요소 심각도에서 모두 상세 디버깅으로 설정하여 에러가 발생할 경우 확인하였고,
    Cut-Over
    를 위한 Task를 구성했을 때에는 기본값으로 설정하였습니다.

    상세 디버깅 모드로 설정을 하게 되면 RIStorage가 상당히 많이 늘어나기 때문에 Cut-Over시점에  Storage Full로 인한 실패가 발생할수 있기 때문입니다.



  • 배치 최적화 옵션 
    배치 최적화(Batch Optimized Apply) 옵션은 항상 배치 최적화 적용 켜기로 설정해서 사용했으며, 이때 주요 장점은 다음과 같습니다.

    1. 성능 향상 및 지연 시간 단축
      • 변경 사항을 개별적으로 적용하는 대신, 여러 변경 사항을 한 번에 배치(batch)로 묶어 처리합니다. 
      • 이로 인해 전송 속도와 처리 성능이 향상되고 지연 시간이 단축됩니다.
    2. 리소스 사용량 감소
      • 데이터베이스에 대한 여러 개별 트랜잭션보다 더 적은 수의 대규모 트랜잭션을 수행하므로, 데이터베이스의 I/O 및 CPU 사용량이 감소합니다.
    3. 대량의 데이터 변경에 효과적
      • 특히 많은 양의 데이터 변경이 일어날 때 배치로 묶어서 처리하면 효율성이 극대화됩니다.
    4. 복제 안정성 개선
      • 적은 수의 큰 트랜잭션을 적용하면 개별 트랜잭션의 실패 가능성이 줄어들고 안정성이 향상됩니다
    5. 비용 효율성 증가
      • 성능과 자원 효율성이 높아지기 때문에 AWS 리소스 사용량과 비용을 절감할 수 있습니다.
하지만 다음 사항을 주의해야 합니다.
 - 트랜잭션 일관성이 중요한 경우 배치 단위로 처리하므로, 실시간 복제 지연이 발생할 수 있습니다.
 - 소스 데이터베이스에서 개별 트랜잭션의 정확한 시점을 유지해야 할 필요가 있는 경우, 배치 최적화 옵션은 신중히 선택해야 합니다.

      : 때문에, 배치 최적화 옵션은 주로 성능 개선 및 비용 절감을 위한 대량 데이터 마이그레이션 및 복제 상황에서 유리하게 작동합니다. 

  • 고급 태스크 설정의 체크 항목에서 복제 상태, 일시 중지된 테이블, 복제 내역은 Task의 상황을 모니터링할 수 있게끔 Target DatabaseTable을 생성하여 Log를 쌓아줍니다. 테이블의 스키마는 위에 “RDS 어드민 계정 사용이라는 스키마에 생성이 됩니다. 

    내역 시간 슬롯()같은 경우에는 해당 Log를 쌓아주는 Table들이 설정해준 시간 단위로 Log를 찍게 됩니다. 그래서 Migration Test 기간에는 5분으로 여유있게 설정하였고, Cut-Over 1~2분 사이로 설정하여 모니터링 하였습니다.

    이 테이블들을 이용하여 모니터링을 할 수 있는 쿼리와 관련해서는 4. Task 모니터링 항목에서 자세히 설명하도록 하겠습니다.

    전체 로드 튜닝 설정에서 병렬로 로드할 최대 테이블 수Task가 여러 테이블 에서 작업할 Parallel 수를 지정해 주며, 전체 로드 중 커밋 비율CommitData가 해당 건수만큼 삽입 및 변경 작업이 일어날 경우 수행하게 됩니다.

  • 테이블 매핑에서 Migration 대상에 대한 스키마 및 테이블에 대한 정보를 작성해 줍니다. 

    또한 Migration SourceTargetTable정보 및 컬럼정보 등이 변경해야 하는 경우 변환 규칙에 추가해 주면 됩니다.


Tip. 실제 Migration 시에는 테이블 수가 많고, 특정 조건에 맞추어 Task가 분리되기 때문에 GUI보다 JSON형태로 관리를 하는 것이 더 효율적입니다.

4. TASK 모니터링

CDC 동기화 중 또는 Cut-Over 시점에는 Task RI에 대한 모니터링이 필요합니다. 그에 따라서 사용할수 있는 2가지 방식의 Task 모니터링 방법을 기재하였습니다.


4-1) CloudWatch

  • RI 및 Task 각각에 대한 CloudWatch 메트릭 대시보드 구성


  • AWS Cloudwatch 서비스 항목에 들어가 대시보드 생성


  • 각 위젯 구성 JSON 예시는 아래와 같습니다.
    • RI CloudWatch JSON
      {
          "widgets": [
              {
                  "type": "metric",
                  "x": 0,
                  "y": 0,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CPUUtilization", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 6,
                  "y": 12,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "ReadThroughput", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 0,
                  "y": 6,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "FreeableMemory", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 12,
                  "y": 18,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "WriteLatency", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 6,
                  "y": 0,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "ServiceCPUUtilization", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 0,
                  "y": 30,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "FreeStorageSpace", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 12,
                  "y": 6,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "ServiceMemoryUsage", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 6,
                  "y": 24,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "SwapUsage", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 18,
                  "y": 0,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "AvailableMemory", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 6,
                  "y": 6,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "FreeMemory", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 0,
                  "y": 12,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "ReadIOPS", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 12,
                  "y": 24,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "DiskQueueDepth", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 12,
                  "y": 0,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "NetworkTransmitThroughput", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 0,
                  "y": 18,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "WriteIOPS", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 0,
                  "y": 24,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "NetworkReceiveThroughput", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 12,
                  "y": 12,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "ReadLatency", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "type": "metric",
                  "x": 6,
                  "y": 18,
                  "width": 6,
                  "height": 6,
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "WriteThroughput", "ReplicationInstanceIdentifier", "RI 식별자" ]
                      ],
                      "region": "ap-northeast-2"
                  }
              }
          ]
      }
       
    • Task CloudWatch JSON
      {
          "widgets": [
              {
                  "height": 6,
                  "width": 12,
                  "y": 0,
                  "x": 0,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "FullLoadThroughputBandwidthTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2",
                      "title": "전체 로드 처리량 대역폭 대상"
                  }
              },
              {
                  "height": 6,
                  "width": 12,
                  "y": 0,
                  "x": 12,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "FullLoadThroughputRowsTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2",
                      "title": "전체 로드 처리량 행 대상"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 6,
                  "x": 0,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCIncomingChanges", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2",
                      "period": 300
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 6,
                  "x": 6,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCChangesMemorySource", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 6,
                  "x": 12,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCChangesDiskSource", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 6,
                  "x": 18,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCChangesMemoryTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 12,
                  "x": 0,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCChangesDiskTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 12,
                  "x": 6,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCThroughputBandwidthTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 12,
                  "x": 12,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCThroughputRowsSource", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 12,
                  "x": 18,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCThroughputRowsTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 18,
                  "x": 0,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCLatencySource", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              },
              {
                  "height": 6,
                  "width": 6,
                  "y": 18,
                  "x": 6,
                  "type": "metric",
                  "properties": {
                      "view": "timeSeries",
                      "stacked": false,
                      "metrics": [
                          [ "AWS/DMS", "CDCLatencyTarget", "ReplicationInstanceIdentifier", "RI 식별자", "ReplicationTaskIdentifier", "Task_1", { "region": "ap-northeast-2" } ],
      [ "...", "Task_2", { "region": "ap-northeast-2" } ],
      [ "...", "Task_3", { "region": "ap-northeast-2" } ],
      [ "...", "Task_4", { "region": "ap-northeast-2" } ],
      [ "...", "Task_5"]
                      ],
                      "region": "ap-northeast-2"
                  }
              }
          ]
      }

      : CloudWath 대시보드 구성후 모니터링을 진행하면 됩니다. 각 대시보드마다의 항목별 설명은 아래 AWS 공식문서를 참고하시기 바랍니다.

https://docs.aws.amazon.com/ko_kr/dms/latest/userguide/CHAP_Monitoring.html

 

AWS DMS 작업 모니터링 - AWS 데이터베이스 마이그레이션 서비스

전체 로드 중에 커밋 속도 값을 줄이려면 AWS DMS 콘솔을 열고 데이터베이스 마이그레이션 작업을 선택한 다음 작업을 생성하거나 수정합니다. 고급 설정을 확장하고 전체 로드 중 커밋 비율 값을

docs.aws.amazon.com

 

4-2) DB 테이블 모니터링

  • 아래 이미지에서 보이는 것과 같이 3-5)Task 생성 단계에서 생성한 복제 내역 awsdms_history 테이블을 활용하여 CDC 진행사항을 체크할 수 있습니다. 

  • 예시 SQL:
select * from (

               select "timeslot" + INTERVAL '9' HOUR as "한국시간", 
                      "server_name" as server_name, 
                      "task_name" as task_name, 
                      "timeslot_type" as task_type, 
                      "timeslot_duration" as "timeslot(분)",
                      round("timeslot_latency" / 60, 3)  as "지연시간(분)",
                      "timeslot_records" as "timeslot내의 처리량(rows)" ,
                      "timeslot_records" as "timeslot내의 처리량(MB)"
                      from mz."awsdms_history" a 
                      where 1=1
                    -- and "task_name" = ''
                    -- and "task_name" = ''
                    -- and "task_name" = ''

order by "timeslot" desc)
where rownum <= 100;
  • 위 SQL은 실제 프로젝트 수행중 Cut-over시점에 Log 주기를 1~3분으로 설정 후 CDC 모니터링을 진행할때 사용한 것입니다.

    쿼리를 실행하게 되면, 나오는 컬럼 중 "지연시간()", "timeslot내의 처리량(rows)", "timeslot내의 처리량(MB)"을 확인하고 Cut-Over를 진행하면 됩니다. , 지연시간이 없고, 현재 Data반영 건수가 0, Size(MB)0이 될 경우 Cut-Over를 진행하면 됩니다. (해당 값의 row3건 이상 일 경우 이후 작업 시작했었음)


    프로젝트 중에는 해당 Log 쌓는 시간을 2분으로 설정, Application 기동을 중지한 뒤 약 10분간 해당 SQL을 수행한 뒤 Data가 들어오지 않는 것을 확인한 뒤 CDC 중지 및 RDS로의 전환을 진행하였습니다.

 


5. DMS적용 Case 소개

5-1) ORA-01555 오류 (Snapshot too old) 발생

  • 사례: 대용량 테이블을 Task에서 실행 시 ORA-01555 : snapshot too old 에러가 발생
  • 원인: Source(On-Prem) Oracle DBundo_retention 설정값이 부족하여 발생
  • 조치: UNDO_RETENTION을 ASIS:10800 TOBE: 43200으로 조정

5-2) CLOB 데이터 깨짐

  • 사례: 일부 서비스에서 DMS를 이용한 Data 전송 및 Cut-Over 이후 CLOB 데이터 손상 발견 
  • AWS Document상에는 CLOBDMS를 이용하여 이관이 가능하다고 되어 있고, 실제로 RDS로 전환후 정상적으로 이관 되는 것을 확인. 다만, 일부 서비스에 대해서만 현상 발생
  • 조치: CLOB만 별도 방식으로 이관

5-3) 스토리지 감소 현상

  • 사례 : Source에서 RDS로 DMS를 통한 이관 수행시 Oracle Reorg 효과로 인해 테이블 사이즈 감소현상 확인

5-4) Data 전송 속도 향상을 위한 Task 분리 전략

  • Table상에 LOB 존재 여부로 구분하고 존재하지 않는 Table의 경우 100G로 기준을 세워 Big Table과 Small Table로 구분하여 Task를 생성 진행
  • 위 내용으로 그룹화하여 Task를 분리해서 DMS를 수행하게 될 경우 병렬 작업을 통해 전체 Data전송 속도가 향상되는 효과가 있었습니다.


6. IAM 권한 구성

실제 프로젝트 수행중에는 AWS Administrator계정을 받는 경우가 거의 없습니다.. 그래서 IAM의 권한을 받은 후 사용하게 되는데 권한 문제에서 생각보다 많은 시간을 사용하는 경우가 많습니다.

때문에, DMS를 이용하여 RDS로 이관하는데 필요한 IAM 권한을 작성하였으니 참고하시기 바랍니다.


필요 역할

  • AmazonDMSCloudWatchLogsRoles
  • AmazonDMSVPCManagementRole
  • AWSMigrationHubDMSAccess
  • MigrationHubDMSAccessServiceRolePolicy
  • AWSDMSFleetAdvisorServiceRolePolicy
  • AmazonRDSFullAccess
  • AmazonS3FullAccess

정책 JSON 예시

IAM 정책 구성은 문서 내 전체 JSON을 활용하여 작성하며, 주요 권한은 CloudWatch, DMS, RDS, EC2 관련 API 접근입니다.

-- DMS사용을 하기 위한 AWS Role
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "VisualEditor0",
			"Effect": "Allow",
			"Action": [
				"logs:DescribeLogGroups",
				"mgh:ListMigrationTasks",
				"ec2:ModifyNetworkInterfaceAttribute",
				"ec2:DeleteNetworkInterface",
				"ec2:DescribeSecurityGroups",
				"ec2:CreateNetworkInterface",
				"ec2:DescribeInternetGateways",
				"ec2:DescribeAvailabilityZones",
				"mgh:GetHomeRegion",
				"ec2:DescribeVpcs",
				"mgh:NotifyApplicationState",
				"ec2:DescribeSubnets",
				"mgh:DescribeApplicationState"
			],
			"Resource": "*"
		},
		{
			"Sid": "VisualEditor1",
			"Effect": "Allow",
			"Action": [
				"mgh:CreateProgressUpdateStream",
				"logs:DescribeLogStreams"
			],
			"Resource": [
				"arn:aws:logs:*:*:log-group:dms-tasks-*",
				"arn:aws:logs:*:*:log-group:dms-serverless-replication-*",
				"arn:aws:mgh:*:*:progressUpdateStream/DMS"
			]
		},
		{
			"Sid": "VisualEditor2",
			"Effect": "Allow",
			"Action": [
				"mgh:DescribeMigrationTask",
				"mgh:AssociateDiscoveredResource",
				"mgh:ListDiscoveredResources",
				"mgh:ImportMigrationTask",
				"mgh:ListCreatedArtifacts",
				"mgh:DisassociateDiscoveredResource",
				"mgh:AssociateCreatedArtifact",
				"mgh:NotifyMigrationTaskState",
				"logs:CreateLogGroup",
				"mgh:DisassociateCreatedArtifact",
				"mgh:PutResourceAttributes"
			],
			"Resource": [
				"arn:aws:mgh:*:*:progressUpdateStream/DMS/*",
				"arn:aws:logs:*:*:log-group:dms-tasks-*",
				"arn:aws:logs:*:*:log-group:dms-serverless-replication-*:log-stream:"
			]
		},
		{
			"Sid": "VisualEditor3",
			"Effect": "Allow",
			"Action": [
				"mgh:DescribeMigrationTask",
				"logs:CreateLogStream",
				"mgh:AssociateDiscoveredResource",
				"mgh:ListDiscoveredResources",
				"mgh:ImportMigrationTask",
				"mgh:ListCreatedArtifacts",
				"mgh:DisassociateDiscoveredResource",
				"mgh:AssociateCreatedArtifact",
				"mgh:NotifyMigrationTaskState",
				"mgh:DisassociateCreatedArtifact",
				"mgh:PutResourceAttributes"
			],
			"Resource": [
				"arn:aws:logs:*:*:log-group:dms-tasks-*:log-stream:dms-task-*",
				"arn:aws:logs:*:*:log-group:dms-serverless-replication-*:log-stream:dms-serverless-*",
				"arn:aws:mgh:*:*:progressUpdateStream/DMS/migrationTask/*"
			]
		},
		{
			"Sid": "VisualEditor4",
			"Effect": "Allow",
			"Action": "logs:PutLogEvents",
			"Resource": [
				"arn:aws:logs:*:*:log-group:dms-tasks-*:log-stream:dms-task-*",
				"arn:aws:logs:*:*:log-group:dms-serverless-replication-*:log-stream:dms-serverless-*"
			]
		},
		{
			"Sid": "VisualEditor5",
			"Effect": "Allow",
			"Action": [
				"mgh:NotifyApplicationState",
				"mgh:DescribeApplicationState"
			],
			"Resource": "arn:aws:mgh:*:*:progressUpdateStream/DMS/*"
		},
		{
			"Sid": "VisualEditor6",
			"Effect": "Allow",
			"Action": [
				"iam:PassRole",
				"iam:ListRoles",
				"iam:GetRole",
				"iam:CreateRole",
				"kms:*",
				"logs:GetLogEvents"
			],
			"Resource": "*"
		},
		{
			"Effect": "Allow",
			"Action": "cloudwatch:PutMetricData",
			"Resource": "*",
			"Condition": {
				"StringEquals": {
					"cloudwatch:namespace": "AWS/DMS/FleetAdvisor"
				}
			}
		},
		{
			"Sid": "Statement1",
			"Effect": "Allow",
			"Action": [
				"dms:*"
			],
			"Resource": [
				"*"
			]
		},
		{
			"Sid": "Statement2",
			"Effect": "Allow",
			"Action": [
				"rds:*"
			],
			"Resource": [
				"*"
			]
		},
		{
			"Sid": "Statement3",
			"Effect": "Allow",
			"Action": [
				"ec2:*"
			],
			"Resource": [
				"*"
			]
		},
		{
			"Sid": "Statement4",
			"Effect": "Allow",
			"Action": [
				"cloudwatch:*"
			],
			"Resource": [
				"*"
			]
		}
	]
}

마무리

이 문서가 AWS DMS 기반 Oracle to RDS 마이그레이션 프로젝트를 준비하시는 분들에게 실질적인 가이드를 제공하길 바랍니다. 실무 중심의 경험을 바탕으로 작성된 만큼, 실제 작업 시 발생할 수 있는 문제와 해결 방안까지 도움이 되었으면 합니다.

추가적으로 더 자세한 정보가 필요하실 경우 아래 AWS 공식 Document를 참고하시기 바랍니다.
https://docs.aws.amazon.com/ko_kr/dms/latest/userguide/CHAP_Source.Oracle.html#CHAP_Source.Oracle.Self-Managed

 

Oracle 데이터베이스를 AWS DMS에서 소스로 사용 - AWS 데이터베이스 마이그레이션 서비스

cp, mv, orapki, mkstore 같은 OS 수준 명령으로 인해 ASM 위치에 저장된 wallet 파일이 손상되므로 Oracle ASM(Automatic Storage Management) 위치에 생성된 TDE wallet을 조작할 수 없습니다. 이 제한은 ASM 위치에 저장

docs.aws.amazon.com

 

 

AWS의 파트너사인 MegazoneCloud 소속으로  AWS Ambassador로 활동하며 작성한 내용입니다.
AWS의 서비스를 소개하고, 실제 업무에서 사용한 사례들에 대한 내용들을 담고 있습니다.
Written By. Karam Kim