Blog / · Thomas Falkner

Named Pipes, TCP/IP oder Shared Memory: Wie der SQL Server wirklich kommuniziert

Named Pipes, TCP/IP oder Shared Memory: Wie der SQL Server wirklich kommuniziert

Ein Kunde meldet, die Anmeldung an der Sage 100 dauere seit dem Serverwechsel „irgendwie länger". Nicht dramatisch, zwei Sekunden vielleicht. Der SQL Server ist gesund, die Wartezeiten sind unauffällig, die Abfragen laufen schnell. Trotzdem hängt jeder Verbindungsaufbau. Zwei Sekunden klingen nach nichts, bis Du nachrechnest, wie oft eine ERP-Anwendung am Tag eine Verbindung öffnet.

Die Ursache lag nicht im SQL Server, sondern eine Schicht darunter: beim Protokoll, über das Client und Server überhaupt miteinander sprechen. Genauer gesagt bei der Reihenfolge, in der der Client sie durchprobiert. Dieser Beitrag geht tief in diese Schicht hinein. Wie Shared Memory, Named Pipes und TCP/IP technisch funktionieren, warum Named Pipes über WAN einbrechen, lokal aber blitzschnell sind, und wie Du in einer Minute feststellst, worüber Deine Verbindungen tatsächlich laufen.

Die Ebene unter der Abfrage

Was zwischen Client und SQL Server hin und her geht, ist immer dasselbe: TDS, das Tabular Data Stream Protokoll. Login, Abfragetext, Ergebnismengen, Fehlermeldungen, alles ist TDS. Das ändert sich nie, egal wie Du verbunden bist.

Was sich ändert, ist der Transportweg darunter. TDS muss irgendwie vom Clientprozess zum Serverprozess kommen, und dafür bietet der SQL Server unter Windows drei Wege an. Sie unterscheiden sich nicht darin, was übertragen wird, sondern darin, welche Windows-Mechanismen den Transport übernehmen. Daraus ergeben sich die Unterschiede bei Geschwindigkeit, Firewall, Authentifizierung und Fehlerbildern.

Ein viertes Protokoll namens VIA gab es bis SQL Server 2008 R2. Es ist mit SQL Server 2012 entfallen. Wenn Du es irgendwo noch in einer Dokumentation findest, ist die Dokumentation alt.

Shared Memory: Der kurze Dienstweg

Shared Memory ist der simpelste der drei Wege und funktioniert nur, wenn Client und SQL Server auf derselben Maschine laufen. Kein Netzwerkstack, keine Pakete, keine Ports. Beide Prozesse greifen auf denselben physischen Speicherbereich zu, den der Windows-Kernel beiden sichtbar macht, und synchronisieren sich über Ereignisobjekte. Der Client schreibt, signalisiert, der Server liest.

Weil keine Protokollschicht dazwischen liegt, gibt es auch nichts zu konfigurieren. Shared Memory hat in der Konfiguration keine einzige Einstellung. Du kannst es nur an- oder abschalten.

Im Verbindungsstring hat Shared Memory die Form lpc:<Servername>, bei einer benannten Instanz lpc:<Servername>\<Instanz>. Das Kürzel steht für Local Procedure Call. Einen Alias kannst Du dafür nicht anlegen, und in der Protokollreihenfolge des Clients steht Shared Memory immer ganz oben. Es lässt sich nicht nach unten schieben, nur deaktivieren. Genau das ist übrigens der übliche Grund, es abzuschalten: Wenn Du auf dem Server selbst testen willst, ob eine TCP-Verbindung funktioniert, musst Du Shared Memory aus dem Weg räumen, sonst gewinnt es jedes Mal.

Named Pipes: Ein Dateisystem, das keines ist

Named Pipes sind ein Windows-Mechanismus für die Kommunikation zwischen Prozessen. Eine Pipe ist ein benannter Kanal, der sich ansprechen lässt wie eine Datei, und genau das ist der entscheidende Punkt für alles Weitere. Der SQL Server öffnet beim Start eine Pipe und wartet darauf, dass jemand sie öffnet.

Die Standardinstanz lauscht auf \\.\pipe\sql\query. Der Punkt steht für den lokalen Rechner, pipe sagt, dass es eine Named Pipe ist, und sql\query ist der Name. Eine benannte Instanz nutzt stattdessen:

\\<Rechnername>\pipe\MSSQL$<Instanzname>\sql\query

