2017-08-03 67 views
1

我需要以編程方式將Azure存儲中的SQL數據庫(Azure或兼容的一個本地存儲)備份/導出並將其還原到另一個SQL數據庫。我只想使用NuGet包進行代碼依賴關係,因爲我無法保證構建或生產服務器將安裝Azure SDK。我無法找到任何我認爲是常見操作的代碼示例。我發現的最接近的是:如何以編程方式將SQL數據庫直接導出到blob存儲

https://blog.hompus.nl/2013/03/13/backup-your-azure-sql-database-to-blob-storage-using-code/

但是,這個代碼出口到本地BACPAC文件(需要RoleEnvironment,獨SDK對象)。我認爲應該有辦法直接導出到Blob存儲,沒有中間文件。一個想法是創建一個Stream,然後運行:

services.ExportBacpac(stream, "dbnameToBackup") 

然後將流寫入存儲;但是一個內存流將無法工作 - 這可能是一個龐大的數據庫(100-200 GB)。

什麼是更好的方法來做到這一點?

+1

博覽會怎麼樣將其關聯到本地文件,然後通過Azure存儲數據移動庫將文件上傳到Blob存儲? https://www.nuget.org/packages/Microsoft.Azure.Storage.DataMovement –

回答

1

這裏有一個想法:

傳流的.ExportBacPac方法,但在不同的線程持有對它的引用,你經常空和重置流,這樣就沒有內存溢出。我假設在這裏,Dac沒有任何手段來訪問正在填充的流。

雖然是線程安全,但您必須自己照顧自己的事情 - 默認情況下,MemoryStreams不是線程安全的。所以你必須圍繞.Position.CopyTo編寫自己的鎖定機制。我沒有測試過,但如果你正確地處理鎖定,我會假設.ExportBacPac方法不會在其他線程訪問流時拋出任何錯誤。

這裏是一個非常簡單的例子,如僞代碼只是概述了我的想法:

ThreadSafeStream stream = new ThreadSafeStream(); 

Task task = new Task(async (exitToken) => { 
    MemoryStream partialStream = new MemoryStream(); 

    // Check if backup completed 
    if (...) 
    { 
     exitToken.Trigger(); 
    } 

    stream.CopyToThreadSafe(partialStream); 
    stream.PositionThreadSafe = 0; 

    AzureService.UploadToStorage(partialStream); 

    await Task.Delay(500); // Play around with this - it shouldn't take too long to copy the stream 
}); 

services.ExportBacpac(stream, "dbnameToBackup"); 

await TimerService.RunTaskPeriodicallyAsync(task, 500); 
+0

我不介意加入鎖定。在以前的經驗中,鎖定一直是一個很大的痛苦來源。在基礎結構代碼中創建一個新線程也是有問題的,因爲應用程序代碼可以選擇創建數百個線程來執行各種並行任務,導致上傳線程被耗盡;最終導致超時。 (再次,這是以前發生過的。) – afeygin

4

根據我的測試中,sql Microsoft Azure SQL Management Library 0.51.0-prerelease支持SQL數據庫.bacpac文件直接導出到Azure存儲。

我們可以使用sqlManagementClient.ImportExport.Export(resourceGroup, azureSqlServer, azureSqlDatabase,exportRequestParameters)來導出。 bacpac文件天藍色存儲

但是我們在最新版本的Microsoft Azure SQL Management Library SDK中找不到ImportExport。所以我們只能使用SQL Microsoft Azure SQL Management Library 0.51.0-prerelease SDK。

有關如何使用sql Microsoft Azure SQL Management Library將sql備份導出到azure blob存儲的更多詳細信息,請參閱下面的步驟和代碼。

先決條件:

註冊一個App在Azure的AD併爲它創建的服務原則。有關如何註冊表應用程序和獲取訪問令牌的更多詳細步驟請參閱document

詳細代碼:

注意:更換的clientId,tenantId,祕密密鑰,subscriptionId您註冊蔚藍AD信息。將azureSqlDatabase,resourceGroup,azureSqlServer,adminLogin,adminPassword,storageKey,storageAccount替換爲您自己的sql數據庫和存儲。

