Transazioni distribuite in database cloud

Si applica a: Database SQL di Azure Istanza gestita di SQL di Azure

Le transazioni di database elastico per Azure SQL Database e Istanza gestita di SQL di Azure consentono di eseguire transazioni che si estendono su più database. Le transazioni di database elastico sono disponibili per le applicazioni .NET che usano ADO.NET e si integrano con l'esperienza di programmazione familiare usando le classi System.Transaction . Per ottenere la libreria, vedere Microsoft .NET Framework 4.6.1 (programma di installazione Web). Inoltre, per le transazioni distribuite dell'istanza gestita sono disponibili in Transact-SQL.

In locale, questo scenario richiede in genere l'esecuzione di Microsoft Distributed Transaction Coordinator (MSDTC). Poiché MSDTC non è disponibile per l'applicazione Platform-as-a-Service in Azure, la possibilità di coordinare le transazioni distribuite è stata ora integrata direttamente in database SQL o Istanza gestita di SQL. Le applicazioni possono connettersi a qualsiasi database per avviare transazioni distribuite e uno dei database o server coordina in modo trasparente la transazione distribuita, come illustrato nella figura seguente.

In questo documento i termini "transazioni distribuite" e "transazioni di database elastici" sono considerati sinonimi e verranno usati in modo intercambiabile.

Transazioni distribuite con database Azure SQL tramite transazioni di database elastici

Scenari comuni

Le transazioni di database elastici consentono alle applicazioni di apportare modifiche atomiche ai dati archiviati in diversi database. Sia database SQL che Istanza gestita di SQL supportano esperienze di sviluppo lato client in C# e .NET. Un'esperienza lato server (codice scritto in stored procedure o script lato server) con Transact-SQL è disponibile solo per Istanza gestita di SQL.

Importante

L'esecuzione di transazioni di database elastici tra Azure SQL Database e Istanza gestita di SQL di Azure non è supportata. La transazione di database elastici può estendersi solo su un set di database in database SQL o su un set di database tra istanze gestite.

Le transazioni di database elastici sono destinate agli scenari seguenti:

  • Applicazioni multi-database in Azure: con questo scenario, i dati vengono partizionati verticalmente in diversi database in database SQL o Istanza gestita di SQL in modo che diversi tipi di dati si trovino in database diversi. Alcune operazioni richiedono modifiche ai dati, che vengono mantenute in due o più database. L'applicazione usa le transazioni di database elastico per coordinare le modifiche tra i database e garantire l'atomicità.
  • Applicazioni di database partizionate in Azure: con questo scenario, il livello dati usa la libreria client del database elastico o il partizionamento automatico per partizionare orizzontalmente i dati in molti database in database SQL o Istanza gestita di SQL. Un caso d'uso significativo è la necessità di eseguire modifiche atomiche per un'applicazione multi-tenant partizionata, quando le modifiche si estendono a più tenant. Si pensi ad esempio a un trasferimento da un tenant all'altro, entrambi residenti in database diversi. Un secondo caso è il partizionamento orizzontale con granularità fine per soddisfare le esigenze di capacità per un tenant di grandi dimensioni, che a sua volta implica che alcune operazioni atomica devono estendersi tra più database usati per lo stesso tenant. Un terzo caso sono gli aggiornamenti atomici per fare riferimento ai dati replicati tra i database. Le operazioni atomiche, transazionate, lungo queste righe possono ora essere coordinate tra diversi database. Le transazioni di database elastici usano il commit in due fasi per garantire l'atomicità delle transazioni tra i database. È una scelta ottimale per le transazioni che coinvolgono meno di 100 database alla volta all'interno di una singola transazione. Questi limiti non vengono applicati, ma è consigliabile prevedere prestazioni e percentuali di successo per le transazioni di database elastici in caso di superamento di questi limiti.

Installazione e migrazione

Le funzionalità per le transazioni di database elastico vengono fornite tramite aggiornamenti alle librerie .NET System.Data.dll e System.Transactions.dll. Le DLL assicurano che il protocollo 2PC venga usato dove necessario per garantire l'atomicità. Per iniziare a sviluppare applicazioni che usano transazioni di database elastico, installare .NET Framework 4.6.1 o una versione successiva. Quando si esegue una versione precedente di .NET Framework, le transazioni non verranno alzate di livello a una transazione distribuita e verrà generata un'eccezione.

