Transazioni distribuite in database cloud

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

Questo articolo descrive l'uso di transazioni di database elastico che consentono di eseguire transazioni distribuite tra database cloud per il database SQL di Azure e l’Istanza gestita di SQL di Azure. In questo articolo, i termini "transazioni distribuite" e "transazioni di database elastico" sono considerati sinonimi e vengono usati in modo intercambiabile.

Nota

È anche possibile usare Distributed Transaction Coordinator per l’Istanza gestita di SQL di Azure per eseguire transazioni distribuite in ambienti misti.

Panoramica

Le transazioni di database elastico per il database SQL di Azure e Istanza gestita di SQL di Azure consentono di eseguire transazioni estese su più database. Le transazioni di database elastici sono disponibili per le applicazioni .NET tramite ADO.NET e si integrano con i tipi di programmazione più diffusi grazie alle classi System.Transaction. Per ottenere la libreria, vedere Microsoft .NET Framework 4.6.1 (programma di installazione Web). Inoltre, le transazioni distribuite dell'istanza gestita sono disponibili in Transact-SQL.

In locale, uno scenario del genere richiede solitamente l'esecuzione di Microsoft Distributed Transaction Coordinator (MSDTC). Poiché MSDTC non è disponibile per il database SQL di Azure, la possibilità di coordinare le transazioni distribuite è stata integrata direttamente nel database SQL e nell’Istanza gestita di SQL. Tuttavia, per l’Istanza gestita di SQL, è anche possibile usare il Distributed Transaction Coordinator per eseguire transazioni distribuite tra diversi ambienti misti, come ad esempio istanze gestite, SQL Server, altri sistemi di gestione di database relazionali (RDBMS), applicazioni personalizzate e altri partecipanti alle transazioni ospitati in qualsiasi ambiente in grado di stabilire la connettività di rete ad Azure.

Le applicazioni possono connettersi a qualsiasi database per avviare transazioni distribuite e uno dei database o dei server coordina in modo trasparente la transazione distribuita, come illustrato nella figura seguente.

Distributed transactions with Azure SQL Database using elastic database transactions

Scenari comuni

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

Importante

Non è supportata l'esecuzione di transazioni di database elastico tra il database SQL di Azure e l’Istanza gestita di SQL di Azure. La transazione di database elastico può estendersi solo in un set di database nel database SQL o in un set di database tra istanze gestite.

Le transazioni di database elastico sono destinate ai seguenti scenari:

  • Applicazioni con più database in Azure: con questo scenario i dati sono partizionati verticalmente in più database nel database SQL o nell’Istanza gestita di SQL, in modo che diversi tipi di dati risiedano in database diversi. Alcune operazioni richiedono modifiche ai dati mantenuti 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 partizionati in Azure: con questo scenario il livello dati usa la libreria client dei database elastico o il partizionamento automatico per eseguire il partizionamento orizzontale dei dati in molti database nel database SQL o nell’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 solitamente la necessità che alcune operazioni atomiche siano estese a diversi 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 e transazionali che seguono questo schema ora possono essere coordinate in diversi database. Le transazioni di database elastico usano il protocollo 2PC per garantire l'atomicità delle transazioni nei database. È una scelta ideale per le transazioni che coinvolgono meno di 100 database alla volta in una singola transazione. Questi limiti non vengono applicati, ma, quando vengono superati, potrebbero implicare una riduzione delle prestazioni e delle percentuali di riuscita delle transazioni di database elastico.

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 l'API di transazione distribuita in System.Transactions con connessioni al database SQL e all’Istanza gestita di SQL. Se sono disponibili applicazioni di MSDTC che usano queste API, basta ricompilare le applicazioni esistenti per .NET 4.6 dopo l’installazione della versione 4.6.1 di Framework. Se i progetti sono destinati a .NET 4.6, verranno usate automaticamente le DLL aggiornate della nuova versione di Framework e così le chiamate API di transazione distribuita in combinazione con le connessioni al database SQL e all’Istanza gestita di SQL avranno successo.

Si ricorda che le transazioni di database elastico non richiedono l'installazione di MSDTC. Al contrario, le transazioni di database elastico sono gestite direttamente e internamente dal servizio. In questo modo, gli scenari basati sul cloud sono notevolmente più semplici, perché non è necessaria una distribuzione di MSDTC per usare transazioni distribuite con il database SQL o l’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 il servizio app di Azure, gli aggiornamenti del 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 nella conversazione 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 il database SQL e l’Istanza gestita di SQL supportano anche il coordinamento delle transazioni distribuite in cui si usa il metodo OpenConnectionForKey della libreria client dei database elastici 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 lato server usando Transact-SQL sono disponibili solo per l’Istanza gestita di SQL di Azure. La transazione distribuita può essere eseguita solo tra istanze appartenenti allo stesso gruppo di attendibilità del server. In questo scenario, le istanze gestite devono usare il server collegato per farvi riferimento.

