Introducción sobre las transacciones de base de datos elástica con Base de datos SQL de Azure

Se aplica a:Azure SQL DatabaseAzure SQL Managed Instance

En este artículo se describe el uso de transacciones de bases de datos elásticas que permiten ejecutar transacciones distribuidas entre bases de datos en la nube para Azure SQL Database y Azure SQL Managed Instance. En este artículo, los términos "transacciones distribuidas" y "transacciones de base de datos elástica" se consideran sinónimos y se usan indistintamente.

Nota:

También puede usar el Coordinador de transacciones distribuidas (DTC) para Azure SQL Managed Instance (versión preliminar) para ejecutar transacciones distribuidas en entornos mixtos.

Información general

Las transacciones de base de datos elástica de Azure SQL Database y Azure SQL Managed Instance permiten ejecutar transacciones que abarcan varias bases de datos. Las transacciones de base de datos elástica están disponibles para aplicaciones .NET con ADO.NET y se integran con la conocida experiencia de programación en la que se emplean las clases System.Transaction. Para obtener la biblioteca, vea .NET Framework 4.6.1 (instalador web). Además, las transacciones distribuidas de instancia administrada están disponibles en Transact-SQL.

De forma local, este escenario suele requerir la ejecución del Coordinador de transacciones distribuidas de Microsoft (MSDTC). Puesto que el Coordinador de transacciones distribuidas no está disponible en Azure SQL Database, la capacidad de coordinar transacciones distribuidas se integra directamente en SQL Database y SQL Managed Instance. Pero, para SQL Managed Instance, también puede usar el Coordinador de transacciones distribuidas para ejecutar transacciones distribuidas en varios entornos mixtos, como en instancias administradas, varios SQL Server, otros sistemas de administración de bases de datos relacionales (RDBMS), aplicaciones personalizadas y otros participantes de transacciones hospedados en cualquier entorno que pueda establecer la conectividad de red con Azure.

Las aplicaciones pueden conectarse a cualquier base de datos para iniciar transacciones distribuidas, y una de las bases de datos o de los servidores coordina de forma transparente la transacción distribuida, como se muestra en la ilustración siguiente.

Distributed transactions with Azure SQL Database using elastic database transactions

Escenarios frecuentes

Las transacciones de base de datos elástica permiten a las aplicaciones realizar cambios atómicos en los datos almacenados en varias bases de datos diferentes. Tanto SQL Database como SQL Managed Instance admiten experiencias de desarrollo del lado del cliente en C# y .NET. La experiencia del servidor (código escrito en procedimientos almacenados o scripts del servidor) mediante Transact-SQL solo está disponible para SQL Managed Instance.

Importante

No se admite la ejecución de transacciones de base de datos elástica entre Azure SQL Database y Azure SQL Managed Instance. La transacción de bases de datos elástica solo puede abarcar un conjunto de bases de SQL Database o un conjunto de bases de datos entre instancias administradas.

Las transacciones de base de datos elástica están orientadas a los siguientes escenarios:

  • Aplicaciones de varias bases de datos en Azure: con este escenario, los datos se particionan verticalmente entre varias bases de datos de SQL Database o SQL Managed Instance, de forma que diferentes clases de datos residen en diferentes bases de datos. Algunas operaciones requieren cambios en los datos que se mantienen en dos o más bases de datos. La aplicación emplea transacciones de base de datos elástica para coordinar los cambios entre las bases de datos y garantizar la atomicidad.
  • Aplicaciones de base de datos particionada en Azure: con este escenario, la capa de datos usa la biblioteca cliente de base de datos elástica o el particionamiento automático para particionar horizontalmente los datos entre muchas bases de datos en SQL Database o SQL Managed Instance. Un caso destacado de uso es cuando existe la necesidad de realizar cambios atómicos en una aplicación particionada multiempresa cuando los cambios abarcan a los inquilinos. Piense por ejemplo en una transferencia desde un inquilino a otro, donde cada uno reside en una base de datos diferente. Un segundo caso es el particionamiento específico para satisfacer las necesidades de capacidad de un inquilino de gran tamaño, lo que a su vez supone normalmente que algunas operaciones atómicas deban extenderse entre varias bases de datos usadas para el mismo inquilino. Un tercer caso es el de las actualizaciones atómicas para hacer referencia a los datos que se replican entre bases de datos. Ahora se pueden coordinar operaciones de transacciones atómicas a lo largo de estas líneas entre varias bases de datos. Las transacciones de base de datos elástica usan la confirmación en dos fases para garantizar la atomicidad de las transacciones entre bases de datos. Esto resulta adecuado para transacciones que suponen menos de 100 bases de datos a la vez en una única transacción. Aunque estos límites no se aplican, se supone que las tasas de rendimiento y éxito de las transacciones de base de datos elástica se verán afectadas cuando se excedan estos límites.