Lokal läuft das im Kernelmodus ab und ist sehr schnell. Der Zugriff bleibt vollständig innerhalb der Maschine, es gibt keinen Netzwerkverkehr, nur Kernelaufrufe.

Über das Netzwerk sieht es völlig anders aus. Eine Remote-Pipe wird nicht über ein eigenes Datenbankprotokoll angesprochen, sondern über SMB, also über dasselbe Protokoll, über das auch Dateifreigaben laufen. Der Client baut eine SMB-Sitzung zum Server auf, meldet sich an der versteckten Freigabe IPC$ an und öffnet die Pipe darüber wie eine Datei. Das bedeutet in der Praxis drei Dinge.

  • Der Verkehr läuft über Port 445, nicht über 1433. Die Windows-Firewall schließt diesen Port standardmäßig.
  • Vor dem ersten TDS-Byte steht eine vollständige Windows-Anmeldung an der Freigabe. Namensauflösung und Authentifizierung müssen vorher funktionieren.
  • Alles, was für SMB gilt, gilt auch hier. SMB-Signierung und SMB-Verschlüsselung kosten CPU-Zeit und bremsen den Durchsatz, und zwar unabhängig davon, ob Du für den SQL Server selbst Verschlüsselung aktiviert hast.

Dass ausgerechnet Port 445 offen sein muss, ist aus Sicherheitssicht kein Detail. 1433 freizugeben öffnet den SQL Server. 445 freizugeben öffnet die gesamte SMB-Oberfläche einer Maschine.

TCP/IP: Der Weg, für den das Netz gebaut wurde

TCP/IP ist der Standardfall für alles, was nicht auf demselben Rechner läuft. Die Standardinstanz lauscht auf Port 1433, benannte Instanzen bekommen in der Regel einen dynamischen Port, der sich beim Neustart ändern kann. Im Verbindungsstring steht tcp:<Servername>,<Port>.

Dass dynamische Ports überhaupt funktionieren, ist die Aufgabe des SQL Server Browser. Der Dienst lauscht auf UDP 1434 und beantwortet die Frage „unter welchem Port erreiche ich die Instanz XY". Interessant dabei: Die Antwort enthält nicht nur den TCP-Port. Das zugrundeliegende SQL Server Resolution Protocol liefert pro Instanz Servername, Instanzname, Clusterstatus, Version und, sofern aktiviert, sowohl tcp als auch np, also auch den Namen der Pipe. Der Browser ist damit die Stelle, an der ein Client überhaupt erst erfährt, welche Protokolle eine benannte Instanz anbietet.

Der eigentliche Knackpunkt: Die Protokollreihenfolge

Jetzt wird es interessant, denn hier sitzt die Ursache der meisten rätselhaften Verbindungsprobleme. Ein Client verbindet sich nämlich nicht einfach mit „dem Protokoll". Er probiert mehrere durch.

Der .NET-Treiber SqlClient, über den die allermeisten modernen Anwendungen gehen, nutzt diese Reihenfolge:

  1. Shared Memory
  2. TCP/IP
  3. Named Pipes

Er arbeitet sie von oben nach unten ab, Fehlschlag für Fehlschlag, bis einer funktioniert. Erkennt er am Servernamen, dass es sich um einen entfernten Rechner handelt, überspringt er Shared Memory. Bei einer benannten Instanz fragt er zusätzlich den Browser, um die Protokollliste des Zielservers zu bekommen.

Und hier liegt die Falle, die in der Praxis am meisten Zeit kostet:

Der Client bekommt keine Fehlermeldung darüber, dass das erste Protokoll gescheitert ist. Der Fallback passiert vollkommen still. Du siehst keinen Fehler, keine Warnung, keinen Eintrag. Du siehst nur, dass es langsam ist.

Genau das war der Fall beim Kunden aus der Einleitung. Auf dem neuen Server war TCP/IP nicht aktiviert. Jede einzelne Verbindung lief erst in einen TCP-Versuch samt Timeout und landete danach auf Named Pipes. Verbindung kam zustande, Anwendung lief, niemand sah einen Fehler. Nur dauerte eben jeder Verbindungsaufbau zwei Sekunden länger als nötig. Nach dem Aktivieren von TCP/IP war die Verzögerung weg. Solche Berichte gibt es reichlich, von zwei Sekunden bis zu sechs Sekunden, die nach der Umstellung auf unter eine Hundertstelsekunde fallen.

