RDS SQL Server提供了將本地SQL Server資料庫遷移到阿里雲RDS SQL Server的資料庫上雲方案。您只需將本地SQL Server資料庫的全量備份資料上傳至阿里雲的Object Storage Service服務(OSS),然後通過RDS控制台即可將全量備份資料上雲至指定RDS SQL Server資料庫中。適用於資料備份、遷移和災備恢複等情境。
前提條件
RDS SQL Server執行個體版本為2008 R2雲端硬碟、2012及以上,且執行個體中沒有與待上雲資料庫名稱相同的資料庫。如需建立執行個體,請參見建立RDS SQL Server執行個體。
RDS SQL Server執行個體擁有足夠的儲存空間。如果空間不足,請提前升級執行個體空間。具體操作,請參見變更配置。
RDS SQL Server執行個體已建立高許可權帳號。具體操作,請參見建立資料庫和帳號。
在本機資料庫環境中執行DBCC CHECKDB
語句,以確保資料庫中沒有任何的allocation errors
和consistency errors
。正常執行結果如下:
...
CHECKDB found 0 allocation errors and 0 consistency errors in database 'xxx'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
已開通OSS服務。具體操作,請參見開通OSS服務。
如果通過RAM使用者登入,則必須滿足以下條件:
RAM帳號具備AliyunOSSFullAccess許可權和AliyunRDSFullAccess許可權。如何為RAM使用者授權,請參見通過RAM對OSS進行許可權管理和通過RAM對RDS進行許可權管理。
阿里雲帳號(主帳號)已授權RDS官方服務帳號可以訪問您OSS的許可權。
點擊展開查看授權方法
前往RDS執行個體詳情頁備份恢複頁面,單擊OSS備份資料恢複上雲按鈕。
在資料匯入嚮導頁面單擊兩次下一步,進入3. 資料匯入步驟。
若該頁面左下角顯示您已授權RDS官方服務帳號可以訪問您OSS的許可權,則表示已授權。否則表示還未授權,單擊該頁面的授權地址同意授權即可。
所在阿里雲帳號(主帳號)需手動建立權限原則,然後將許可權添加到RAM帳號中。如何建立權限原則,請參見通過指令碼編輯模式建立自訂權限原則。
點擊展開查看策略內容
{
"Version": "1",
"Statement": [
{
"Action": [
"ram:GetRole"
],
"Resource": "acs:ram:*:*:role/AliyunRDSImportRole",
"Effect": "Allow"
}
]
}
注意事項
本方案遷移的層級為資料庫,即每次只能遷移一個資料庫上雲。如果需要遷移多個或所有資料庫,建議採用執行個體級的遷移上雲方案,具體操作,請參見SQL Server執行個體層級遷移上雲。
不支援高版本的備份檔案遷移至低版本。例如從SQL Server 2016遷移到SQL Server 2012。
不支援差異備份檔案或記錄備份檔案。
全量備份檔案名不能包含特殊字元!@#$%^&*()_+-=,否則會導致上雲失敗。
授予RDS服務帳號訪問OSS的許可權以後,系統會在存取控制RAM的角色管理中建立名為AliyunRDSImportRole的角色,請勿修改或刪除這個角色,否則會導致上雲任務因無法下載備份檔案而失敗。如果修改或刪除了這個角色,您需要通過資料上雲嚮導重新授權。
本方案遷移上雲後,無法使用原有的資料庫帳號,需要在RDS控制台重新建立帳號。
在OSS備份資料恢複上雲任務沒有完成之前,請不要刪除OSS上的備份檔案,否則會導致上雲任務失敗。
備份檔案的尾碼名必須為bak、diff、trn或log,說明如下:
bak:全量備份檔案。
diff:差異備份檔案。
trn或者log:交易記錄備份檔案。
費用說明
本方案中僅會產生OSS的相關費用,詳情如下圖所示。
情境 | 費用說明 |
將本機資料備份檔案上傳至OSS | 不產生費用。 |
備份檔案儲存在OSS | 會產生OSS的儲存費用,計費詳情請參見OSS定價。 |
將備份檔案從OSS遷移至RDS | |
1. 備份本機資料庫
說明 在對本機資料庫做全量備份之前,請確保已停止寫入資料。備份過程中新寫入的資料將不會被備份。
下載備份指令碼,用SSMS(SQL Server Management Studio)開啟備份指令碼。
修改的如下參數。
配置項 | 說明 |
@backup_databases_list | 需要備份的資料庫,多個資料庫以分號(;)或者半形逗號(,)分隔。 |
@backup_type | 備份類型。參數值如下: FULL:全量備份。 DIFF:差異備份。 LOG:記錄備份。
|
@backup_folder | 備份檔案所在的本地目錄。如不存在,會自動建立。 |
@is_run | 是否執行備份。參數值如下: |
說明 修改指令碼中SELECT語句中的如上參數,位於指令碼中YOU HAVE TO INIT PUBLIC VARIABLES HERE下。
執行備份指令碼。
2. 上傳備份檔案到OSS
重要 如果OSS中已經建立了Bucket,請檢查Bucket是否滿足如下要求:
建立儲存空間Bucket。
登入OSS管理主控台。
單擊Bucket列表,然後單擊建立Bucket。
配置如下關鍵參數,其他參數可以保持預設。
參數 | 說明 | 取值樣本 |
Bucket 名稱 | 儲存空間名稱,全域唯一,設定後無法修改。 命名規則: 只能包括小寫字母、數字和短劃線(-)。 必須以小寫字母或者數字開頭和結尾。 長度必須在3~63字元之間。
| migratetest |
地區 | Bucket所屬的地區,如果您通過ECS內網上傳資料至Bucket中,且通過內網將資料恢複至RDS中,則需要三者地區保持一致。 | 華東1(杭州) |
儲存類型 | 選擇標準儲存。本文上雲操作不支援其他儲存類型的Bucket。 | 標準儲存 |
上傳備份檔案到OSS。
說明 當RDS執行個體和OSS的Bucket在同一地區時,二者可以通過內網互連,且資料上傳速度更快,並且不會產生外網流量費用。因此,在上傳備份檔案時,建議將檔案上傳至與目標RDS執行個體在同一地區的Bucket上。
本機資料庫備份完成後,需要將備份檔案上傳到您的OSS Bucket中,您可以採用如下方法之一:
使用ossbrowser工具上傳(推薦)
下載ossbrowser。
以Windows x64作業系統為例,解壓下載的oss-browser-win32-x64.zip
壓縮包,雙擊運行oss-browser.exe
應用程式。
使用AK登入方式,配置參數AccessKeyId和AccessKeySecret,其他參數保持預設,然後單擊登入。
說明 AccessKey用於身分識別驗證,確保資料安全,請妥善保管,如何建立及擷取,請參見建立AccessKey。
單擊目標Bucket,進入儲存空間。
單擊,選擇需要上傳的備份檔案,然後單擊開啟,即可將本地檔案上傳至OSS中。
使用OSS控制台上傳
說明 如果備份檔案小於5 GB,建議您直接通過OSS控制台上傳備份檔案。
登入OSS管理主控台。
單擊Bucket列表,然後單擊目標Bucket名稱。
在檔案清單中,單擊上傳檔案。
您可以將備份檔案拖拽至待上傳檔案地區,也可以單擊掃描檔案,選擇需要上傳的備份檔案。
單擊頁面下方的上傳檔案,即可將本地備份檔案上傳至OSS中。
使用OSS API分區上傳
說明 如果備份檔案大於5 GB,建議您調用OSS API採用分區上傳的方式將備份檔案上傳到OSS Bucket中。
本樣本以Java專案為例,從環境變數中擷取訪問憑證代碼。運行本程式碼範例之前,請先配置環境變數。如何配置訪問憑證,請參見配置訪問憑證。更多樣本,請參見分區上傳。
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填寫Bucket名稱,例如examplebucket。
String bucketName = "examplebucket";
// 填寫Object完整路徑,例如exampledir/exampleobject.txt。Object完整路徑中不能包含Bucket名稱。
String objectName = "exampledir/exampleobject.txt";
// 待上傳本地檔案路徑。
String filePath = "D:\\localpath\\examplefile.txt";
// 填寫Bucket所在地區。以華東1(杭州)為例,Region填寫為cn-hangzhou。
String region = "cn-hangzhou";
// 建立OSSClient執行個體。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// 建立InitiateMultipartUploadRequest對象。
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
// 如果需要在初始化分區時佈建要求頭,請參考以下範例程式碼。
ObjectMetadata metadata = new ObjectMetadata();
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// 指定該Object的網頁緩衝行為。
// metadata.setCacheControl("no-cache");
// 指定該Object被下載時的名稱。
// metadata.setContentDisposition("attachment;filename=oss_MultipartUpload.txt");
// 指定該Object的內容編碼格式。
// metadata.setContentEncoding(OSSConstants.DEFAULT_CHARSET_NAME);
// 指定初始化分區上傳時是否覆蓋同名Object。此處設定為true,表示禁止覆蓋同名Object。
// metadata.setHeader("x-oss-forbid-overwrite", "true");
// 指定上傳該Object的每個part時使用的伺服器端加密方式。
// metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
// 指定Object的密碼編譯演算法。如果未指定此選項,表明Object使用AES256密碼編譯演算法。
// metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_DATA_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
// 指定KMS託管的使用者主要金鑰。
// metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, "9468da86-3509-4f8d-a61e-6eab1eac****");
// 指定Object的儲存類型。
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard);
// 指定Object的對象標籤,可同時設定多個標籤。
// metadata.setHeader(OSSHeaders.OSS_TAGGING, "a:1");
// request.setObjectMetadata(metadata);
// 根據檔案自動化佈建ContentType。如果不設定,ContentType預設值為application/oct-srream。
if (metadata.getContentType() == null) {
metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
}
// 初始化分區。
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
// 返回uploadId。
String uploadId = upresult.getUploadId();
// 根據uploadId執行取消分區上傳事件或者列舉已上傳分區的操作。
// 如果您需要根據uploadId執行取消分區上傳事件的操作,您需要在調用InitiateMultipartUpload完成初始化分區之後擷取uploadId。
// 如果您需要根據uploadId執行列舉已上傳分區的操作,您需要在調用InitiateMultipartUpload完成初始化分區之後,且在調用CompleteMultipartUpload完成分區上傳之前擷取uploadId。
// System.out.println(uploadId);
// partETags是PartETag的集合。PartETag由分區的ETag和分區號組成。
List<PartETag> partETags = new ArrayList<PartETag>();
// 每個分區的大小,用於計算檔案有多少個分區。單位為位元組。
final long partSize = 1 * 1024 * 1024L; //1 MB。
// 根據上傳的資料大小計算分區數。以本地檔案為例,說明如何通過File.length()擷取上傳資料的大小。
final File sampleFile = new File(filePath);
long fileLength = sampleFile.length();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
// 遍曆分區上傳。
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(objectName);
uploadPartRequest.setUploadId(uploadId);
// 設定上傳的分區流。
// 以本地檔案為例說明如何建立FIleInputstream,並通過InputStream.skip()方法跳過指定資料。
InputStream instream = new FileInputStream(sampleFile);
instream.skip(startPos);
uploadPartRequest.setInputStream(instream);
// 設定分區大小。除了最後一個分區沒有大小限制,其他的分區最小為100 KB。
uploadPartRequest.setPartSize(curPartSize);
// 設定分區號。每一個上傳的分區都有一個分區號,取值範圍是1~10000,如果超出此範圍,OSS將返回InvalidArgument錯誤碼。
uploadPartRequest.setPartNumber( i + 1);
// 每個分區不需要按順序上傳,甚至可以在不同用戶端上傳,OSS會按照分區號排序組成完整的檔案。
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
// 每次上傳分區之後,OSS的返回結果包含PartETag。PartETag將被儲存在partETags中。
partETags.add(uploadPartResult.getPartETag());
}
// 建立CompleteMultipartUploadRequest對象。
// 在執行完成分區上傳操作時,需要提供所有有效partETags。OSS收到提交的partETags後,會逐一驗證每個分區的有效性。當所有的資料分區驗證通過後,OSS將把這些分區組合成一個完整的檔案。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// 如果需要在完成分區上傳的同時設定檔案存取權限,請參考以下範例程式碼。
// completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.Private);
// 指定是否列舉當前UploadId已上傳的所有Part。僅在Java SDK為3.14.0及以上版本時,支援通過服務端List分區資料來合并完整檔案時,將CompleteMultipartUploadRequest中的partETags設定為null。
// Map<String, String> headers = new HashMap<String, String>();
// 如果指定了x-oss-complete-all:yes,則OSS會列舉當前UploadId已上傳的所有Part,然後按照PartNumber的序號排序並執行CompleteMultipartUpload操作。
// 如果指定了x-oss-complete-all:yes,則不允許繼續指定body,否則報錯。
// headers.put("x-oss-complete-all","yes");
// completeMultipartUploadRequest.setHeaders(headers);
// 完成分區上傳。
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
System.out.println(completeMultipartUploadResult.getETag());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
3. 建立資料上雲任務
訪問RDS執行個體列表,在上方選擇地區,然後單擊目標執行個體ID。
在左側功能表列中選擇備份恢複。
單擊頁面上方的OSS備份資料恢複上雲。
在資料匯入嚮導頁面,單擊兩次下一步,進入資料匯入步驟。
說明 如果您是第一次使用OSS備份資料恢複上雲功能,需要給RDS官方服務帳號授予訪問OSS的許可權,請單擊授權地址並同意授權,否則會因許可權問題導致OSS Bucket下拉式清單為空白。
設定如下參數。
配置項 | 說明 |
資料庫名 | 備份資料匯入目標RDS執行個體上的資料庫名,名稱需要符合SQL Server官方限制。 |
OSS Bucket | 選擇備份檔案所在的OSS Bucket。 |
OSS子檔案夾名 | 備份檔案所在的子檔案夾名。 |
OSS檔案清單 | 單擊右側按鈕,可以按照備份檔案名首碼模糊尋找,會展示檔案名稱、檔案大小和更新時間。請選擇需要上雲的備份檔案。 |
上雲方案 | 開啟資料庫(只有一個全量備份檔案):全量上雲,適合僅有一個完全備份檔案上雲的情境。本操作選擇開啟資料庫,此時CreateMigrateTask中的BackupMode = FULL 並且IsOnlineDB = True 。 不開啟資料庫(還有差異備份或記錄檔):增量上雲,適合有完全備份檔案加上記錄備份(或者差異備份檔案)上雲的情境,此時CreateMigrateTask中的BackupMode = UPDF 並且IsOnlineDB = False 。
|
一致性檢查方式 | 非同步執行DBCC:在開啟資料庫的時候系統不做DBCC CheckDB,會在開啟資料庫任務結束以後,非同步執行DBCC CheckDB操作,以此來節約開啟資料庫操作的時間開銷(資料庫比較大,DBCC CheckDB非常耗時),減少您的業務停機時間。如果您對業務停機時間要求非常敏感,且不關心DBCC CheckDB結果,建議使用非同步執行DBCC。此時CreateMigrateTask 中的CheckDBMode = AsyncExecuteDBCheck 。 同步執行DBCC:相對於非同步執行DBCC,有的使用者非常關心DBCC CheckDB的結果,以此來找出使用者線下資料庫資料一致性錯誤。此時,建議您選擇同步執行DBCC,影響是會拉長開啟資料庫的時間。此時CreateMigrateTask 中的CheckDBMode = SyncExecuteDBCheck 。
|
單擊確定。
請耐心等待上雲任務完成,您可以單擊重新整理查看資料上雲任務最新狀態。如果上雲失敗,請根據任務描述提示排查錯誤,具體可參見本文的常見錯誤。
4. 查看備份上雲記錄
您可以在備份恢複頁面備份資料上雲記錄頁簽內查看備份上雲記錄,預設會展示最近一周的記錄。
常見錯誤
每條備份上雲恢複記錄中都會有任務描述資訊,您可以通過這些描述資訊發現任務失敗或報錯的原因。常見的錯誤資訊如下:
同名資料庫已經存在
錯誤資訊:The database (xxx) is already exist on RDS, please backup and drop it, then try again.
錯誤原因:為了保證RDS SQL Server上資料的安全性,RDS SQL Server不支援同名資料庫的上雲操作。
解決方案:如果您確實需要對現有資料庫的資料進行覆蓋,請自行先備份已經存在的資料,然後刪除資料庫,最後再重新執行資料上雲任務。
使用差異備份檔案
錯誤資訊:Backup set (xxx.bak) is a Database Differential backup, we only accept a FULL Backup.
錯誤原因:您提供的備份檔案是差異備份,不是全量備份檔案,一次性全量遷入上雲僅支援全量備份檔案,不支援差異備份。
使用記錄備份檔案
錯誤資訊:Backup set (xxx.trn) is a Transaction Log backup, we only accept a FULL Backup.
錯誤原因:您提供的備份檔案是記錄備份,不是全量備份檔案,一次性全量遷入上雲僅支援全量備份檔案,不支援記錄備份。
備份檔案校正失敗
錯誤資訊:Failed to verify xxx.bak, backup file was corrupted or newer edition than RDS.
錯誤原因:備份檔案損壞或者備份檔案所在的本地環境SQL Server執行個體版本比RDS SQL Server版本高,導致校正失敗。例如將一個SQL Server 2016的備份還原到RDS SQL Server 2012版本,就會報告這個錯誤。
解決方案:如果是備份檔案損壞,請在本地環境重新做一個全量備份,重建遷移上雲任務;如果是版本過高,請使用與本地環境版本一致或者更高的RDS SQL Server。
說明 如需將已有RDS SQL Server執行個體升級到更高版本,請參見升級資料庫版本。
DBCC CHECKDB失敗
錯誤資訊:DBCC checkdb failed.
錯誤原因:DBCC CheckDB檢查操作報錯,說明資料庫在本地環境中已經有錯誤發生。
解決方案:使用如下命令修複本地環境資料庫錯誤後重新上雲。
重要 使用該命令修複錯誤的過程,可能會導致資料丟失。
DBCC CHECKDB (DBName, REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS, ALL_ERRORMSGS
空間不足1
錯誤資訊:Not Enough Disk Space for restoring, space left (xxx MB) < needed (xxx MB).
錯誤原因:RDS執行個體剩餘空間不滿足備份檔案上雲所需要的最小空間要求。
解決方案:升級執行個體儲存空間。具體操作,請參見變更配置。
空間不足2
錯誤資訊:Not Enough Disk Space, space left xxx MB < bak file xxx MB.
錯誤原因:RDS執行個體剩餘空間比備份檔案本身小,不滿足最小空間要求。
解決方案:升級執行個體儲存空間。具體操作,請參見變更配置。
沒有高許可權帳號
錯誤資訊:Your RDS doesn’t have any init account yet, please create one and grant permissions on RDS console to this migrated database (XXX).
錯誤原因:RDS執行個體不存在高許可權帳號,OSS備份資料上雲任務不知道需要為哪個使用者授權,但是備份檔案已經成功還原到目標執行個體上,所以任務狀態是成功的。
解決方案:建立高許可權帳號。具體操作,請參見建立高許可權帳號。
RAM子帳號操作許可權不足
Q1:執行建立資料上雲任務步驟5時,各配置項參數均已填寫完整,但確定按鈕為灰色無法單擊?
A1:無法單擊的原因可能是您為RAM使用者,您的帳號許可權不足。請參見本文前提條件,確保相應許可權已授予。
Q2:使用RAM子帳號進行AliyunRDSImportRole
授權時提示沒有許可權
如何解決?
A2:使用阿里雲主帳號為RAM子帳號臨時增加AliyunRAMFullAccess
許可權解決。如何為RAM使用者授權,請參見通過RAM對RDS進行許可權管理。
常見返回資訊
任務類型 | 任務狀態 | 任務描述 | 說明 |
全量備份檔案一次性遷入 | 成功 | success
| 上雲成功。 |
失敗 | Failed to download backup file since OSS URL was expired.
| OSS下載URL有效期間到期,導致上雲失敗。 |
Your backup is corrupted or newer than RDS, failed to verify.
| 備份檔案損壞或者比RDS的版本更高,導致上雲失敗。 |
DBCC checkdb failed
| DBCC checkdb失敗,導致上雲失敗。 |
autotest_2008r2_std_testmigrate_log.trn is a Transaction Log backup, we only accept a FULL Backup.
| 記錄備份,導致上雲失敗。 |
autotest_2008r2_std_testmigrate_diff.bak is a Database Differential backup, we only accept a FULL Backup.
| 差異備份,導致上雲失敗。 |