Instalación y migración

Las capacidades de las transacciones de base de datos elástica se proporcionan por medio de actualizaciones de las bibliotecas .NET System.Data.dll y System.Transactions.dll. Los archivos DLL garantizan que la confirmación en dos fases se usa cuando es necesario para asegurar la atomicidad. Para empezar a desarrollar aplicaciones mediante transacciones de base de datos elástica, instale .NET Framework 4.6.1 o versión posterior. Cuando se ejecutan en una versión anterior de .NET Framework, las transacciones no podrán promoverse a una transacción distribuida y se producirá una excepción.

Tras la instalación, puede usar las API de transacciones distribuidas de System.Transactions con conexiones a SQL Database y SQL Managed Instance. Si tiene aplicaciones de MSDTC existentes que usan estas API, recompílelas para .NET 4.6 después de instalar Framework 4.6.1. Si los proyectos se destinan a .NET 4.6, usan automáticamente los archivos DLL actualizados de la nueva versión de Framework, y las llamadas API de transacciones distribuidas en combinación con las conexiones a SQL Database o SQL Managed Instance ahora se realizan correctamente.

Recuerde que las transacciones de base de datos elástica no precisan la instalación de MSDTC. Por el contrario, se administran directamente mediante y dentro del servicio. Con ello se simplifican enormemente los escenarios de nube, ya que no es necesario implementar MSDTC para usar transacciones distribuidas con SQL Database o SQL Managed Instance. En la sección 4 se explica con más detalle cómo implementar transacciones de base de datos elástica y la versión de .NET Framework necesaria junto con sus aplicaciones de nube en Azure.

Instalación de .NET para Azure Cloud Services

Azure proporciona varias ofertas para hospedar aplicaciones. NET. Hay disponible una comparación de las diferentes ofertas en Comparación de Azure App Service, Cloud Services y Virtual Machines. Si el SO invitado de la oferta es inferior a .NET 4.6.1, que es el que se requiere para las transacciones elásticas, debe actualizar el SO invitado a 4.6.1.

Para Azure App Service, no se admiten las actualizaciones del SO invitado en estos momentos. En el caso de Azure Virtual Machines, solo tiene que iniciar sesión en la máquina virtual y ejecutar el instalador para la última versión de .NET Framework. Para Azure Cloud Services, hay que incluir la instalación de una versión más reciente de .NET en las tareas de inicio de la implementación. Los conceptos y los pasos se documentan en Instalación de .NET en un rol de servicio en la nube.

Tenga en cuenta que el instalador de .NET 4.6.1 puede requerir más espacio de almacenamiento temporal durante el proceso de arranque en los Servicios en la nube de Azure que el instalador de .NET 4.6. Para garantizar una instalación correcta, debe aumentar el almacenamiento temporal para el servicio en la nube de Azure en el archivo ServiceDefinition.csdef en la sección LocalResources y en la configuración del entorno de la tarea de inicio, como se muestra en el ejemplo siguiente:

<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>

Experiencia de desarrollo de .NET

Aplicaciones de varias bases de datos

En el ejemplo de código siguiente se usa la experiencia de programación conocida con System.Transactions de .NET. La clase TransactionScope establece una transacción de ambiente en. NET. (Una "transacción de ambiente" es aquella que reside en el subproceso actual). Todas las conexiones abiertas dentro de TransactionScope participan en la transacción. Si intervienen bases de datos diferentes, la transacción se eleva automáticamente a transacción distribuida. El resultado de la transacción se controla mediante la configuración del ámbito como completo para indicar una confirmación.

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();
}

Aplicaciones de base de datos particionada

