연습 - 특정 시점으로 복원
이 연습에서는 PITR(특정 시점 복원)을 사용하여 일반적인 오류에서 복구하는 방법을 학습합니다. 포털에서 또는 프로그래밍 방식으로 이 프로세스를 쉽게 수행할 수 있습니다. 이 연습에서는 Azure CLI를 사용하여 수행하는 방법을 알아봅니다.
설정: 스크립트를 사용하여 Azure SQL Database 배포
오른쪽 터미널에는 브라우저를 사용하여 Azure와 상호 작용하는 한 가지 방법인 Azure Cloud Shell이 나와 있습니다. 연습을 시작하기 전에 스크립트를 실행하여 AdventureWorks 데이터베이스가 포함된 환경인 Azure SQL Database를 만들어야 합니다. 스크립트에는 암호 및 로컬 IP 주소에 관련된 몇 가지 프롬프트가 있습니다.
이러한 스크립트를 완료하는 데 3~5분이 소요됩니다. 암호, 고유 ID 및 영역은 다시 표시되지 않으므로 기록해 두어야 합니다.
필요한 IP 주소를 가져오려면 VPN 서비스에서 연결을 끊고 이 브라우저가 아니라 로컬 PowerShell 창에서
(Invoke-WebRequest -Uri "https://ipinfo.io/ip").Content
를 실행해야 합니다. 결과 IP 주소를 확인합니다.이 페이지의 오른쪽에 있는 Azure Cloud Shell에서 다음 스크립트를 실행합니다. 메시지가 표시되면 복잡한 암호 및 공용 IP 주소를 입력합니다.
$adminSqlLogin = "cloudadmin" $password = Read-Host "Your username is 'cloudadmin'. Please enter a password for your Azure SQL Database server that meets the password requirements" # Prompt for local IP address $ipAddress = Read-Host "Disconnect your VPN, open PowerShell on your machine and run '(Invoke-WebRequest -Uri "https://ipinfo.io/ip").Content'. Please enter the value (include periods) next to 'Address': " # Get resource group and location and random string $resourceGroup = Get-AzResourceGroup | Where ResourceGroupName -like "<rgn>Sandbox resource group name</rgn>" $resourceGroupName = "<rgn>Sandbox resource group name</rgn>" $uniqueID = Get-Random -Minimum 100000 -Maximum 1000000 $storageAccountName = "mslearnsa"+$uniqueID $location = $resourceGroup.Location # The logical server name has to be unique in the system $serverName = "aw-server$($uniqueID)"
Azure Cloud Shell에서 다음 스크립트를 실행하여 정보를 출력하고 저장합니다(텍스트 파일 또는 유사한 위치에). 이 정보는 이 모듈 전체에서 필요합니다. 마지막 줄은 기본적으로 실행되지 않으므로 코드를 붙여넣은 후 Enter 키를 선택해야 할 수 있습니다.
Write-Host "Please note your unique ID for future exercises in this module:" Write-Host $uniqueID Write-Host "Your resource group name is:" Write-Host $resourceGroupName Write-Host "Your resources were deployed in the following region:" Write-Host $location Write-Host "Your server name is:" Write-Host $serverName
중요
암호, 고유 ID 및 영역을 기록해 두세요. 이 정보는 모듈 전체에서 필요합니다.
다음 스크립트를 실행하여 AdventureWorks 샘플이 포함된 Azure SQL 데이터베이스 및 논리 서버를 배포합니다. 또한 이 스크립트는 IP 주소를 방화벽 규칙으로 추가하고, 클라우드용 Microsoft Defender를 사용하도록 설정하고, 예정된 단위에서 사용할 스토리지 계정을 만듭니다.
# The logical server name has to be unique in the system $serverName = "aw-server$($uniqueID)" # The sample database name $databaseName = "AdventureWorks" # The storage account name has to be unique in the system $storageAccountName = $("sql$($uniqueID)") # Create a new server with a system-wide unique server name $server = New-AzSqlServer -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -Location $location ` -SqlAdministratorCredentials $(New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $adminSqlLogin, $(ConvertTo-SecureString -String $password -AsPlainText -Force)) # Create a server firewall rule that allows access from the specified IP range and all Azure services $serverFirewallRule = New-AzSqlServerFirewallRule ` -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -FirewallRuleName "AllowedIPs" ` -StartIpAddress $ipAddress -EndIpAddress $ipAddress $allowAzureIpsRule = New-AzSqlServerFirewallRule ` -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -AllowAllAzureIPs # Create a database $database = New-AzSqlDatabase -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -DatabaseName $databaseName ` -SampleName "AdventureWorksLT" ` -Edition "GeneralPurpose" -Vcore 2 -ComputeGeneration "Gen5" # Enable Azure Defender $azureDefender = Enable-AzSqlServerAdvancedDataSecurity ` -ResourceGroupName $resourceGroupName ` -ServerName $serverName # Create a storage account $storageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroupName ` -AccountName $storageAccountName ` -Location $location ` -Type "Standard_LRS"
로컬 컴퓨터에서 SSMS를 열고 논리 서버에 대한 새 연결을 만듭니다. 서버 이름에 Azure SQL Database 논리 서버의 이름을 입력합니다. 이름을 이전에 저장하지 않은 경우 Azure Portal로 이동하여 가져올 수도 있습니다. 예:
aw-server\<unique ID>.database.windows.net
Azure Portal에서 검색창에 AdventureWorks를 입력하여 검색하여 데이터베이스 및 연결된 논리 서버를 찾을 수 있습니다.
인증 상자에 SQL Server 인증을 입력합니다. 해당하는 서버 관리자 로그인과 암호를 입력합니다(이전 연습에서 배포하는 동안 입력한 로그인 및 암호).
암호 기억 확인란을 선택한 다음 연결을 선택합니다.
참고
로컬 구성(예: VPN)에 따라 클라이언트 IP 주소는 배포 중에 사용되는 Azure Portal IP 주소와 다를 수도 있습니다. 이런 경우에는 다음 메시지가 표시됩니다. “클라이언트 IP 주소에서 서버에 액세스할 수 없습니다. Azure 계정에 로그인하고 액세스를 사용하도록 설정하는 새 방화벽 규칙을 만듭니다.” 이 메시지가 표시되면 샌드박스에 사용 중인 계정으로 로그인하고 클라이언트 IP 주소에 대한 방화벽 규칙을 추가합니다. SSMS의 팝업 마법사를 사용하여 해당 단계를 완료할 수 있습니다.
PITR 완료
계속 진행하기 전에 PITR을 수행하기 위한 권장 프로세스를 이해해야 합니다.
- 테이블 또는 데이터베이스가 실수로 삭제됩니다.
- 돌아가야 할 시간을 결정합니다. 오류가 발생하기 전이어야 합니다.
- PowerShell 또는 Azure Portal을 통해 PITR을 완료하여 해당 시간으로 돌아갑니다. 이 프로세스에서 새 데이터베이스가 배포되고 데이터베이스의 사본(예: 예를 들면 다음과 같습니다. AdventureWorks-copy.
- 새 데이터베이스(예: AdventureWorks-copy)가 사고 발생 이전의 올바른 상태인지 확인합니다.
- 원본 데이터베이스의 이름을 바꿉니다. 예를 들어 AdventureWorks에서 AdventureWorks-old로 이름을 바꿉니다.
- 새 데이터베이스의 이름을 원래 데이터베이스 이름으로 바꿉니다. 예를 들어 AdventureWorks-copy에서 AdventureWorks로 이름을 바꿉니다.
- 원본 데이터베이스를 삭제합니다. 예를 들면 다음과 같습니다. AdventureWorks-old.
이 연습에서는 다음 단계를 완료합니다.
데이터 삭제 시뮬레이트
먼저 ‘실수로’ 삭제할 테이블이 있고 테이블에 데이터가 있는지 확인하겠습니다. SalesLT.OrderDetail에서 일부 값을 살펴보겠습니다.
SSMS로 이동하고 연결을 확인/업데이트합니다. 파일>개체 탐색기 연결을 선택한 다음 옵션 단추를 선택합니다.
사용하는 연결이 특정 데이터베이스가 아닌 논리 서버에 연결되는지 확인합니다. (예를 들어 다음 스크린샷에 나온 것처럼 <default>를 사용합니다.) 또한 추가 연결 매개 변수 탭에 텍스트가 포함되어 있지 않은지 확인합니다.
데이터베이스 폴더를 확장한 다음 AdventureWorks 데이터베이스를 마우스 오른쪽 단추로 클릭하고 새 쿼리를 선택합니다. 다음 쿼리를 입력하고 실행을 선택하여 실행한 후 결과를 검토합니다.
SELECT TOP 10 * from SalesLT.SalesOrderDetail
데이터베이스에서 테이블을 삭제하여 데이터 손실을 시뮬레이트합니다.
동일한 쿼리 창에서 이 쿼리를 실행한 다음 결과 창에서 메시지 탭을 선택하고 완료 시간을 확인합니다.
DROP TABLE SalesLT.SalesOrderDetail
Important
완료 시간을 저장하세요. 나중에 필요합니다. 예:
Completion time: 2020-06-22T09:20:27.1859237-07:00
.마지막으로 데이터베이스 복원 단계를 시작하기 전에 이 페이지 오른쪽에 있는 Azure Cloud Shell에서 다음 코드를 실행하여 환경을 구성합니다.
$resourceGroup = Get-AzResourceGroup | Where ResourceGroupName -like <rgn>Sandbox resource group name</rgn> $server = Get-AzureRmSqlServer -ResourceGroupName $resourceGroup.ResourceGroupName $logical_server = $server.ServerName $resource_group = $resourceGroup.ResourceGroupName # Specify your default resource group and Azure SQL Database logical server az configure --defaults group=$resource_group sql-server=$logical_server # Confirm the defaults are set az configure --list-defaults
반환된
group
및sql-server
매개 변수는 Microsoft Learn 리소스 그룹 및 Azure SQL Database 논리 서버의 이름과 일치해야 합니다.
데이터베이스를 복원할 시간 식별
첫 번째 단계는 데이터베이스를 복원할 시간을 파악하는 것입니다. “잘못된” 트랜잭션 전에 마지막으로 “양호한” 트랜잭션이 발생한 시점을 알아야 합니다. 마지막으로 양호한 트랜잭션이 발생한 후, 잘못된 트랜잭션이 발생하기 전에 해당하는 시점으로 복원합니다.
삭제 시간을 확인하는 한 가지 방법은 이전 단계에서 기록한 DROP 문 완료 시간을 살펴보는 것입니다.
다른 방법은 Azure Portal에서 감사 로그를 사용하는 것입니다. 이 연습에서는 Log Analytics에 대한 감사를 구성하지 않았지만, 감사가 있는 경우 수행할 수 있는 작업을 살펴보겠습니다. Azure Portal에서 Azure SQL 데이터베이스로 이동할 수 있습니다. 왼쪽 창의 보안에서 감사를 선택한 다음, 감사 로그 보기를 선택할 수 있습니다. 그런 다음, Log Analytics를 선택하면 KQL(Kusto 쿼리 언어)을 사용하여 로그를 쿼리할 수 있는 쿼리 편집기로 이동합니다. SQL 전문가는 이 쿼리 언어를 사용하여 쉽게 로그를 쿼리할 수 있습니다.
그러면 다음 KQL 쿼리를 실행할 수 있습니다.
search database_name_s == "AdventureWorks" | where Category == 'SQLSecurityAuditEvents' and statement_s like 'DROP' | project format_datetime(event_time_t, 'yyyy-MM-dd hh:mm:ss.fff'), ResourceGroup, server_instance_name_s, database_name_s, statement_s, succeeded_s,client_ip_s, server_principal_name_s, application_name_s | sort by event_time_t desc
결과는 날짜와 시간이 다르고 다음 결과와 유사합니다.
참고 항목
여기에 로그가 표시되는 데 5~10분 정도 걸릴 수 있으므로 이 연습에서는 생략했습니다. 대신 이전 단계에서 기록한 완료 시간을 사용합니다. (GMT로 변환해야 합니다.) 실제 상황에서는 완료 시간이 포함된 창에 도달하지 못할 가능성이 있으므로 감사가 크게 도움이 될 수 있습니다.
이 예제에서 날짜/시간은 Log Analytics의
2020-07-24 08:06:24.386
과 SSMS의2020-07-24T13:06:24.386-07:00
입니다. 필요한 형식은 약간 다릅니다. 다음 예제를 사용하여 올바른 형식을 결정합니다. 또한 오류 발생 ‘이전’ 시점으로 복원하기 위해 0.001초를 빼는 것이 좋습니다.- Log Analytics 형식:
2020-07-24 08:06:24.386
- SSMS 형식:
2020-07-24T13:06:24.386-07:00
- 필요한 형식:
2020-07-24T20:06:24.385
- Log Analytics 형식:
이 예의 시간을 사용자의 시간으로 대체하여
$before_error_time
을 결과 값으로 설정합니다.$before_error_time ="2020-07-24T20:06:24.385"
데이터베이스 복원 및 누락 데이터 확인
이 섹션에서는 az cli db restore
를 사용하여 데이터베이스를 테이블이 삭제되기 전 시점으로 복원합니다.
이 창의 오른쪽에 있는 터미널에서 다음 스크립트를 실행합니다.
# Restore the database to a time before the database was deleted az sql db restore --dest-name "AdventureWorks-copy" --name "AdventureWorks" --time $before_error_time --verbose
복원에는 약 5~10분 정도 소요됩니다. 복원을 실행하면 Azure는 Azure SQL Database 논리 서버에 새 Azure SQL 데이터베이스를 배포합니다. 새 데이터베이스에는 원본과 동일한 구성 옵션이 있습니다. Azure SQL Database가 배포된 후 Azure는 데이터베이스를 새 Azure SQL Database로 복원합니다.
SSMS에서 데이터베이스 보기를 새로 고쳐 상태를 확인할 수 있습니다. 데이터베이스 폴더를 마우스 오른쪽 단추로 클릭하고 새로 고침을 선택합니다. 데이터베이스가 배포된 후에는 복원이 진행 중임을 확인할 수 있습니다.
복원이 진행 중인 것을 확인한 후 복원에는 2~3분 정도 더 소요됩니다. 명령이 완료되기 때문에 작업이 완료된 것을 알 수 있습니다. 또한 새로 고침을 시작할 때 복사본 데이터베이스 옆에 “(복원 중...)”이 더 이상 표시되지 않습니다.
복원에 걸리는 시간이 앞에서 설명한 것보다 길어진다면 Microsoft Learn 환경 때문일 수 있습니다. 단일 구독에 대해 한 번에 처리/제출할 수 있는 복원 요청 수는 제한됩니다. 기다리는 동안 PITR에 대한 한도 및 관련 세부 정보에 대해 자세히 알아보려면 Azure SQL Database의 백업에서 데이터베이스 복원을 참조하세요.
이제 새 데이터베이스가 (사고 발생 이전과 같은) 올바른 상태인지 확인합니다. SSMS에서 논리 서버를 마우스 오른쪽 단추로 클릭한 다음 새로 고침을 선택하여 Azure SQL Database 논리 서버 연결을 새로 고칩니다.
새 데이터베이스(예: AdventureWorks-copy)를 마우스 오른쪽 단추로 클릭한 다음 새 쿼리를 선택합니다.
다음 쿼리를 사용하여 테이블이 있는지 확인합니다.
SELECT TOP 10 * from SalesLT.SalesOrderDetail
다음 스크린샷에 나온 결과와 유사한 결과를 얻습니다. 이 결과는 원하는 위치로 데이터베이스가 복원되었음을 확인합니다.
데이터베이스 교환 및 정리
다음으로, 나중에 새 데이터베이스에 원래 데이터베이스 이름이 사용되도록 이름을 바꿀 수 있게 원래 데이터베이스 이름을 AdventureWorks-old로 바꿉니다. 애플리케이션에서 재시도 논리를 사용하면 연결 문자열을 변경할 필요가 없도록 변경됩니다.
특정 시점에 데이터베이스가 사용할 수 없는 것으로 표시되면(예: 연결을 새로 고치는 경우 SSMS의 데이터베이스에 연결할 수 없음) DNS 테이블에 업데이트가 발생했기 때문일 수 있습니다. 따라서 실제로 데이터베이스를 사용할 수 없는 동안에는 문제를 해결할 수 없습니다. 잠시 기다리면 정상 활동을 다시 시작할 수 있습니다.
다음 명령을 사용하여 데이터베이스 이름을 변경합니다.
az sql db rename --name "AdventureWorks" --new-name "AdventureWorks-old"
이제 원래 데이터베이스 이름이 더 이상 사용되지 않으므로 Azure Cloud Shell을 다시 사용하여 복사본 데이터베이스 이름을 원래 데이터베이스 이름으로 바꿀 수 있습니다.
az sql db rename --name "AdventureWorks-copy" --new-name "AdventureWorks"
이전 데이터베이스가 필요하지 않으므로
az sql db delete
를 사용하여 삭제할 수 있습니다.az sql db delete --name "AdventureWorks-old" --yes Write-Host "Database deleted"
다음 명령을 사용하면 이전 데이터베이스가 더 이상 존재하지 않는지 확인할 수 있습니다.
az sql db list -o table
이제 Azure SQL Database에서 PITR을 사용하는 방법을 살펴보았습니다. PITR은 Azure SQL Managed Instance에서도 사용할 수 있지만, 전체 인스턴스에서는 사용할 수 없습니다. az sql db
대신 az sql midb
를 사용해야 한다는 점을 제외하고 거의 동일한 명령을 사용할 수 있습니다.