Den Fehler verstehen

Der Fehler “Communication with the underlying transaction manager has failed” tritt auf, wenn der Microsoft Distributed Transaction Coordinator (MSDTC)-Dienst auf einer Maschine nicht mit dem MSDTC-Dienst auf einer anderen Maschine kommunizieren kann, um eine verteilte Transaktion zu koordinieren.

Der vollständige Fehler und die innere Ausnahme sehen typischerweise so aus:

System.Transactions.TransactionManagerCommunicationException:
Communication with the underlying transaction manager has failed.

Inner Exception:
The MSDTC transaction manager was unable to pull the transaction from the
source transaction manager due to communication problems. Possible causes are:
a firewall is present and it doesn't have an exception for the MSDTC process,
the two machines cannot find each other by their NetBIOS names, or the support
for network transactions is not enabled for one of the two transaction managers.
(Exception from HRESULT: 0x8004D02B)

Dies tritt häufig auf, wenn:

  • Eine .NET-Anwendung TransactionScope über mehrere SQL Server-Instanzen hinweg verwendet
  • Eine gespeicherte Prozedur Verbindungsserver mit BEGIN DISTRIBUTED TRANSACTION verwendet
  • WCF-Dienste transaktionale Bindungen zwischen Maschinen verwenden

Wann verteilte Transaktionen ausgelöst werden

Möglicherweise ist Ihnen nicht bewusst, dass Ihre Anwendung verteilte Transaktionen verwendet. Sie werden in diesen Szenarien automatisch eskaliert:

// This creates a distributed transaction if conn1 and conn2 point to different servers
using (TransactionScope scope = new TransactionScope())
{
    using (SqlConnection conn1 = new SqlConnection("Server=Server1;Database=DB1;..."))
    using (SqlConnection conn2 = new SqlConnection("Server=Server2;Database=DB2;..."))
    {
        conn1.Open();
        // Execute work on Server1

        conn2.Open();  // This escalates to a distributed transaction
        // Execute work on Server2
    }
    scope.Complete();
}

Selbst das Öffnen von zwei Verbindungen zum gleichen Server kann in einigen Fällen zu MSDTC eskalieren (vor .NET 4.0 mit SQL Server 2008).

Schritt-für-Schritt-Lösung

Schritt 1: MSDTC-Sicherheitseinstellungen konfigurieren

Dies muss auf beiden an der Transaktion beteiligten Maschinen durchgeführt werden.

  1. Öffnen Sie die Komponentendienste durch Ausführen von dcomcnfg
  2. Navigieren Sie zu: Komponentendienste > Computer > Arbeitsplatz > Koordinator für verteilte Transaktionen > Lokaler DTC
  3. Klicken Sie mit der rechten Maustaste auf Lokaler DTC und wählen Sie Eigenschaften
  4. Gehen Sie zur Registerkarte Sicherheit
  5. Konfigurieren Sie die folgenden Einstellungen:
EinstellungWert
Netzwerk-DTC-ZugriffAktiviert
Remoteclients zulassenAktiviert
Eingehend zulassenAktiviert
Ausgehend zulassenAktiviert
Gegenseitige Authentifizierung erforderlichSiehe Hinweis unten
Keine Authentifizierung erforderlichWählen Sie dies, wenn die Maschinen NICHT in derselben Domäne sind
XA-Transaktionen aktivierenAktiviert (bei Verwendung von XA)
SNA LU 6.2-Transaktionen aktivierenDeaktiviert lassen, sofern nicht benötigt

Hinweis zur Authentifizierung: Wenn sich beide Maschinen in derselben Active Directory-Domäne befinden, verwenden Sie Gegenseitige Authentifizierung erforderlich. Wenn sie sich in verschiedenen Domänen oder Arbeitsgruppen befinden, verwenden Sie Keine Authentifizierung erforderlich.

  1. Klicken Sie auf OK und bestätigen Sie, dass Sie den MSDTC-Dienst neu starten möchten

Schritt 2: Windows-Firewall konfigurieren

Die innere Ausnahme erwähnt ausdrücklich die Firewall. Unter Windows 7, Windows Server 2008 und späteren Versionen müssen Sie die MSDTC-Firewall-Ausnahme explizit aktivieren, auch wenn Sie glauben, dies bereits getan zu haben.

Verwenden der Windows-Firewall mit erweiterter Sicherheit

# Enable the predefined MSDTC firewall rules (do this on BOTH machines)
Enable-NetFirewallRule -DisplayGroup "Distributed Transaction Coordinator"