Dass dieses Verhalten so selten erkannt wird, liegt an einem zweiten Umstand. Es gibt zwei getrennte Protokollreihenfolgen, und die meisten Leute kennen nur eine davon.

TreiberReihenfolge steht inIm Konfigurations-Manager änderbar
Native Client, ODBC, OLE DBder Registryja
SqlClient (.NET)fest im Treibernein

Beim Native Client steuert der Wert ProtocolOrder die Reihenfolge:

HKLM\Software\Microsoft\MSSQLServer\Client\SuperSocketNetLib

SqlClient liest diesen Wert nicht. Wer also im Konfigurations-Manager die Clientprotokolle umsortiert und sich wundert, dass die .NET-Anwendung unbeeindruckt bleibt, hat am falschen Hebel gedreht. Die Einstellung dort betrifft den Native Client, nicht SqlClient.

Wie Du das Protokoll forcierst

Sobald Du das Protokoll im Verbindungsstring explizit angibst, entfällt das Durchprobieren vollständig. Der Treiber nutzt genau das angegebene und nichts anderes. Das ist der schnellste Weg, eine Verbindung reproduzierbar zu machen:

Data Source=np:SQLSRV01; Integrated Security=SSPI
Data Source=tcp:SQLSRV01,1433; Integrated Security=SSPI
Data Source=lpc:SQLSRV01; Integrated Security=SSPI

In älteren ODBC-Verbindungsstrings begegnen Dir stattdessen die alten Netzwerkbibliotheksnamen. Network=DBMSSOCN steht für TCP/IP, Network=DBNMPNTW für Named Pipes. Die Namen stammen noch aus der Zeit vor der Jahrtausendwende und tauchen in gewachsenen Installationen erstaunlich oft auf.

Warum Named Pipes über das Netz einbrechen

Die pauschale Aussage „Named Pipes sind langsam" ist zu grob. Lokal sind sie schnell. Was sie schlecht macht, ist Latenz, und der Grund dafür liegt in der Art, wie die beiden Mechanismen kommunizieren.

Named Pipes sind gesprächig. Eine Gegenstelle schickt keine Daten, bevor die andere sie nicht per Lesebefehl angefordert hat, und einem Lesevorgang geht typischerweise eine ganze Serie von Peek-Nachrichten voraus, mit denen der Client erst einmal nachsieht, ob überhaupt etwas da ist. Jede dieser Nachrichten ist eine Runde über das Netz. In einem schnellen LAN mit einer Latenz unter einer Millisekunde fällt das nicht auf. Bei 30 Millisekunden über eine VPN-Strecke wird aus jeder Runde ein spürbarer Beitrag, und davon gibt es viele.

TCP hat für genau dieses Problem Vorkehrungen eingebaut. Windowing, verzögerte Bestätigungen und Pufferung sorgen dafür, dass mehrere Datenblöcke unterwegs sein können, ohne dass auf jede einzelne Bestätigung gewartet wird. Named Pipes haben diese Mechanismen nicht. Der Effekt: Named Pipes brauchen für dieselbe Arbeit mehr Pakete, und je höher die Latenz, desto teurer wird jedes einzelne davon.

Dazu kommt ein Unterschied beim Verbindungsaufbau unter Last. TCP kennt eine Backlog-Queue, in der eingehende Verbindungsanfragen zwischengeparkt werden. Named Pipes haben dieses Polster nicht, weshalb bei vielen gleichzeitigen Verbindungsversuchen Pipe-Busy-Fehler auftreten können.

EigenschaftShared MemoryNamed PipesTCP/IP
Reichweitenur lokallokal und Netzwerklokal und Netzwerk
Portkeiner445 (SMB)1433 bzw. dynamisch
Transportgemeinsamer SpeicherbereichSMB über IPC$TCP-Sockets
Verhalten bei Latenznicht relevantbricht deutlich einrobust
Windowing und Pufferungnicht nötigneinja
Konfigurierbarnur an und ausPipename änderbarPorts, IPs, Verschlüsselung
Unter Linux verfügbarneinneinja

Nachsehen, was tatsächlich läuft

Genug Theorie. Die folgende Abfrage beantwortet für die aktuelle Verbindung beide Fragen auf einmal, also welches Protokoll und welche Authentifizierung:

SELECT net_transport, auth_scheme, encrypt_option
FROM   sys.dm_exec_connections
WHERE  session_id = @@SPID;