static void Main(string[] args) 
{ 

    var subscriptionId = "xxxxxxxx"; 
    var clientId = "xxxxxxxxx"; 
    var tenantId = "xxxxxxxx"; 
    var secretKey = "xxxxx"; 
    var azureSqlDatabase = "data base name"; 
    var resourceGroup = "Resource Group name"; 
    var azureSqlServer = "xxxxxxx"; //testsqlserver 
    var adminLogin = "user"; 
    var adminPassword = "password"; 
    var storageKey = "storage key"; 
    var storageAccount = "storage account"; 
    var baseStorageUri = $"https://{storageAccount}.blob.core.windows.net/brandotest/";//with container name endwith "/" 
    var backName = azureSqlDatabase + "-" + $"{DateTime.UtcNow:yyyyMMddHHmm}" + ".bacpac"; //back up sql file name 
    var backupUrl = baseStorageUri + backName; 
    ImportExportOperationStatusResponse exportStatus = new ImportExportOperationStatusResponse(); 
    try 
    { 
     ExportRequestParameters exportRequestParameters = new ExportRequestParameters 
     { 
      AdministratorLogin = adminLogin, 
      AdministratorLoginPassword = adminPassword, 
      StorageKey = storageKey, 
      StorageKeyType = "StorageAccessKey", 
      StorageUri = new Uri(backupUrl) 
     }; 

     SqlManagementClient sqlManagementClient = new SqlManagementClient(new Microsoft.Azure.TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey))); 
     var export = sqlManagementClient.ImportExport.Export(resourceGroup, azureSqlServer, azureSqlDatabase, 
         exportRequestParameters); //do export operation 

     while (exportStatus.Status != Microsoft.Azure.OperationStatus.Succeeded) // until operation successed 
     { 
      Thread.Sleep(1000 * 60); 
      exportStatus = sqlManagementClient.ImportExport.GetImportExportOperationStatus(export.OperationStatusLink); 
     } 

     Console.WriteLine($"Export DataBase {azureSqlDatabase} to Storage {storageAccount} Succesfully"); 
    } 

    catch (Exception exception) 
    { 

     //todo 

    } 

} 

private static string GetAccessToken(string tenantId, string clientId, string secretKey) 
{ 
    var authenticationContext = new AuthenticationContext($"https://login.windows.net/{tenantId}"); 
    var credential = new ClientCredential(clientId, secretKey); 
    var result = authenticationContext.AcquireTokenAsync("https://management.core.windows.net/", 
     credential); 

    if (result == null) 
    { 
     throw new InvalidOperationException("Failed to obtain the JWT token"); 
    } 

    var token = result.Result.AccessToken; 
    return token; 
} 

結果是這樣的:

1.Send要求告訴SQL服務器開始出口到蔚藍的Blob存儲

enter image description here

2.Continue發送請求到監控數據庫中導出運行狀態。

enter image description here

3.Finish導出操作。

enter image description here

+0

這看起來很有希望,但我們不能使用預發佈軟件。 – afeygin

+0

我們也可以使用sql數據庫導出[rest api](https://docs.microsoft.com/en-us/rest/api/sql/databases%20-%20import%20export#Databases_Export)來告訴sql server數據庫導出到azure blob。如果你接受這種方式,我也可以提供一些代碼示例。 –

1

這是類同的白蘭度的答案,但這個軟件需要一個穩定的包:

using Microsoft.WindowsAzure.Management.Sql; 

Nuget

使用在白蘭度的回答相同的變量,代碼會是這樣:

var azureSqlServer = "xxxxxxx"+".database.windows.net"; 
var azureSqlServerName = "xxxxxxx"; 

     SqlManagementClient managementClient = new SqlManagementClient(new TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey))); 

     var exportParams = new DacExportParameters() 
     { 
      BlobCredentials = new DacExportParameters.BlobCredentialsParameter() 
      { 
       StorageAccessKey = storageKey, 
       Uri = new Uri(baseStorageUri) 
      }, 
      ConnectionInfo = new DacExportParameters.ConnectionInfoParameter() 
      { 
       ServerName = azureSqlServer, 
       DatabaseName = azureSqlDatabase, 
       UserName = adminLogin, 
       Password = adminPassword 
      } 
     }; 
     var exportResult = managementClient.Dac.Export(azureSqlServerName, exportParams); 
相關問題