Dopo l'installazione, è possibile usare le API delle transazioni distribuite in System.Transactions con connessioni a database SQL e Istanza gestita di SQL. Se sono presenti applicazioni MSDTC che usano queste API, ricompilare le applicazioni esistenti per .NET 4.6 dopo aver installato il framework 4.6.1. Se i progetti sono destinati a .NET 4.6, useranno automaticamente le DLL aggiornate dalla nuova versione di Framework e le chiamate API di transazione distribuite in combinazione con le connessioni a database SQL o Istanza gestita di SQL avranno esito positivo.

Tenere presente che le transazioni di database elastico non richiedono l'installazione di MSDTC. Al contrario, le transazioni di database elastico vengono gestite direttamente da e all'interno del servizio. Questo semplifica in modo significativo gli scenari cloud perché una distribuzione di MSDTC non è necessaria per usare le transazioni distribuite con database SQL o Istanza gestita di SQL. La sezione 4 illustra in dettaglio come distribuire le transazioni di database elastico e la versione di .NET Framework necessaria insieme alle proprie applicazioni cloud in Azure.

Installazione di .NET per i servizi cloud di Azure

Azure offre diverse soluzioni per l'hosting di applicazioni .NET. Per un confronto delle diverse soluzioni, vedere Confronto tra Azure App Service, Servizi cloud e Macchine virtuali di Azure. Se il sistema operativo guest della soluzione è precedente alla versione 4.6.1 di .NET richiesta per le transazioni elastiche, è necessario aggiornare il sistema operativo guest alla versione 4.6.1.

Per Servizio app di Azure, gli aggiornamenti al sistema operativo guest non sono attualmente supportati. Per le macchine virtuali di Azure, è sufficiente accedere alla macchina virtuale ed eseguire il programma di installazione del framework .NET più recente. Per i servizi cloud di Azure, è necessario includere l'installazione di una versione più recente di .NET nelle attività di avvio della distribuzione. I concetti e i passaggi sono documentati in Installare .NET in un ruolo del servizio cloud.

Si noti che il programma di installazione per .NET 4.6.1 può richiedere più spazio di archiviazione temporaneo durante il processo di bootstrap nei servizi cloud di Azure rispetto al programma di installazione per .NET 4.6. Per garantire una corretta installazione, è necessario aumentare l'archiviazione temporanea per il servizio cloud di Azure nel file ServiceDefinition.csdef nella sezione LocalResources e le impostazioni di ambiente dell'attività di avvio, come illustrato nell'esempio seguente:

<LocalResources>
...
    <LocalStorage name="TEMP" sizeInMB="5000" cleanOnRoleRecycle="false" />
    <LocalStorage name="TMP" sizeInMB="5000" cleanOnRoleRecycle="false" />
</LocalResources>
<Startup>
    <Task commandLine="install.cmd" executionContext="elevated" taskType="simple">
        <Environment>
    ...
            <Variable name="TEMP">
                <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='TEMP']/@path" />
            </Variable>
            <Variable name="TMP">
                <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='TMP']/@path" />
            </Variable>
        </Environment>
    </Task>
</Startup>

Esperienza di sviluppo .NET

Applicazioni con più database

L'esempio di codice seguente usa l'esperienza di programmazione familiare con System.Transactions per .NET. La classe TransactionScope definisce una transazione di ambiente in .NET. Una "transazione di ambiente" è una che risiede nel thread corrente. Tutte le connessioni aperte all'interno di TransactionScope partecipano alla transazione. Se partecipano diversi database, la transazione viene automaticamente elevata a transazione distribuita. Il risultato della transazione viene controllato impostando l'ambito da completare per indicare un commit.

using (var scope = new TransactionScope())
{
    using (var conn1 = new SqlConnection(connStrDb1))
    {
        conn1.Open();
        SqlCommand cmd1 = conn1.CreateCommand();
        cmd1.CommandText = string.Format("insert into T1 values(1)");
        cmd1.ExecuteNonQuery();
    }
    using (var conn2 = new SqlConnection(connStrDb2))
    {
        conn2.Open();
        var cmd2 = conn2.CreateCommand();
        cmd2.CommandText = string.Format("insert into T2 values(2)");
        cmd2.ExecuteNonQuery();
    }
    scope.Complete();
}