Oder manuell über die grafische Oberfläche:

  1. Öffnen Sie die Windows-Firewall mit erweiterter Sicherheit (wf.msc)
  2. Klicken Sie auf Eingehende Regeln
  3. Suchen Sie die Regeln in der Gruppe Koordinator für verteilte Transaktionen
  4. Aktivieren Sie alle (Rechtsklick > Regel aktivieren):
    • Koordinator für verteilte Transaktionen (RPC)
    • Koordinator für verteilte Transaktionen (RPC-EPMAP)
    • Koordinator für verteilte Transaktionen (TCP-In)

Wiederholen Sie dies auch für die ausgehenden Regeln.

Einen festen MSDTC-Port konfigurieren (empfohlen für Firewalls)

Standardmäßig verwendet MSDTC dynamische RPC-Ports, was die Firewall-Konfiguration erschwert. Sie können einen festen Port zuweisen:

  1. Öffnen Sie die Komponentendienste (dcomcnfg)
  2. Navigieren Sie zu Arbeitsplatz > Koordinator für verteilte Transaktionen > Lokaler DTC > Eigenschaften
  3. Es gibt keine grafische Oberfläche für die Port-Einstellung; verwenden Sie die Registrierung:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC]
"ServerTcpPort"=dword:00001388

Dies konfiguriert MSDTC auf TCP-Port 5000 (0x1388). Erstellen Sie dann eine spezifische Firewall-Regel:

New-NetFirewallRule -DisplayName "MSDTC Fixed Port" -Direction Inbound -Protocol TCP -LocalPort 5000 -Action Allow
New-NetFirewallRule -DisplayName "MSDTC RPC" -Direction Inbound -Protocol TCP -LocalPort 135 -Action Allow

Nach der Port-Änderung starten Sie den MSDTC-Dienst neu:

Restart-Service -Name MSDTC

Schritt 3: NetBIOS-Namensauflösung überprüfen

Die beiden Maschinen müssen sich gegenseitig über den NetBIOS-Namen auflösen können, nicht nur über die IP-Adresse oder den FQDN. MSDTC verwendet intern den NetBIOS-Namen.

Testen Sie von jeder Maschine aus:

:: From the client, test resolution of the server
ping SERVER1
nbtstat -a SERVER1

:: From the server, test resolution of the client
ping CLIENT1
nbtstat -a CLIENT1

Wenn die Namensauflösung fehlschlägt, fügen Sie Einträge zur hosts-Datei auf beiden Maschinen hinzu:

# C:\Windows\System32\drivers\etc\hosts
10.0.1.10    SERVER1
10.0.1.20    CLIENT1

Oder besser, stellen Sie sicher, dass WINS oder DNS mit entsprechenden Einträgen konfiguriert ist.

Schritt 4: Überprüfen, ob der MSDTC-Dienst läuft

# Check MSDTC service status on both machines
Get-Service -Name MSDTC | Select-Object Name, Status, StartType

# Ensure it is set to start automatically
Set-Service -Name MSDTC -StartupType Automatic
Start-Service -Name MSDTC

Schritt 5: MSDTC-Kommunikation testen

Verwenden Sie das DTCPing-Tool von Microsoft, um die MSDTC-Konnektivität zwischen zwei Maschinen zu testen.

  1. Laden Sie DTCPing von Microsoft herunter
  2. Führen Sie dtcping.exe auf beiden Maschinen gleichzeitig aus
  3. Geben Sie auf jeder Maschine den NetBIOS-Namen der anderen Maschine ein
  4. Klicken Sie auf Ping — ein erfolgreicher Test zeigt “successfully completed” sowohl für die RPC- als auch die Transaktionstests

Alternativ testen Sie über PowerShell:

# Test RPC endpoint mapper connectivity
Test-NetConnection -ComputerName SERVER1 -Port 135

# Test the MSDTC fixed port (if configured)
Test-NetConnection -ComputerName SERVER1 -Port 5000

Verteilte Transaktionen mit SQL Server

Szenario: Verbindungsserver-Abfragen

Wenn SQL Server eine Abfrage über einen Verbindungsserver ausführt, ist MSDTC beteiligt:

-- This triggers a distributed transaction
BEGIN DISTRIBUTED TRANSACTION
    INSERT INTO LocalDB.dbo.Orders (OrderID, CustomerName)
    SELECT OrderID, CustomerName FROM [RemoteServer].RemoteDB.dbo.Orders
    WHERE OrderDate > '2024-01-01';
COMMIT TRANSACTION

Stellen Sie sicher, dass MSDTC auf beiden SQL Server-Maschinen konfiguriert ist.

Szenario: .NET TransactionScope