Il seguente esempio di codice Transact-SQL 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='MSOLEDBSQL', -- Microsoft OLE DB Driver for SQL Server
        @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 AdventureWorks2022;
    GO
    SET XACT_ABORT ON;
    GO
    BEGIN DISTRIBUTED TRANSACTION;
    -- Delete candidate from local instance.
    DELETE AdventureWorks2022.HumanResources.JobCandidate
        WHERE JobCandidateID = 13;
    -- Delete candidate from remote instance.
    DELETE RemoteServer.AdventureWorks2022.HumanResources.JobCandidate
        WHERE JobCandidateID = 13;
    COMMIT TRANSACTION;
    GO

Combinazione dell'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 la seconda SqlConnecton viene aperta all'interno di TransactionScope, verrà promossa in modo implicito alla transazione distribuita, dopo il cui avvio, tutte le richieste di transazioni successive, provenienti da .NET o Transact-SQL, verranno unite alla transazione distribuita padre. Di conseguenza, tutti gli ambiti delle transazioni 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, quindi non verrà eseguito il commit di alcun risultato prima che venga richiamato il metodo Complete() sull'oggetto TransactionScope. Eliminando definitivamente quest’ultimo prima del completamento, tutte le modifiche apportate all'interno dell'ambito vengono ripristinate allo stato precedente.
  • L'istruzione ROLLBACK ripristinerà l'intero oggetto TransactionScope allo stato precedente. Eventuali tentativi di integrazione di nuove transazioni all'interno di TransactionScope avranno esito negativo in seguito, e tenteranno 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();
}

L'esempio seguente mostra una transazione promossa in modo implicito a transazione distribuita dopo l'avvio del secondo oggetto SqlConnection 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 il database SQL

Le transazioni di database elastico sono supportate in diversi server di database SQL nel database SQL di Azure. Quando le transazioni oltrepassano i limiti dei server, i server partecipanti devono essere innanzitutto inseriti 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. Se le transazioni si estendono su più di due server, è necessaria una relazione di comunicazione per ogni 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 un database SQL di Azure. La relazione è simmetrica, ovvero entrambi possono avviare le 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 l’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 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 in ingresso e in uscita del gruppo di sicurezza di rete devono consentire le porte 5024 e 11000-12000 in tutte le reti virtuali partecipanti.

Server Trust Groups on Azure Portal

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

Distributed transactions with Azure SQL Managed Instance using elastic transactions

Monitoraggio dello stato delle transazioni

Per monitorare lo stato e l'avanzamento delle transazioni di database elastico in corso, usare viste a gestione dinamica (DMV). Tutte le viste a gestione dinamica correlate alle transazioni sono rilevanti per le transazioni distribuite nel database SQL e nell’Istanza gestita di SQL. È possibile trovare l'elenco delle viste a gestione dinamica corrispondente in 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 le transazioni attualmente 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 ulteriori informazioni, vedere la documentazione sulle DMV.
  • sys.dm_tran_database_transactions: fornisce altre informazioni sulle transazioni, come ad esempio la posizione della transazione nel log. Per ulteriori informazioni, vedere la documentazione sulle DMV.
  • sys.dm_tran_locks: fornisce informazioni sui blocchi attualmente mantenuti dalle transazioni in corso. Per ulteriori informazioni, vedere la documentazione sulle DMV.

Limiti

Per le transazioni di database elastico nel database SQL si applicano attualmente le limitazioni seguenti:

  • Sono supportate solo le transazioni tra database nel database SQL. Altri provider di risorse X/Open XA e database al di fuori del database SQL non possono partecipare alle transazioni di database elastico. Ciò significa che le transazioni di database elastico non possono estendersi in locale a SQL Server e al database SQL di Azure. 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.
  • Non sono supportate transazioni tra i servizi WCF. 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 (note anche come transazioni elastiche o transazioni distribuite supportate in modo nativo) nell’Istanza gestita di SQL:

  • Con questa tecnologia sono supportate solo le transazioni tra database in istanze gestite. Per tutti gli altri scenari che possono includere provider di risorse X/Open XA e database all'esterno dell’Istanza gestita di SQL di Azure è consigliabile configurare il controllo DTC per l’Istanza gestita di SQL di Azure.
  • Non sono supportate transazioni tra i servizi WCF. 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.
  • L’Istanza gestita di SQL di Azure deve far parte di un Gruppo di attendibilità del server per partecipare alla transazione distribuita.
  • Le limitazioni dei gruppi di attendibilità del server hanno effetti 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 sono distribuiti) e devono consentire il riferimento reciprocamente usando FQDN privati. Le applicazioni client possono usare transazioni distribuite su endpoint privati. Inoltre, nei casi in cui Transact-SQL sfrutta i server collegati che fanno riferimento a endpoint privati, le applicazioni client possono anche usare transazioni distribuite su endpoint pubblici. Questa limitazione è illustrata nel diagramma seguente.

Private endpoint connectivity limitation

Passaggi successivi