2017-08-03 45 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); 
相关问题