using (var scope = new TransactionScope())
{
    using (var conn = new SqlConnection(connectionString1))
    {
        conn.Open();
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO Table1 (Col1) VALUES ('Value1')";
            cmd.ExecuteNonQuery();
        }
    }

    using (var conn = new SqlConnection(connectionString2))
    {
        conn.Open();  // Escalates to distributed transaction
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO Table2 (Col1) VALUES ('Value2')";
            cmd.ExecuteNonQuery();
        }
    }

    scope.Complete();
}

Unnötige verteilte Transaktionen vermeiden

Wenn beide Verbindungen auf die gleiche SQL Server-Instanz zeigen, können Sie die MSDTC-Eskalation vermeiden, indem Sie eine einzelne Verbindung wiederverwenden:

using (var scope = new TransactionScope())
using (var conn = new SqlConnection(connectionString))
{
    conn.Open();

    using (var cmd1 = conn.CreateCommand())
    {
        cmd1.CommandText = "INSERT INTO DB1.dbo.Table1 (Col1) VALUES ('Value1')";
        cmd1.ExecuteNonQuery();
    }

    using (var cmd2 = conn.CreateCommand())
    {
        cmd2.CommandText = "INSERT INTO DB2.dbo.Table2 (Col1) VALUES ('Value2')";
        cmd2.ExecuteNonQuery();
    }

    scope.Complete();
}

Checkliste zur Fehlerbehebung

Gehen Sie diese Checkliste auf beiden Maschinen durch:

  1. Der MSDTC-Dienst läuft und ist auf automatischen Start eingestellt
  2. Die Sicherheitseinstellungen der Komponentendienste sind korrekt (Netzwerk-DTC-Zugriff aktiviert, Eingehend/Ausgehend zulassen)
  3. Die Windows-Firewall hat die Ausnahme für den Koordinator für verteilte Transaktionen sowohl für eingehenden als auch ausgehenden Datenverkehr aktiviert
  4. Die NetBIOS-Namensauflösung funktioniert in beide Richtungen
  5. Die gleiche MSDTC-Authentifizierungsstufe auf beiden Maschinen (Gegenseitige Authentifizierung, Authentifizierung eingehender Aufrufer oder Keine Authentifizierung)
  6. RPC-Port 135 ist zwischen den Maschinen erreichbar
  7. Der DTCPing-Test ist in beide Richtungen erfolgreich
  8. Das Antivirenprogramm blockiert keinen MSDTC- oder RPC-Datenverkehr
  9. SQL Server hat den Remotezugriff aktiviert (sp_configure 'remote access', 1)
  10. Cluster-Umgebungen: Wenn SQL Server in einem Cluster ist, konfigurieren Sie MSDTC als Cluster-Ressource, nicht nur auf den einzelnen Knoten

Häufige Fallstricke

Die Windows-Firewall „sieht” offen aus, ist es aber nicht

Unter Windows 7 und Server 2008+ kann die Firewall so aussehen, als wären die MSDTC-Ausnahmen aktiviert, aber die Regeln können auf das falsche Netzwerkprofil angewendet sein (Domäne vs. Privat vs. Öffentlich). Überprüfen Sie:

Get-NetFirewallRule -DisplayGroup "Distributed Transaction Coordinator" |
    Select-Object Name, Enabled, Profile, Direction

Stellen Sie sicher, dass die Regeln für das richtige Profil aktiviert sind.

Unterschiedliche MSDTC-Instanzen in einem Cluster

In einem Windows Server-Failovercluster sollte jede geclusterte SQL Server-Instanz eine eigene MSDTC-Ressource haben. Der lokale MSDTC auf dem Knoten ist möglicherweise nicht derjenige, der die Transaktionen für die geclusterte SQL-Instanz verarbeitet.

Beschädigung der MSDTC-Protokolldatei

Wenn die MSDTC-Protokolldatei beschädigt ist, kann der Dienst starten, aber bei der Verarbeitung von Transaktionen fehlschlagen:

:: Reset the MSDTC log
msdtc -resetlog

Zusammenfassung

Der Fehler “Communication with the underlying transaction manager has failed” ist ein Problem der Firewall- und MSDTC-Konfiguration. Um ihn zu beheben, öffnen Sie die Komponentendienste auf beiden Maschinen und aktivieren Sie den Netzwerk-DTC-Zugriff mit Eingehend zulassen und Ausgehend zulassen. Aktivieren Sie dann die Ausnahme für den Koordinator für verteilte Transaktionen in der Windows-Firewall auf beiden Maschinen. Überprüfen Sie, dass sich die Maschinen gegenseitig über den NetBIOS-Namen auflösen können, und verwenden Sie DTCPing, um die MSDTC-Kommunikation von Ende zu Ende zu validieren.