Las transacciones de base de datos elástica de SQL Database y SQL Managed Instance también admiten la coordinación de transacciones distribuidas en las que se usa el método OpenConnectionForKey de la biblioteca cliente de base de datos elástica a fin de abrir conexiones para una capa de datos escalada horizontalmente. Tenga en cuenta los casos en lo que deba garantizar la coherencia de las transacciones para los cambios entre varios valores diferentes de clave de particionamiento. Las conexiones a las particiones que hospedan los diferentes valores de clave de particionamiento se interrumpen mediante OpenConnectionForKey. Por lo general, las conexiones pueden ser a particiones diferentes de forma que, para garantizar las transacciones, se necesita una transacción distribuida. En el ejemplo de código siguiente se muestra este método. Se supone que una variable llamada shardmap se usa para representar un mapa de particiones de la biblioteca de cliente de base de datos elástica:

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();
}

Experiencia de desarrollo de Transact-SQL

Las transacciones distribuidas del servidor que usan Transact-SQL solo están disponibles para Azure SQL Managed Instance. La transacción distribuida solo se puede ejecutar entre instancias que pertenezcan al mismo Grupo de confianza del servidor. En este caso, las instancias administradas deben usar un servidor vinculado para hacerse referencia entre sí.

En el siguiente código de Transact-SQL de ejemplo se usa BEGIN DISTRIBUTED TRANSACTION para iniciar la transacción distribuida.

    -- 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

Combinación de la experiencia de desarrollo de .NET y Transact-SQL

Las aplicaciones .NET que usan las clases System.Transaction pueden combinar la clase TransactionScope con la instrucción de Transact-SQL BEGIN DISTRIBUTED TRANSACTION. En TransactionScope, la transacción interna que ejecuta BEGIN DISTRIBUTED TRANSACTION se promueve explícitamente a transacción distribuida. Además, cuando se abre el segundo SqlConnecton en TransactionScope, se promociona implícitamente a transacción distribuida. Una vez iniciada la transacción distribuida, todas las solicitudes posteriores de transacciones, tanto si proceden de .NET como de Transact-SQL, se unen a la transacción distribuida primaria. Como consecuencia, todos los ámbitos de transacción anidados iniciados por la instrucción BEGIN terminan en la misma transacción y las instrucciones COMMIT/ROLLBACK tienen el efecto siguiente en el resultado general:

  • La instrucción COMMIT no tiene ningún efecto en el ámbito de la transacción iniciado por la instrucción BEGIN, es decir, no se confirman resultados antes de que se invoque al método Complete() en el objeto TransactionScope. Si el objeto TransactionScope se destruye antes de completarse, se revierten todos los cambios realizados dentro del ámbito.
  • La instrucción ROLLBACK hace que se revierta TransactionScope completamente. Cualquier intento de dar de alta nuevas transacciones en TransactionScope produce un error posteriormente, así como el intento de invocar a Complete() en el objeto TransactionScope.

Este es un ejemplo en el que la transacción se promueve explícitamente a transacción distribuida 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();
}

En el ejemplo siguiente se muestra una transacción que se promueve implícitamente a transacción distribuida una vez que se inicia el segundo SqlConnecton en 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();
}

Transacciones para SQL Database

Se admiten transacciones de la base de datos elástica entre diferentes servidores en Azure SQL Database. Cuando las transacciones cruzan los límites del servidor, los servidores implicados en primer lugar deben involucrarse en una relación de comunicación mutua. Una vez que se ha establecido la relación de comunicación, cualquier base de datos ubicada en uno de los dos servidores puede participar en transacciones elásticas con bases de datos desde el otro servidor. En el caso de las transacciones distribuidas en más de dos servidores, debe existir una relación de comunicación para cualquier par de servidores.

Use los siguientes cmdlets de PowerShell para administrar las relaciones de comunicación entre los servidores para las transacciones de la base de datos elástica:

  • New-AzSqlServerCommunicationLink: este cmdlet se usa para crear una relación de comunicación nueva entre dos servidores en Azure SQL Database. La relación es simétrica, lo que significa que ambos servidores pueden iniciar transacciones con el otro servidor.
  • Get-AzSqlServerCommunicationLink: este cmdlet se usa para recuperar una relación de comunicación existente y sus propiedades.
  • Remove-AzSqlServerCommunicationLink: este cmdlet se usa para eliminar una relación de comunicación existente.

Transacciones para SQL Managed Instance

Las transacciones distribuidas se admiten entre bases de datos dentro de varias instancias. Cuando las transacciones cruzan los límites de las instancias administradas, las instancias participantes deben estar en una relación de comunicación y seguridad mutua. Esto se hace mediante la creación de un grupo de confianza del servidor, operación que se puede realizar mediante Azure Portal, Azure PowerShell o la CLI de Azure. Si las instancias no están en la misma red virtual, es necesario configurar el emparejamiento de red virtual y las reglas de entrada y salida del grupo de seguridad de red deben permitir los puertos 5024 y 11000-12000 en todas las redes virtuales que participan.