In net_transport steht Shared memory, Named pipe oder TCP. In auth_scheme steht KERBEROS, NTLM oder SQL. Dieselbe Abfrage ohne die Einschränkung auf @@SPID zeigt Dir das Bild für alle offenen Verbindungen, was deutlich aufschlussreicher ist:

SELECT net_transport, auth_scheme, COUNT(*) AS verbindungen
FROM   sys.dm_exec_connections
GROUP  BY net_transport, auth_scheme
ORDER  BY verbindungen DESC;

Wenn in einer Umgebung, in der eigentlich alles über TCP laufen sollte, plötzlich eine Handvoll Named-Pipe-Verbindungen auftaucht, hast Du einen Client gefunden, bei dem der stille Fallback zuschlägt. Das ist genau der Befund, den Du suchst, und er ist mit einer Abfrage zu haben.

Für den Verbindungsaufbau selbst hilft ein kurzer Vergleich aus PowerShell. Einmal mit erzwungenem TCP, einmal ohne Angabe:

$ziele = @("tcp:SQLSRV01,1433", "SQLSRV01")
foreach ($z in $ziele) {
    $c = New-Object System.Data.SqlClient.SqlConnection
    $c.ConnectionString = "Server=$z;Database=master;Integrated Security=SSPI"
    $sw = [Diagnostics.Stopwatch]::StartNew()
    $c.Open()
    $sw.Stop()
    "{0,-22} {1,7:N0} ms" -f $z, $sw.Elapsed.TotalMilliseconds
    $c.Close()
}

Klafft zwischen beiden Zeilen eine Lücke von mehreren hundert Millisekunden oder mehr, probiert der Treiber etwas durch, das er nicht sollte.

Was wann sinnvoll ist

Die Entscheidung ist in der Praxis weniger kompliziert, als die Menge an Material zum Thema vermuten lässt.

Anwendung und SQL Server auf derselben Maschine

Shared Memory, ohne Diskussion. Es ist der direkteste Weg und der mit Abstand schnellste. Reine IPC-Vergleiche sehen Shared Memory je nach Messaufbau um ein Vielfaches vor Named Pipes. Die absoluten Zahlen taugen nicht für eine Kapazitätsplanung, die Größenordnung stimmt aber: Wo es um Mikrosekunden geht, kostet jede zusätzliche Schicht.

In der Realität ist diese Konstellation allerdings seltener, als man denkt. Dass die Anwendung auf dem Datenbankserver läuft, ist bei einem ERP eher die Ausnahme.

Client und Server im selben LAN

TCP/IP. Im schnellen LAN sind Named Pipes und TCP in der Praxis vergleichbar, aber TCP bringt die besseren Eigenschaften mit, sobald es ungemütlich wird: robuster bei Latenzschwankungen, Backlog-Queue beim Verbindungsaufbau, klar umrissene Firewallregel auf einem einzigen Port, nachvollziehbare Diagnose. Named Pipes gewinnen hier nichts, was den zusätzlichen SMB-Unterbau rechtfertigen würde.

Verbindung über WAN, VPN oder Standortkopplung

TCP/IP, und zwar ohne Alternative. Das ist der Fall, in dem Named Pipes nicht nur etwas langsamer sind, sondern den Unterschied zwischen „läuft" und „läuft nicht" ausmachen. Die vielen kleinen Runden multiplizieren sich mit der Latenz, und bei schlechter Strecke kommen Timeouts dazu. Wenn Du über VPN arbeitest, gehört Named Pipes auf dem Server abgeschaltet, damit niemand versehentlich dort landet.

Bleibt die Frage, wann Named Pipes gewinnen

Ehrlich gesagt: in einer neu gebauten Umgebung praktisch nie. Die Fälle, in denen Named Pipes die richtige Wahl sind, sind fast immer Altlasten. Eine Anwendung, deren Verbindungsstring sich nicht ändern lässt. Ein Dienst, der fest auf einen Pipenamen konfiguriert ist. Eine Umgebung, in der 1433 aus Richtlinien-Gründen zu ist, 445 aber offen. Das sind legitime Gründe, eine bestehende Konfiguration nicht anzufassen. Es sind keine Gründe, eine neue so zu bauen.

Für Neuinstallationen gilt ohnehin: Weniger aktivierte Protokolle bedeuten weniger Angriffsfläche. Beide gleichzeitig zu betreiben ist in den seltensten Fällen nötig.