Applicazioni di database partizionato

Le transazioni di database elastico per database SQL e Istanza gestita di SQL supportano anche il coordinamento delle transazioni distribuite in cui si usa il metodo OpenConnectionForKey della libreria client del database elastico per aprire le connessioni per un livello dati con scalabilità orizzontale. Considerare i casi in cui è necessario garantire la coerenza delle transazioni per le modifiche dei diversi valori delle chiavi di partizionamento orizzontale. Le connessioni alle partizioni che ospitano i diversi valori delle chiavi di partizionamento orizzontale sono negoziate tramite OpenConnectionForKey. In generale, le connessioni possono essere stabilite a partizioni diverse, in modo tale che per assicurare garanzie transazionali sia richiesta una transazione distribuita. Il seguente esempio di codice illustra questo approccio. Si presuppone che venga usata una variabile denominata shardmap per rappresentare un mappa partizioni dalla libreria client dei database elastici:

using (var scope = new TransactionScope())
{
    using (var conn1 = shardmap.OpenConnectionForKey(tenantId1, credentialsStr))
    {
        SqlCommand cmd1 = conn1.CreateCommand();
        cmd1.CommandText = string.Format("insert into T1 values(1)");
        cmd1.ExecuteNonQuery();
    }
    using (var conn2 = shardmap.OpenConnectionForKey(tenantId2, credentialsStr))
    {
        var cmd2 = conn2.CreateCommand();
        cmd2.CommandText = string.Format("insert into T1 values(2)");
        cmd2.ExecuteNonQuery();
    }
    scope.Complete();
}

Esperienza di sviluppo Transact-SQL

Le transazioni distribuite sul lato server che usano Transact-SQL sono disponibili solo per Istanza gestita di SQL di Azure. La transazione distribuita può essere eseguita solo tra istanze gestite che appartengono allo stesso gruppo di attendibilità del server. In questo scenario, le istanze gestite devono usare il server collegato per farvi riferimento.

Il codice Transact-SQL di esempio seguente usa BEGIN DISTRIBUTED TRANSACTION per avviare la transazione distribuita.

    -- Configure the Linked Server
    -- Add one Azure SQL Managed Instance as Linked Server
    EXEC sp_addlinkedserver
        @server='RemoteServer', -- Linked server name
        @srvproduct='',
        @provider='sqlncli', -- SQL Server Native Client
        @datasrc='managed-instance-server.46e7afd5bc81.database.windows.net' -- SQL Managed Instance endpoint

    -- Add credentials and options to this Linked Server
    EXEC sp_addlinkedsrvlogin
        @rmtsrvname = 'RemoteServer', -- Linked server name
        @useself = 'false',
        @rmtuser = '<login_name>',         -- login
        @rmtpassword = '<secure_password>' -- password

    USE AdventureWorks2012;
    GO
    SET XACT_ABORT ON;
    GO
    BEGIN DISTRIBUTED TRANSACTION;
    -- Delete candidate from local instance.
    DELETE AdventureWorks2012.HumanResources.JobCandidate
        WHERE JobCandidateID = 13;
    -- Delete candidate from remote instance.
    DELETE RemoteServer.AdventureWorks2012.HumanResources.JobCandidate
        WHERE JobCandidateID = 13;
    COMMIT TRANSACTION;
    GO

Combinazione di esperienza di sviluppo .NET e Transact-SQL

