

# RDS Custom for SQL Server 인스턴스를 특정 시점으로 복원
<a name="custom-backup.pitr-sqs"></a>

DB 인스턴스를 특정 시점(PITR)으로 복원하여 새로운 DB 인스턴스를 생성할 수 있습니다. PITR을 지원하려면 DB 인스턴스에 백업 보존 기능이 활성화되어 있어야 합니다.

RDS Custom for SQL Server DB 인스턴스의 가장 빠른 복원 가능 시간은 여러 요소에 따라 달라지지만, 일반적으로 현재 시간에서 5분 이내입니다. DB 인스턴스의 최근 복원 가능 시간을 확인하려면 AWS CLI[describe-db-instances](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html) 명령을 사용한 후 DB 인스턴스의 `LatestRestorableTime` 필드에 반환되는 값을 살펴봅니다. Amazon RDS 콘솔에서 각 DB 인스턴스의 복원 가능한 최신 시간을 보려면 [ **자동 백업**을 선택합니다.

백업 보존 기간 중 어느 특정 시점으로든 복원할 수 있습니다. 각 DB 인스턴스의 복원 가능한 가장 빠른 시간을 보려면 Amazon RDS 콘솔에서 **자동 백업**을 선택합니다.

PITR에 대한 일반적인 정보는 [Amazon RDS에서 DB 인스턴스를 지정된 시간으로 복원](USER_PIT.md) 섹션을 참조하세요.

**Topics**
+ [RDS Custom for SQL Server에 대한 PITR 고려 사항](#custom-backup.pitr.sqlserver)
+ [인스턴스 클래스 유형별 PITR 대상 데이터베이스 수](#custom-backup.pitr.sqlserver.eligiblecountperinstance)
+ [데이터베이스를 PITR에 포함되지 않도록 설정](#custom-backup.pitr.sqlserver.ineligible)
+ [Amazon S3의 트랜잭션 로그](#custom-backup.pitr.sqlserver.tlogs)
+ [AWS Management Console, AWS CLI 또는 RDS API를 사용하여 PITR 복원합니다.](#custom-backup.pitr-sqs-concli)

## RDS Custom for SQL Server에 대한 PITR 고려 사항
<a name="custom-backup.pitr.sqlserver"></a>

RDS Custom for SQL Server에서 PITR은 다음과 같은 중요한 면에서 Amazon RDS의 PITR과 다릅니다.
+ PITR은 DB 인스턴스의 데이터베이스만 복원합니다. C: 드라이브의 운영 체제 또는 파일은 복원되지 않습니다.
+ RDS Custom for SQL Server DB 인스턴스의 경우 데이터베이스가 자동으로 백업되며 다음 조건에서만 PITR을 사용할 수 있습니다.
  + 데이터베이스가 온라인 상태입니다.
  + 복구 모델이 `FULL`로 설정되어 있습니다.
  + 쓰기가 가능합니다.
  + D: 드라이브에 실존 파일이 있습니다.
  + `rds_pitr_blocked_databases` 테이블에 등록되어 있지 않습니다. 자세한 내용은 [데이터베이스를 PITR에 포함되지 않도록 설정](#custom-backup.pitr.sqlserver.ineligible) 섹션을 참조하세요.
+ PITR 대상 데이터베이스는 데이터베이스 ID의 순서에 따라 결정됩니다. RDS Custom for SQL Server는 DB 인스턴스당 최대 5,000개의 데이터베이스를 허용합니다. 그러나 RDS Custom for SQL Server DB 인스턴스에 대해 PITR 작업을 통해 복원되는 최대 데이터베이스 수는 인스턴스 클래스 유형에 따라 달라집니다. 자세한 내용은 [인스턴스 클래스 유형별 PITR 대상 데이터베이스 수](#custom-backup.pitr.sqlserver.eligiblecountperinstance) 섹션을 참조하세요.

  PITR에 포함되지 않는 다른 데이터베이스는 PITR에 사용되는 자동 스냅샷 백업을 비롯하여 DB 스냅샷에서 복원할 수 있습니다.
+ 새로운 데이터베이스를 추가하거나, 데이터베이스 이름을 바꾸거나, PITR 대상 데이터베이스를 복원하면 DB 인스턴스의 스냅샷이 시작됩니다.
+ PITR 대상인 최대 데이터베이스 수는 데이터베이스 인스턴스가 규모 조정 컴퓨팅 작업을 거칠 때 대상 인스턴스 클래스 유형에 따라 달라집니다. 인스턴스의 더 많은 데이터베이스가 PITR에 적합하도록 인스턴스를 확장하면 새 스냅샷이 생성됩니다.
+ 복원된 데이터베이스의 이름은 소스 DB 인스턴스와 동일합니다. 다른 이름을 지정할 수 없습니다.
+ `AWSRDSCustomSQLServerIamRolePolicy`는 다른 AWS 서비스에 대한 액세스가 필요합니다. 자세한 내용은 [AWSRDSCustomSQLServerInstanceRole에 액세스 정책 추가](custom-setup-sqlserver.md#custom-setup-sqlserver.iam.add-policy) 섹션을 참조하세요.
+ RDS Custom for SQL Server에는 표준 시간대 변경이 지원되지 않습니다. 운영 체제 또는 DB 인스턴스 시간대를 변경하면 PITR(및 기타 자동화)이 작동하지 않습니다.

## 인스턴스 클래스 유형별 PITR 대상 데이터베이스 수
<a name="custom-backup.pitr.sqlserver.eligiblecountperinstance"></a>

다음 표에는 인스턴스 클래스 유형에 따라 PITR에 사용할 수 있는 최대 데이터베이스 수가 나와 있습니다.


| 인스턴스 클래스 유형 | PITR에 사용할 수 있는 최대 데이터베이스 수 | 
| --- | --- | 
| db.\$1.large | 100 | 
| db.\$1.xlarge to db.\$1.2xlarge | 150 | 
| db.\$1.4xlarge to db.\$1.8xlarge | 300 | 
| db.\$1.12xlarge to db.\$1.16xlarge | 600 | 
| db.\$1.24xlarge, db.\$132xlarge | 1000 | 

`*` *서로 다른 인스턴스 클래스 유형을 나타냅니다.*

DB 인스턴스에서 PITR에 사용할 수 있는 최대 데이터베이스 수는 인스턴스 클래스 유형에 따라 다릅니다. RDS Custom for SQL Server에서 지원하는 최대 인스턴스 클래스 유형의 경우 100개부터 1,000개까지 다양합니다. SQL 서버 시스템 데이터베이스`(master, model, msdb, tempdb)`는 이 제한에 포함되지 않습니다. 대상 인스턴스 클래스 유형에 따라 DB 인스턴스를 확장하거나 축소할 때 RDS Custom은 PITR에 사용할 수 있는 데이터베이스 수를 자동으로 업데이트합니다. RDS Custom for SQL Server는 DB 인스턴스에서 PITR에 사용할 수 있는 최대 데이터베이스 수가 변경될 때 `RDS-EVENT-0352`를 전송합니다. 자세한 내용은 [사용자 지정 엔진 버전 이벤트](USER_Events.Messages.md#USER_Events.Messages.CEV) 섹션을 참조하세요.

**참고**  
100개 이상의 데이터베이스에 대한 PITR 지원은 2023년 8월 26일 이후에 생성된 DB 인스턴스에서만 사용할 수 있습니다. 2023년 8월 26일 이전에 생성된 인스턴스의 경우 PITR에 사용할 수 있는 최대 데이터베이스 수는 인스턴스 클래스에 관계없이 100개입니다. 2023년 8월 26일 이전에 생성된 DB 인스턴스의 데이터베이스 100개 이상에 대해 PITR 지원을 활성화하려면 다음 작업을 수행할 수 있습니다.  
DB 엔진 버전을 15.00.4322.2.v1 이상으로 업그레이드

PITR 작업 중에 RDS Custom은 복원 시 소스 DB 인스턴스에서 PITR에 속했던 모든 데이터베이스를 복원합니다. 대상 DB 인스턴스가 복원 작업을 완료하고 백업 보존을 활성화하면 대상 DB 인스턴스에서 PITR에 사용할 수 있는 최대 데이터베이스 수를 기준으로 DB 인스턴스가 백업을 시작합니다.

예를 들어, DB 인스턴스가 200개의 데이터베이스가 있는 `db.*.xlarge`에서 실행되는 경우는 다음과 같습니다.

1. RDS Custom for SQL Server는 PITR 백업을 위해 데이터베이스 ID를 기준으로 정렬된 처음 150개의 데이터베이스를 선택합니다.

1. db.\$1.4xlarge까지 확장하도록 인스턴스를 수정합니다.

1. 컴퓨팅 확장 작업이 완료되면 RDS Custom for SQL Server는 데이터베이스 ID를 기준으로 정렬된 처음 300개의 데이터베이스를 PITR 백업용으로 선택합니다. 이제 PITR 요구 사항 조건을 충족하는 200개 데이터베이스 각각이 PITR을 사용할 수 있습니다.

1. 이제 다시 db.\$1.xlarge로 인스턴스 규모를 축소합니다.

1. 컴퓨팅 축소 작업이 완료되면 RDS Custom for SQL Server는 데이터베이스 ID를 기준으로 정렬된 처음 150개의 데이터베이스를 PITR 백업용으로 다시 선택합니다.

## 데이터베이스를 PITR에 포함되지 않도록 설정
<a name="custom-backup.pitr.sqlserver.ineligible"></a>

PITR에서 개별 데이터베이스를 제외하도록 선택할 수 있습니다. 이렇게 하려면 `database_id` 값을 `rds_pitr_blocked_databases` 테이블에 넣으면 됩니다. 다음 SQL 스크립트를 사용하여 테이블을 생성합니다.

**rds\$1pitr\$1blocked\$1databases 테이블을 생성하는 방법**
+ 다음 SQL 스크립트를 실행합니다.

  ```
  create table msdb..rds_pitr_blocked_databases
  (
  database_id INT NOT NULL,
  database_name SYSNAME NOT NULL,
  db_entry_updated_date datetime NOT NULL DEFAULT GETDATE(),
  db_entry_updated_by SYSNAME NOT NULL DEFAULT CURRENT_USER,
  PRIMARY KEY (database_id)
  );
  ```

대상 데이터베이스 및 대상이 아닌 데이터베이스 목록은 Amazon S3 버킷 `do-not-delete-rds-custom-$ACCOUNT_ID-$REGION-unique_identifier`의 `RDSCustomForSQLServer/Instances/DB_instance_resource_ID/TransactionLogMetadata` 디렉터리에 있는 `RI.End` 파일을 참조하세요. `RI.End` 파일에 대한 자세한 내용은 [Amazon S3의 트랜잭션 로그](#custom-backup.pitr.sqlserver.tlogs)를 참조하세요.

다음 SQL 스크립트를 사용하여 PITR 대상인 데이터베이스 목록을 확인할 수도 있습니다. `@limit` 변수를 인스턴스 클래스의 PITR에 사용할 수 있는 최대 데이터베이스 수로 설정합니다. 자세한 내용은 [인스턴스 클래스 유형별 PITR 대상 데이터베이스 수](#custom-backup.pitr.sqlserver.eligiblecountperinstance) 섹션을 참조하세요.

**DB 인스턴스 클래스의 PITR 대상인 데이터베이스 목록을 확인하려면**
+ 다음 SQL 스크립트를 실행합니다.

  ```
  DECLARE @Limit INT;
  SET @Limit = (insert-database-instance-limit-here);
  
  USE msdb;
  IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND  TABLE_NAME = 'rds_pitr_blocked_databases'))
      WITH TABLE0 AS (
          SELECT hdrs.database_id as DatabaseId, sdb.name as DatabaseName, 'ALWAYS_ON_NOT_WRITABLE_REPLICA' as Reason, NULL as DatabaseNameOnPitrTable
          FROM sys.dm_hadr_database_replica_states hdrs
          INNER JOIN sys.databases sdb ON sdb.database_id = hdrs.database_id
          WHERE (hdrs.is_local = 1 AND hdrs.is_primary_replica = 0) 
          OR (sys.fn_hadr_is_primary_replica (sdb.name) = 1 AND DATABASEPROPERTYEX (sdb.name, 'Updateability') = 'READ_ONLY')
      ),
      TABLE1 as (
              SELECT dbs.database_id as DatabaseId, sysdbs.name as DatabaseName, 'OPTOUT' as Reason,
              CASE WHEN dbs.database_name = sysdbs.name THEN NULL ELSE dbs.database_name END AS DatabaseNameOnPitrTable
              FROM msdb.dbo.rds_pitr_blocked_databases dbs
              INNER JOIN sys.databases sysdbs ON dbs.database_id = sysdbs.database_id
              WHERE sysdbs.database_id > 4
              ),
      TABLE2 as (
              SELECT
              db.name AS DatabaseName,
              db.create_date AS CreateDate,
              db.state_desc AS DatabaseState,
              db.database_id AS DatabaseId,
              rs.database_guid AS DatabaseGuid,
              rs.last_log_backup_lsn AS LastLogBackupLSN,
              rs.recovery_fork_guid RecoveryForkGuid,
              rs.first_recovery_fork_guid AS FirstRecoveryForkGuid,
              db.recovery_model_desc AS RecoveryModel,
              db.is_auto_close_on AS IsAutoClose,
              db.is_read_only as IsReadOnly,
              NEWID() as FileName,
              CASE WHEN(db.state_desc = 'ONLINE'
                      AND db.recovery_model_desc != 'SIMPLE' 
                      AND((db.is_auto_close_on = 0 and db.collation_name IS NOT NULL) OR db.is_auto_close_on = 1)) 
                      AND db.is_read_only != 1
                      AND db.user_access = 0
                      AND db.source_database_id IS NULL
                      AND db.is_in_standby != 1
                      THEN 1 ELSE 0 END AS IsPartOfSnapshot,
              CASE WHEN db.source_database_id IS NULL THEN 0 ELSE 1 END AS IsDatabaseSnapshot
              FROM sys.databases db
              INNER JOIN sys.database_recovery_status rs
              ON db.database_id = rs.database_id
              WHERE DB_NAME(db.database_id) NOT IN('tempdb') AND
              db.database_id NOT IN (SELECT DISTINCT DatabaseId FROM TABLE1) AND
              db.database_id NOT IN (SELECT DISTINCT DatabaseId FROM TABLE0)
          ),
          TABLE3 as(
              Select @Limit+count(DatabaseName) as TotalNumberOfDatabases from TABLE2 where TABLE2.IsPartOfSnapshot=1 and DatabaseName in ('master','model','msdb')
          )
          SELECT TOP(SELECT TotalNumberOfDatabases from TABLE3)  DatabaseName,CreateDate,DatabaseState,DatabaseId from TABLE2 where TABLE2.IsPartOfSnapshot=1
          ORDER BY TABLE2.DatabaseID ASC
  ELSE
      WITH TABLE0 AS (
          SELECT hdrs.database_id as DatabaseId, sdb.name as DatabaseName, 'ALWAYS_ON_NOT_WRITABLE_REPLICA' as Reason, NULL as DatabaseNameOnPitrTable
          FROM sys.dm_hadr_database_replica_states hdrs
          INNER JOIN sys.databases sdb ON sdb.database_id = hdrs.database_id
          WHERE (hdrs.is_local = 1 AND hdrs.is_primary_replica = 0) 
          OR (sys.fn_hadr_is_primary_replica (sdb.name) = 1 AND DATABASEPROPERTYEX (sdb.name, 'Updateability') = 'READ_ONLY')
      ),
      TABLE1 as (
              SELECT
              db.name AS DatabaseName,
              db.create_date AS CreateDate,
              db.state_desc AS DatabaseState,
              db.database_id AS DatabaseId,
              rs.database_guid AS DatabaseGuid,
              rs.last_log_backup_lsn AS LastLogBackupLSN,
              rs.recovery_fork_guid RecoveryForkGuid,
              rs.first_recovery_fork_guid AS FirstRecoveryForkGuid,
              db.recovery_model_desc AS RecoveryModel,
              db.is_auto_close_on AS IsAutoClose,
              db.is_read_only as IsReadOnly,
              NEWID() as FileName,
              CASE WHEN(db.state_desc = 'ONLINE'
                      AND db.recovery_model_desc != 'SIMPLE' 
                      AND((db.is_auto_close_on = 0 and db.collation_name IS NOT NULL) OR db.is_auto_close_on = 1)) 
                      AND db.is_read_only != 1
                      AND db.user_access = 0
                      AND db.source_database_id IS NULL
                      AND db.is_in_standby != 1
                      THEN 1 ELSE 0 END AS IsPartOfSnapshot,
              CASE WHEN db.source_database_id IS NULL THEN 0 ELSE 1 END AS IsDatabaseSnapshot
              FROM sys.databases db
              INNER JOIN sys.database_recovery_status rs
              ON db.database_id = rs.database_id
              WHERE DB_NAME(db.database_id) NOT IN('tempdb') AND
              db.database_id NOT IN (SELECT DISTINCT DatabaseId FROM TABLE0)
          ),
          TABLE2 as(
              SELECT @Limit+count(DatabaseName) as TotalNumberOfDatabases from TABLE1 where TABLE1.IsPartOfSnapshot=1 and DatabaseName in ('master','model','msdb')
          )
          select top(select TotalNumberOfDatabases from TABLE2)  DatabaseName,CreateDate,DatabaseState,DatabaseId from TABLE1 where TABLE1.IsPartOfSnapshot=1
          ORDER BY TABLE1.DatabaseID ASC
  ```

**참고**  
심볼 링크만 있는 데이터베이스도 PITR 작업 대상인 데이터베이스에서 제외됩니다. 위 쿼리는 이 기준에 따라 필터링되지 않습니다.

## Amazon S3의 트랜잭션 로그
<a name="custom-backup.pitr.sqlserver.tlogs"></a>

백업 보존 기간에 따라 RDS Custom for SQL Server DB 인스턴스에 대한 트랜잭션 로그가 자동으로 추출되어 Amazon S3에 업로드되는지 여부가 결정됩니다. 0이 아닌 값은 자동 백업이 생성되고 RDS Custom 에이전트가 트랜잭션 로그를 5분마다 S3에 업로드함을 의미합니다.

S3의 트랜잭션 로그 파일은 DB 인스턴스를 생성할 때 입력한 AWS KMS key를 사용하여 유후 상태로 암호화됩니다. 자세한 내용은 *Amazon Simple Storage Service 사용 설명서*의 [서버 측 암호화를 사용하여 데이터 보호](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html)를 참조하세요.

각 데이터베이스의 트랜잭션 로그는 `do-not-delete-rds-custom-$ACCOUNT_ID-$REGION-unique_identifier`라는 이름이 지정된 S3 버킷에 업로드됩니다. S3 버킷의 `RDSCustomForSQLServer/Instances/DB_instance_resource_ID` 디렉터리에는 다음 두 개의 하위 디렉터리가 있습니다.
+ `TransactionLogs` - 각 데이터베이스 및 해당 메타데이터에 대한 트랜잭션 로그를 포함합니다.

  트랜잭션 로그 파일 이름은 `yyyyMMddHHmm.database_id.timestamp`와 같은 패턴을 따릅니다.

  ```
  202110202230.11.1634769287
  ```

  `_metadata`라는 접미사가 있는 동일한 파일 이름에는 로그 시퀀스 번호, 데이터베이스 이름 및 `RdsChunkCount`와 같은 트랜잭션 로그에 대한 정보가 포함되어 있습니다. `RdsChunkCount`는 단일 트랜잭션 로그 파일을 나타내는 실제 파일 수를 결정합니다. 트랜잭션 로그 파일의 물리적 청크를 의미하는 접미사 `_0001`, `_0002` 등이 있는 파일이 표시될 수 있습니다. 청크된 트랜잭션 로그 파일을 사용하려면 청크를 다운로드한 후 병합해야 합니다.

  다음과 같은 파일이 있는 경우를 생각해 봅니다.
  + `202110202230.11.1634769287`
  + ` 202110202230.11.1634769287_0001`
  + ` 202110202230.11.1634769287_0002 `
  + ` 202110202230.11.1634769287_metadata`

  `RdsChunkCount`은 `3`입니다. 파일 병합 순서는 `202110202230.11.1634769287`, ` 202110202230.11.1634769287_0001`, `202110202230.11.1634769287_0002`입니다.
+ `TransactionLogMetadata` - 트랜잭션 로그 추출의 각 반복에 대한 메타데이터 정보를 포함합니다.

  `RI.End` 파일에는 트랜잭션 로그가 추출된 모든 데이터베이스 및 존재하지만 트랜잭션 로그가 추출되지 않은 모든 데이터베이스에 대한 정보가 들어 있습니다. 예를 들어, `RI.End` 파일 이름은 `yyyyMMddHHmm.RI.End.timestamp` 패턴을 따릅니다.

  ```
  202110202230.RI.End.1634769281
  ```

## AWS Management Console, AWS CLI 또는 RDS API를 사용하여 PITR 복원합니다.
<a name="custom-backup.pitr-sqs-concli"></a>

AWS Management Console, AWS CLI 또는 RDS API를 사용하여 RDS Custom for SQL Server DB 인스턴스를 특정 시점으로 복원할 수 있습니다.

### 콘솔
<a name="custom-backup-sqs.pitr2.CON"></a>

**RDS Custom DB 인스턴스를 지정된 시간으로 복원하는 방법**

1. AWS Management Console에 로그인한 후 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)에서 Amazon RDS 콘솔을 엽니다.

1. 탐색 창에서 **자동 백업(Automated backups)**을 선택합니다.

1. 복원하려는 RDS Custom DB 인스턴스를 선택합니다.

1. **작업**에서 **특정 시점으로 복구**를 선택합니다.

   **특정 시점으로 복구** 창이 나타납니다.

1. **최근 복원 가능 시간**을 선택하여 가능한 최근 시간으로 복원하거나, **사용자 지정**을 선택하여 시간을 선택합니다.

   **사용자 지정(Custom)**을 선택한 경우 인스턴스를 복원하려는 날짜와 시간을 입력합니다.

   시간은 현지 시간대로 표시됩니다. 즉, 협정 세계시(UTC)에서 오프셋으로 표시됩니다. 예를 들어 UTC-5는 동부 표준시/하절기 중부 표준시입니다.

1. **DB 인스턴스 식별자(DB instance identifier)**에는 복원된 대상 RDS Custom DB 인스턴스의 이름을 입력합니다. 이름은 고유해야 합니다.

1. 필요에 따라 DB 인스턴스 클래스와 같은 기타 옵션을 선택합니다.

1. **특정 시점으로 복구**를 선택합니다.

### AWS CLI
<a name="custom-backup-sqs.pitr2.CLI"></a>

새로운 RDS Custom DB 인스턴스를 생성하려면 [restore-db-instance-to-point-in-time](https://docs.aws.amazon.com/cli/latest/reference/rds/restore-db-instance-to-point-in-time.html) AWS CLI 명령을 사용하여 DB 인스턴스를 지정된 시간으로 복원합니다.

다음 옵션 중 하나를 사용하여 복원 원본으로 사용할 백업을 지정합니다.
+ `--source-db-instance-identifier mysourcedbinstance`
+ `--source-dbi-resource-id dbinstanceresourceID`
+ `--source-db-instance-automated-backups-arn backupARN`

옵션은 `custom-iam-instance-profile` 필수입니다.

다음 예제는 지정된 시간을 기준으로 `my-custom-db-instance`를 `my-restored-custom-db-instance`라는 새로운 DB 인스턴스로 복원합니다.

**Example**  
대상 LinuxmacOS, 또는Unix:  

```
1. aws rds restore-db-instance-to-point-in-time \
2.     --source-db-instance-identifier my-custom-db-instance\
3.     --target-db-instance-identifier my-restored-custom-db-instance \
4.     --custom-iam-instance-profile AWSRDSCustomInstanceProfileForRdsCustomInstance \
5.     --restore-time 2022-10-14T23:45:00.000Z
```
Windows의 경우:  

```
1. aws rds restore-db-instance-to-point-in-time ^
2.     --source-db-instance-identifier my-custom-db-instance ^
3.     --target-db-instance-identifier my-restored-custom-db-instance ^
4.     --custom-iam-instance-profile AWSRDSCustomInstanceProfileForRdsCustomInstance ^
5.     --restore-time 2022-10-14T23:45:00.000Z
```