Die Standardeinstellungen, die Dich erwischen

Ein praktischer Hinweis zum Schluss, der viel Sucherei spart. Bei einer Neuinstallation sind die Protokolle nicht in allen Editionen gleich eingestellt.

EditionShared MemoryTCP/IPNamed Pipes
Express, Developeraktivdeaktiviertdeaktiviert
Standard, Enterprise, Evaluation, Workgroupaktivaktivdeaktiviert

Ein Entwicklungsrechner mit Developer Edition spricht also zunächst ausschließlich über Shared Memory. Lokal fällt das nie auf. Sobald der erste Kollege oder der erste Dienst von außen zugreifen will, geht nichts, und der Fehler sieht nach allem Möglichen aus, nur nicht nach einem fehlenden Protokoll. Bei einem Upgrade über eine bestehende Installation hinweg bleiben die vorhandenen Einstellungen übrigens erhalten, was erklärt, warum zwei scheinbar identische Server unterschiedlich konfiguriert sein können.

Noch ein Detail für alle, die mit Aliassen arbeiten: Ab SQL Server 2022 legt der Konfigurations-Manager keine Aliase mehr an. Vorhandene funktionieren weiter, für neue brauchst Du das alte Client Network Utility oder einen direkten Registry-Eintrag.

Einordnung für die Sage 100

Für Sage-100-Umgebungen sind zwei Dinge wichtig, die gern durcheinandergehen.

Erstens: Der Sage-100-Mehrbenutzerdienst nutzt selbst eine Named Pipe, nämlich \\.\pipe\SageMultiUserService. Das hat mit der Protokollwahl zum SQL Server nichts zu tun. Es ist eine eigene lokale Pipe zwischen Sage-Komponenten, und sie bleibt eine Pipe, egal wie der Applikationsserver mit der Datenbank spricht. Wenn Du in einer Fehlersuche über Named Pipes stolperst, kläre also zuerst, über welche der beiden Du gerade redest. Welche Rolle diese Pipe beim Start spielt, steht im Beitrag zum geänderten Servernamen.

Zweitens: Die Verbindung vom Applikationsserver zum SQL Server sollte über TCP laufen, und zwar überprüfbar, nicht vermutet. In der Praxis sehen wir regelmäßig Umgebungen, in denen nach einem Serverumzug TCP schlicht nicht aktiviert wurde und alles still über Named Pipes läuft. Es funktioniert, es ist nur langsamer als nötig. Unser Performance-Script prüft das zusammen mit Latenz, Paketgröße und der Frage, ob die Anmeldung auf Kerberos oder NTLM landet.

Merksatz für die Fehlersuche: Wenn Verbindungen langsam aufgehen, die Abfragen danach aber schnell laufen, liegt das Problem fast nie im SQL Server. Dann geht es um Protokollwahl, Namensauflösung oder Authentifizierung, also um alles, was vor dem ersten TDS-Paket passiert.

Fazit

Shared Memory lokal, TCP/IP für alles andere. Named Pipes sind kein schlechtes Protokoll, sie sind nur für eine Welt gebaut, in der Latenz keine Rolle spielt, und in dieser Welt arbeitet heute kaum jemand.

Das eigentlich Wertvolle an diesem Thema ist nicht die Protokollwahl selbst, sondern das Wissen um den stillen Fallback. Ein Treiber, der Protokolle durchprobiert und Fehlschläge für sich behält, produziert Symptome, die nach allem Möglichen aussehen. Zwei Abfragen auf sys.dm_exec_connections klären in einer Minute, was tatsächlich passiert.

Verbindungsprobleme, die niemand erklären kann?

Wenn bei Dir Anmeldungen zäh sind, Verbindungen sporadisch in Timeouts laufen oder nach einem Serverumzug plötzlich alles etwas langsamer ist, schauen wir uns das an. Wir messen die Strecke vom Client bis zur Datenbank, prüfen Protokoll, Namensauflösung und Authentifizierung und sagen Dir, wo die Zeit tatsächlich verloren geht. Auch bei allen anderen SQL-Server-Themen rund um die Sage 100 sind wir gern Dein Ansprechpartner.

Verbindungsanalyse anfragen
Beitrag teilen
LinkedIn WhatsApp E-Mail

Wie hilfreich war dieser Beitrag?

Noch keine Bewertungen.