Le applicazioni .NET che usano classi System.Transaction possono combinare la classe TransactionScope con l'istruzione Transact-SQL BEGIN DISTRIBUTED TRANSACTION. All'interno di TransactionScope, la transazione interna che esegue BEGIN DISTRIBUTED TRANSACTION verrà promossa in modo esplicito alla transazione distribuita. Inoltre, quando il secondo oggetto SqlConnecton viene aperto all'interno di TransactionScope, verrà promosso in modo implicito alla transazione distribuita. Dopo l'avvio della transazione distribuita, tutte le richieste di transazioni successive, che provenano da .NET o Transact-SQL, verranno unite alla transazione distribuita padre. Di conseguenza, tutti gli ambiti di transazione annidati avviati dall'istruzione BEGIN finiranno nella stessa transazione e le istruzioni COMMIT/ROLLBACK avranno effetto sul risultato complessivo:

  • L'istruzione COMMIT non avrà alcun effetto sull'ambito della transazione avviata dall'istruzione BEGIN, ovvero non verrà eseguito il commit di alcun risultato prima che venga richiamato il metodo Complete() sull'oggetto TransactionScope. Se l'oggetto TransactionScope viene eliminato prima del completamento, viene eseguito il rollback di tutte le modifiche apportate all'interno dell'ambito.
  • L'istruzione ROLLBACK causerà il rollback dell'intero oggetto TransactionScope. Eventuali tentativi di integrazione di nuove transazioni all'interno di TransactionScope avranno esito negativo in seguito, oltre a tentare di richiamare Complete() nell'oggetto TransactionScope.

Di seguito è riportato un esempio in cui la transazione viene promossa in modo esplicito alla transazione distribuita con Transact-SQL.