Server Trust Groups on Azure Portal

En el diagrama siguiente se muestra el grupo de confianza del servidor con instancias administradas que pueden ejecutar transacciones distribuidas con .NET o Transact-SQL:

Distributed transactions with Azure SQL Managed Instance using elastic transactions

Supervisión del estado de la transacción

Use vistas de administración dinámica (DMV) para supervisar el estado y el progreso de las transacciones en curso de base de datos elástica. Todas las DMV relacionadas con las transacciones son pertinentes para las transacciones distribuidas en SQL Database y SQL Managed Instance. Puede encontrar la lista correspondiente de DMV aquí: Funciones y vistas de administración dinámica relacionadas con transacciones (Transact-SQL).

Estas DMV son especialmente útiles:

  • sys.dm_tran_active_transactions: enumera las transacciones actualmente activas y su estado. La columna UOW (unidad de trabajo) puede identificar las distintas transacciones secundarias que pertenecen a la misma transacción distribuida. Todas las transacciones de la misma transacción distribuida llevan el mismo valor de UOW. Para obtener más información, vea la documentación de DMV.
  • sys.dm_tran_database_transactions: proporciona información adicional sobre las transacciones, como la colocación de la transacción en el registro. Para obtener más información, vea la documentación de DMV.
  • sys.dm_tran_locks: ofrece información sobre los bloqueos actuales de las transacciones. Para obtener más información, vea la documentación de DMV.

Limitaciones

Las limitaciones siguientes se aplican actualmente a transacciones de base de datos elástica en SQL Database:

  • Se admiten únicamente transacciones entre bases de datos en SQL Database. Otros proveedores de recursos y bases de datos de X/Open XA externos a SQL Database no podrán participar en transacciones de base de datos elástica. Esto significa que dichas transacciones no pueden extenderse entre bases de datos locales de SQL Server y Azure SQL Database. Para las transacciones distribuidas en el entorno local, siga usando MSDTC.
  • Solo se admiten transacciones coordinadas por el cliente desde una aplicación .NET. Está prevista la compatibilidad en el lado servidor con T-SQL, por ejemplo, INICIAR TRANSACCIÓN DISTRIBUIDA, pero aún no se encuentra disponible.
  • No se admiten las transacciones por los servicios WCF. Por ejemplo, tiene un método de servicio de WCF que se ejecuta una transacción. Si se encierra la llamada dentro de un ámbito de transacción, se producirá un error como System.ServiceModel.ProtocolException.

Actualmente se aplican las siguientes limitaciones a las transacciones distribuidas (también conocidas como transacciones elásticas o transacciones distribuidas admitidas de forma nativa) en SQL Managed Instance:

  • Con esta tecnología se admiten únicamente transacciones en bases de datos de las instancias administradas. Para todos los demás escenarios que pueden incluir proveedores de recursos y bases de datos X/Open XA fuera de Azure SQL Managed Instance, debe configurar DTC para Azure SQL Managed Instance.
  • No se admiten las transacciones por los servicios WCF. Por ejemplo, tiene un método de servicio de WCF que se ejecuta una transacción. Si se encierra la llamada dentro de un ámbito de transacción, se producirá un error como System.ServiceModel.ProtocolException.
  • Azure SQL Managed Instance debe formar parte de un Grupo de confianza del servidor para poder participar en transacciones distribuidas.
  • Las limitaciones de los Grupos de confianza del servidor afectan a las transacciones distribuidas.
  • Las instancias de Managed Instance que participan en las transacciones distribuidas deben disponer de conectividad mediante puntos de conexión privados (mediante la dirección IP privada de la red virtual en la que se implementan) y deben hacerse referencia mutuamente mediante FQDN privados. Las aplicaciones cliente pueden usar transacciones distribuidas en puntos de conexión privados. Además, en aquellos casos en los que Transact-SQL aproveche los servidores vinculados que hacen referencia a puntos de conexión privados, las aplicaciones cliente también pueden usar las transacciones distribuidas en puntos de conexión públicos. Dicha limitación se explica en el siguiente diagrama.

Private endpoint connectivity limitation

Pasos siguientes