using (TransactionScope s = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(DB0_ConnectionString)
    {
        conn.Open();
    
        // Transaction is here promoted to distributed by BEGIN statement
        //
        Helper.ExecuteNonQueryOnOpenConnection(conn, "BEGIN DISTRIBUTED TRAN");
        // ...
    }
 
    using (SqlConnection conn2 = new SqlConnection(DB1_ConnectionString)
    {
        conn2.Open();
        // ...
    }
    
    s.Complete();
}

Nell'esempio seguente viene illustrata una transazione promossa in modo implicito alla transazione distribuita dopo l'avvio del secondo oggetto SqlConnecton all'interno di TransactionScope.

using (TransactionScope s = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(DB0_ConnectionString)
    {
        conn.Open();
        // ...
    }
    
    using (SqlConnection conn = new SqlConnection(DB1_ConnectionString)
    {
        // Because this is second SqlConnection within TransactionScope transaction is here implicitly promoted distributed.
        //
        conn.Open(); 
        Helper.ExecuteNonQueryOnOpenConnection(conn, "BEGIN DISTRIBUTED TRAN");
        Helper.ExecuteNonQueryOnOpenConnection(conn, lsQuery);
        // ...
    }
    
    s.Complete();
}

Transazioni per database SQL

Le transazioni di database elastico sono supportate in server diversi in Azure SQL Database. Quando le transazioni superano i limiti del server, i server partecipanti devono prima essere immessi in una relazione di comunicazione reciproca. Dopo aver stabilito la relazione di comunicazione, qualsiasi database in uno dei due server può partecipare alle transazioni elastiche con i database dell'altro server. Con le transazioni che si estendono su più di due server, è necessario che sia presente una relazione di comunicazione per qualsiasi coppia di server.

Usare i seguenti cmdlet di PowerShell per la gestione delle relazioni di comunicazione tra server per le transazioni di database elastici:

  • New-AzSqlServerCommunicationLink: usare questo cmdlet per creare una nuova relazione di comunicazione tra due server in Azure SQL Database. La relazione è simmetrica, il che significa che entrambi i server possono avviare transazioni con l'altro server.
  • Get-AzSqlServerCommunicationLink: usare questo cmdlet per recuperare le relazioni di comunicazione esistenti e le relative proprietà.
  • Remove-AzSqlServerCommunicationLink: usare questo cmdlet per rimuovere una relazione di comunicazione esistente.

Transazioni per Istanza gestita di SQL

Le transazioni distribuite sono supportate tra database all'interno di più istanze. Quando le transazioni superano i limiti dell'istanza gestita, le istanze partecipanti devono trovarsi in una relazione di sicurezza e comunicazione reciproca. A tale scopo, creare un gruppo di attendibilità del server, che può essere eseguito usando il portale di Azure o Azure PowerShell o l'interfaccia della riga di comando di Azure. Se le istanze non si trovano nella stessa rete virtuale, è necessario configurare il peering di rete virtuale e le regole di sicurezza di rete in ingresso e in uscita devono consentire porte 5024 e 11000-12000 in tutte le reti virtuali partecipanti.

Gruppi di attendibilità server nel portale di Azure

Il diagramma seguente mostra un gruppo di attendibilità server con istanze gestite che possono eseguire transazioni distribuite con .NET o Transact-SQL:

Transazioni distribuite con Istanza gestita di SQL di Azure tramite transazioni elastiche

Monitoraggio dello stato delle transazioni

Usare viste di gestione dinamica (DMV) per monitorare lo stato e lo stato delle transazioni di database elastici in corso. Tutte le DMV correlate alle transazioni sono rilevanti per le transazioni distribuite in database SQL e Istanza gestita di SQL. È possibile trovare l'elenco corrispondente di DMV di seguito: Funzioni e viste a gestione dinamica relative alle transazioni (Transact-SQL).

Queste viste a gestione dinamica sono particolarmente utili:

  • sys.dm_tran_active_transactions: elenca attualmente transazioni attive e il relativo stato. La colonna UOW (unità di lavoro) può identificare le diverse transazioni figlio che appartengono alla stessa transazione distribuita. Tutte le transazioni all'interno della stessa transazione distribuita hanno lo stesso valore di unità di lavoro. Per altre informazioni, vedere la documentazione del DMV.
  • sys.dm_tran_database_transactions: fornisce informazioni aggiuntive sulle transazioni, ad esempio il posizionamento della transazione nel log. Per altre informazioni, vedere la documentazione del DMV.
  • sys.dm_tran_locks: fornisce informazioni sui blocchi attualmente mantenuti dalle transazioni in corso. Per altre informazioni, vedere la documentazione del DMV.

Limitazioni

Le limitazioni seguenti si applicano attualmente alle transazioni di database elastiche in database SQL:

  • Sono supportate solo le transazioni tra database in database SQL. Altri provider di risorse X/Open XA e database esterni a database SQL non possono partecipare alle transazioni di database elastici. Ciò significa che le transazioni di database elastiche non possono estendersi tra SQL Server locali e database Azure SQL. Per le transazioni distribuite in locale, continuare a usare MSDTC.
  • Sono supportate solo le transazioni coordinate tramite client da un'applicazione .NET. Il supporto sul lato server per T-SQL, ad esempio BEGIN DISTRIBUTED TRANSACTION, è pianificato, ma non ancora disponibile.
  • Le transazioni tra i servizi WCF non sono supportate. Ad esempio, si dispone di un metodo del servizio WCF che esegue una transazione. Se si racchiude la chiamata all'interno di un ambito della transazione, essa avrà esito negativo come eccezione System.ServiceModel.ProtocolException.

Le limitazioni seguenti si applicano attualmente alle transazioni distribuite in Istanza gestita di SQL:

  • Sono supportate solo le transazioni tra database nelle istanze gestite. Altri provider di risorse X/Open XA e database esterni a Istanza gestita di SQL di Azure non possono partecipare alle transazioni distribuite. Ciò significa che le transazioni distribuite non possono estendersi tra SQL Server locali e Istanza gestita di SQL di Azure. Per le transazioni distribuite in locale, continuare a usare MSDTC.
  • Le transazioni tra i servizi WCF non sono supportate. Ad esempio, si dispone di un metodo del servizio WCF che esegue una transazione. Se si racchiude la chiamata all'interno di un ambito della transazione, essa avrà esito negativo come eccezione System.ServiceModel.ProtocolException.
  • Istanza gestita di SQL di Azure deve essere parte di un gruppo di attendibilità server per partecipare alla transazione distribuita.
  • Le limitazioni dei gruppi di attendibilità server influiscono sulle transazioni distribuite.
  • Le istanze gestite che partecipano alle transazioni distribuite devono avere connettività su endpoint privati (usando l'indirizzo IP privato dalla rete virtuale in cui vengono distribuite) e devono essere a cui si fa riferimento reciprocamente usando FQDN privati. Le applicazioni client possono usare transazioni distribuite in endpoint privati. Inoltre, nei casi in cui Transact-SQL sfrutta i server collegati che fanno riferimento agli endpoint privati, le applicazioni client possono anche usare transazioni distribuite negli endpoint pubblici. Questa limitazione è illustrata nel diagramma seguente.

Limitazione della connettività dell'endpoint privato

Passaggi successivi