VERTRIEB: 1-800-867-1380

Bewährte Vorgehensweisen für den Entwurf umfangreicher Dienste auf Azure Cloud Services

Letzte Aktualisierung: Januar 2014

Autoren: Mark Simms und Michael Thomassy

Beitragende Autoren: Jason Roth und Ralph Squillace

Bearbeiter: Brad Calder, Dennis Mulder, Mark Ozur, Nina Sarawgi, Marc Mercuri, Conor Cunningham, Peter Carlin, Stuart Ozer, Lara Rubbelke und Nicholas Dritsas.

Cloudcomputing ist verteiltes Rechnen; das Verteilen der Rechenleistung erfordert durchdachte Planung und Bereitstellung - unabhängig von der Plattformauswahl. Der Zweck dieses Dokuments ist es, durchdachte Richtlinien basierend auf echten Kundenszenarios zum Erstellen von skalierbaren Anwendungen auf Azure- und SQL-Datenbanken bereitzustellen und den PaaS-Ansatz (Platform as a Service, Plattform als Dienst) zu nutzen (solche Anwendungen werden als Azure Cloud Services mithilfe von Web- und Workerrollen erstellt).

ImportantWichtig
HINWEIS: Alle bewährten Vorgehensweisen in diesem Papier stammen aus der engen Zusammenarbeit mit Kunden, die Produktionscode auf Azure ausführen. Dieses Whitepaper behandelt die Azure Cloud Services (PaaS)-Plattform auf Grundlage der SDK-Version 1.6; Funktionen wie Azure-Websites oder virtuelle Azure-Computer (IaaS) werden nicht erläutert.

Dieses Dokument enthält die zugrunde liegenden Entwurfskonzepte zum Erstellen von Azure-Anwendungen, wichtige Azure-Plattformfunktionen, -Grenzen und -Features sowie bewährte Methoden zum Arbeiten mit den Azure-Kerndiensten. Der Fokus liegt auf den Anwendungen, die für einen mehr oder weniger konsistenten verteilten einem Datenspeicher infrage kommen (im Gegensatz zu ausschließlich konsistenten oder mehrinstanzenfähigen Datenmodellen mit hoher Dichte).

Das Verändern der Aspekte Ihrer Anwendungen und Dienste in Azure kann aus vielen Gründe lohnenswert sein, zum Beispiel:

  • Konservieren oder Konsolidieren von Kapitalausgaben in Betriebsausgaben (capex in opex).

  • Reduzieren von Kosten (und Verbessern der Effizienz) durch genaueres Abstimmen von Bedarf und Kapazität.

  • Verbessern der Flexibilität und der Markteinführungszeit durch Reduzieren oder Entfernen von Infrastrukturbarrieren.

  • Ausweiten der Zielgruppenreichweite auf neue Märkte, wie mobile Geräte.

  • Profitieren aus dem enormen Umfang des Cloudcomputings durch die Erstellung neuer Anwendungen, die eine globale Zielgruppe in weltweit verteilten Rechenzentren unterstützen.

Es gibt viele gute technischen Gründe, um neue Anwendungen zu entwickeln oder einige bzw. alle vorhandenen Anwendungen nach Azure zu portieren. Da die Umgebung über viele Implementierungsalternativen verfügt, muss Ihr spezielles Anwendungsmuster sorgfältig analysiert werden, um den richtigen Implementierungsansatz auszuwählen. Einige Anwendungen sind gut für Azure Cloud Services (ein PaaS-Ansatz, Platform-as-a-Service) geeignet, während andere möglicherweise von einem teilweisen oder vollständigen IaaS-Ansatz (Infrastructure-as-a-Service, Infrastruktur als Dienst) profitieren, wie virtuelle Azure-Computer. Abschließend würden bestimmte Anwendungsanforderungen möglicherweise am besten erfüllt, indem beide zusammen verwendet werden.

Die Anwendung sollte eine oder mehrere der folgenden drei Hauptaspekte haben, um die Vorteile von Azure Cloud Services zu maximieren. (Nicht alle müssen in der Anwendung vorhanden sein; eine Anwendung kann auch eine hohe Rendite erzeugen, indem sie Azure mit nur einem der folgenden Aspekte sehr gut verwendet. Eine Arbeitsauslastung, die keine dieser Eigenschaften aufweist, wird aber wahrscheinlich nicht optimal zu Azure Cloud Services passen.)

Die wichtigen Punkte, anhand derer eine Anwendung bewertet werden sollte:

  • Elastischer Bedarf. Einer der zentralen Wertvorschläge der Umstellung auf Azure ist das elastische Skalieren: die Möglichkeit, Kapazität zur Anwendung hinzuzufügen oder daraus zu entfernen, um der dynamischen Benutzernachfrage besser entsprechen zu können. Wenn die Arbeitsauslastung einen statischen, stabilen Bedarf aufweist (zum Beispiel eine statische Anzahl von Benutzern, Transaktionen usw.), wird dieser Vorteil von Azure Cloud Services nicht maximiert.

  • Verteilte Benutzer und Geräte. Das Ausführen unter Azure bietet sofortigen Zugriff auf die globale Bereitstellung von Anwendungen. Wenn Ihre Arbeitsauslastung eine eigene Benutzerbasis an einem einzigen Speicherort aufweist (beispielsweise eine einzelne Niederlassung), stellt die Cloudbereitstellung möglicherweise keine optimale Rendite bereit.

  • Partitionierbare Arbeitsauslastung. Cloudanwendungen skalieren durch das horizontale Skalieren – und fügen damit mehr Kapazität in kleineren Segmenten hinzu. Wenn die Anwendung von der horizontalen Skalierung abhängt (beispielsweise große Datenbanken und Data Warehouses), oder wenn es sich um eine spezialisierte, dedizierte Arbeitsauslastung handelt (beispielsweise ein großer, einheitlicher Hochgeschwindigkeitsspeicher), muss sie zerlegt werden (partitioniert), um auf Diensten für horizontales Skalieren ausgeführt werden zu können und in der Wolke durchführbar zu sein. Abhängig von der Arbeitsauslastung kann dies ein kompliziertes Verfahren sein.

Wie bereits erwähnt wurde, Wenn Sie Ihre Anwendung analysieren, können Sie auch dann eine hohe Rendite aus der Investition der Umstellung oder des Aufbaus auf Azure Cloud Services erzielen, wenn die Arbeitsauslastung nur eine der vorhergehenden drei Aspekte enthält, die in einer PaaS-Umgebung wie Azure Cloud Services verwendet werden. Anwendungen, die alle drei Eigenschaften haben, generieren wahrscheinlich eine hohe Rendite.

Während viele Aspekte des Entwerfen von Anwendungen für Azure aus der lokalen Entwicklung sehr vertraut sind, gibt es auch einige wichtige Unterschiede in Bezug darauf, wie sich die zugrunde liegende Plattform und die Dienste verhalten. Das Verstehen dieser Unterschiede und das daraus resultierende Entwickeln für die Plattform – nicht dagegen – sind wichtig für das Bereitstellen von Anwendungen, die das elastische Skalieren in der Cloud versprechen.

In diesem Abschnitt werden fünf Schlüsselkonzepte, die die wichtigen Entwurfspunkte der Erstellung weit verteilter Anwendungen für horizontales Skalieren für PaaS-Umgebungen darstellen, wie Azure Cloud Services, erläutert. Das Verständnis dieser Konzepte hilft Ihnen dabei, Anwendungen zu entwerfen und zu erstellen, die nicht nur mit Azure Cloud Services arbeiten, sondern dort reifen und möglichst hohe Rendite aus der Investition generieren. Alle Überlegungen zum Entwurf und zu den Auswahlmöglichkeiten, die weiter unten in diesem Dokument behandelt werden, gehen auf diese fünf Konzepte zurück.

Darüber hinaus sollte bemerkt werden, dass viele dieser Überlegungen und bewährten Methoden zwar aus Sicht einer .NET-Anwendung gesehen werden, die zugrunde liegenden Konzepte und Ansätze aber weitestgehend unabhängig von Sprache und Plattform sind.

Der erste Schritt bei der Umstellung von einer lokalen Anwendung auf Azure Cloud Services hat mit der Anwendungsskalierung zu tun. Die herkömmliche Methode zum Erstellen von größeren Anwendungen basiert auf einer Kombination aus horizontalem Skalieren (statusfreie Web- und Anwendungsserver) und zentralem Skalieren (Kaufen eines größeren Mehrkern. bzw. großen Arbeitsspeichersystem, Datenbankserver, Erstellen eines größeren Rechenzentrums usw.). In der Cloud ist das zentrale Skalieren keine realistische Option; der einzige Weg zu wirklich skalierbaren Anwendungen liegt im expliziten Entwurf für horizontales Skalieren.

Da viele Elemente einer lokalen Anwendung bereits für horizontales Skalieren (Webserver, Anwendungsserver) geeignet sind, liegt die Herausforderung im Identifizieren der Aspekte der Anwendung, die von einem zentralen Skalierungsdienst abhängen, und im Konvertieren (oder Zuordnen) zu einer Implementierung für horizontales Skalieren. Der primäre Kandidat für eine Abhängigkeit von der zentralen Skalierung ist in der Regel die relationale Datenbank (SQL Server-/Azure SQL-Datenbank).

Herkömmliche relationale Entwürfe konzentrieren sich auf ein global zusammenhängendes Datenmodell (zentrale Einzelserverskalierung) mit starker Konsistenz und starkem Transaktionsverhalten. Der herkömmliche Ansatz zur Bereitstellung der Skalierung für diesen Sicherungsspeicher besteht darin, "alles zustandslos zu machen". Dadurch wird die Verantwortung der Verwaltung von Zuständen an den SQL-Server für zentrale Skalierung zurückgegeben.

Die hohe Skalierbarkeit von SQL Server bringt aber einen eindeutigen Mangel an tatsächlich elastischer Skalierung mit sich. Das heißt, anstelle von Ressourcen mit äußerst hoher Verfügbarkeit müssen Sie einen größeren Server mit einer teuren Migrationsphase kaufen, bei dem die Kapazität den Bedarf deutlich übersteigt – und das jedes Mal, wenn Sie die zentrale Skalierung erweitern. Ferner besteht eine exponenzielle Kostenkurve, wenn die Skalierung Mittelklassehardware übersteigt.

Mit der Architekturuntermauerung von Azure Cloud Services durch das horizontale Skalieren müssen Anwendungen entworfen werden, um mit Datenspeichern für horizontales Skalieren zu arbeiten. Dies bedeutet Entwurfsherausforderungen, wie das explizite Partitionieren von Daten in kleinere Segmente (von denen jedes in eine Datenpartition oder in eine Einheit für horizontales Skalieren passt) und das Verwalten der Konsistenz zwischen verteilten Datenelementen. Dies sorgt für Skalierung durch Partitionierung auf eine Art und Weise, die viele Nachteile des Entwurfs für zentrales Skalieren vermeidet.

Das Pivotieren von bekannten Techniken zur zentralen Skalierung hin zur Daten- und Zustandsverwaltung für horizontales Skalieren ist in der Regel eine der größten Hürden beim Entwerfen für die Cloud; Das Bewältigen dieser Herausforderungen und das Entwerfen von Anwendungen, die die skalierbaren, elastischen Funktionen von Azure Cloud Services- und Azure SQL-Datenbanken zum Verwalten von dauerhaften Daten nutzen können, ist über weite Strecken das Hauptaugenmerk dieses Dokuments.

In einer Umgebung, in der Sie ein eigenes Rechenzentrum ausführen, haben Sie fast unbegrenzte Kontrollmöglichkeiten, denen eine praktisch unendliche Anzahl von Optionen gegenübersteht. Alles von der physischen Anlage (Klimaanlage, Stromversorgung, Bodenfläche) über die Infrastruktur (Racks, Server, Speicher, Netzwerke usw.) bis zur Konfiguration (Routingtopologie, Betriebssysteminstallation) ist unter Ihrer Kontrolle.

Diesen Grad der Kontrolle gibt es nicht umsonst – Kapital, Betrieb, Mitarbeiter und Zeit verursachen Kosten. Die Kosten der Verwaltung aller Details in einer flexiblen und veränderbaren Umgebung sind der Kern des Strebens nach Virtualisierung und ein Hauptaspekt der Umstellung auf die Cloud. Im Gegenzug für einen Teil der Kontrolle reduzieren diese Plattformen die Kosten der Bereitstellung und Verwaltung und erhöhen die Flexibilität. Die Einschränkung, die sie mit sich bringen, ist, dass die Größe (Kapazität, Durchsatz usw.) der verfügbaren Komponenten und Dienste auf einen festen Satz von Angeboten beschränkt ist.

Um eine Analogie zu verwenden: Der Handelsmassenversand basiert hauptsächlich auf Versandcontainer. Diese Container werden durch verschiedene Transportmittel (Schiffe, Züge, LKWs) getragen und sind in verschiedenen Standardgrößen (bis zu 53 Fuß Länge) verfügbar. Wenn die Frachtmenge, die Sie versenden möchten, die Kapazität des größten Anhängers übersteigt, haben Sie folgende Möglichkeiten:

  • Verwenden mehrerer Anhänger. Dies umfasst das Aufteilen (oder Partitionieren) der Fracht auf mehrere Container, und das Koordinieren der Lieferung der Anhänger.

  • Verwenden einer speziellen Liefermethode. Für Fracht, die nicht in Standardcontainern befördert werden kann (zu groß, zu sperrig usw.), müssen sehr spezielle Methoden verwendet werden, wie z. B. Lastkähne. Diese Methoden sind in der Regel viel teurer als der Standardfrachtversand.

Wenn wir diese Analogie zurück zu Azure (und Cloudcomputing im Allgemeinen) bringen, verfügt jede Ressource über eine Grenze. Sei es eine einzelne Rolleninstanz, ein Speicherkonto, ein Cloud-Dienst oder sogar ein Rechenzentrum – jede verfügbare Ressource in Azure hat eine feste Grenze. Dabei kann es sich um sehr große Grenzen handeln, wie die Menge des Arbeitsspeichers in einem Rechenzentrum (analog: Auch die größten Frachtschiffe können mehr als 10.000 Container befördern), es sind jedoch Grenzen.

In diesem Sinn ist der Ansatz für die Skalierung folgender: Partitionieren Sie die Last, und erstellen Sie sie über mehrere Skalierungseinheiten hinweg – dabei kann es sich um mehrere virtuelle Computer (Virtual Machines, VMs), Datenbanken, Speicherkonten, Cloud-Dienste oder Rechenzentren handeln.

In diesem Dokument verwenden wir den Begriff Skalierungseinheit, um auf eine Gruppe mit Ressourcen zu verweisen, die (A) einen definierten Grad an Last verarbeiten kann und (b) kombiniert werden kann, um zusätzliche Last zu verarbeiten. Beispielsweise weist ein Azure-Speicherkonto eine Maximalgröße von 100 TB auf. Wenn Sie mehr als 100 TB Daten speichern müssen, müssen Sie mehrere Speicherkonten verwenden (d. h. mindestens zwei Skalierungseinheiten aus dem Speicher).

Die allgemeinen Entwurfsrichtlinien für die Kapazität jedes Kerndiensts oder jeder Komponente von Azure werden in späteren Abschnitten zusammen mit empfohlenen Vorgehensweisen für das Erstellen dieser Dienste für zusätzliche Skalierung näher erläutert.

Große Mengen an Zeit, Energie und intellektuellem Kapital wurden in die Erstellung hochstabiler lokaler Anwendungen investiert. Das führt normalerweise dazu, dass die Anwendung in Komponenten mit niedrigem Status (Anwendungsserver, Netzwerk) und Komponenten mit hohem Status (Datenbanken, SANs) aufgeteilt werden, wobei jede Komponente mehr Stabilität gegen Fehler bietet.

In diesem Zusammenhang bezeichnet ein Fehler oder Fehlermodus eine Kombination aus (a) dem Überwachen des Systems in einem Fehlerzustand und (b) dem Ergebnis der Fehlerursache. Beispielsweise ist eine Datenbank, auf die aufgrund eines falsch konfigurierten Kennwortupdates nicht zugegriffen werden kann, ein Fehlermodus; der Fehlerzustand ist die Unmöglichkeit der Verbindung (Verbindung abgelehnt, Anmeldeinformationen nicht akzeptiert), und die Fehlerursache ist ein Kennwortupdate, das nicht ordnungsgemäß an den Anwendungscode übertragen wurde.

Komponenten mit niedrigem Status bieten Stabilität durch eine lose gekoppelte Redundanz, wobei ihre "Integration" in das System von externen Systemen verwaltet wird. Beispiel: Zusätzliche Webserver werden hinter einem Lastenausgleich platziert; die Webserver sind alle identisch (so wird das Hinzufügen neuer Kapazitäten zu einer Angelegenheit des Klonens eines grundlegenden Webserverabbilds), wobei die Integration in die Gesamtanwendung vom Lastenausgleich verwaltet wird.

Komponenten mit hohem Status bieten Stabilität durch fest gekoppelte Redundanz, wobei die "Integration" eng zwischen Komponenten verwaltet wird. Beispiele:

  • SQL Server. Damit eine redundante SQL Server-Instanz als Teil eines aktiven/passiven Clusters hinzugefügt wird, ist eine sorgfältige Auswahl der kompatiblen (das heißt identischen) Hardware und des gemeinsam genutzten Speichers (z. B. ein SAN) erforderlich, um Transaktions-konsistenten Failover zwischen mehreren Knoten bereitzustellen.

  • Stromversorgung. Das Bereitstellen einer redundanten Stromversorgung stellt ein sehr hoch entwickeltes Beispiel dar und erfordert, dass mehrere Systeme gemeinsam agieren, um lokale (mehrere Stromversorgungen für einen Server, wobei die Onboard-Hardware zwischen primärer und sekundärer Stromversorgung wechselt) und zentrale Probleme (Backup-Generatoren für Stromausfälle) zu minimieren.

Stabilitätslösungen, die auf fest verkoppelten Ansätzen basieren, sind grundsätzlich teurer als lose verbundene Ansätze zum "Hinzufügen von weiterem geklonten Material", da hochgradig trainierte Mitarbeiter, spezielle Hardware und vorsichtige Konfiguration und Tests benötigt werden. Es ist nicht nur schwer durchzuführen, sondern auch noch kostenintensiv.

Dieser Ansatz des Sicherstellens, dass die Hardwareplattformen sehr stabil sind, können Sie sich als "Titaneierschale" vorstellen. Um den Inhalt des Eies zu schützen, beschichten wir die Hülle mit stabilem (und teurem) Titan.

Die Erfahrung des Ausführens von großen Systemen (weitere Informationen finden Sie unter http://www.mvdirona.com/jrh/TalksAndPapers/JamesRH_Lisa.pdf), hat gezeigt, dass in jedem System mit ausreichender Größer (z. B. Datensysteme mit der Größe von Azure) die bloße Anzahl physischer beweglicher Teile dazu führt, dass einige Systemteile immer defekt sind. Die Azure-Plattform ist so entwickelt wurden, dass sie mit dieser Einschränkung anstatt dagegen arbeitet und sich auf die automatisierte Wiederherstellung von Fehlerereignissen auf Knotenebene verlässt. Diese Entwurfsabsicht findet sich in allen Azure-Kerndiensten und ist beim Entwerfen einer Anwendung, die mit dem Azure-Verfügbarkeitsmodell arbeitet, von zentraler Bedeutung.

Der Umstieg auf Azure ändert die Stabilitätsdiskussion von einer Infrastrukturredundanzherausforderung zu einer Diensteredundanzherausforderung. Viele der Kerndienste, die die lokale Verfügbarkeitsplanung dominieren, arbeiten in Azure "einfach weiter":

  • Die SQL-Datenbank verwaltet automatisch mehrere im Hinblick auf Transaktionen konsistente Replikate Ihrer Daten. Fehler auf Knotenebene für eine Datenbank werden automatisch zu einem Failover für die konsistente sekundäre Datenbank; vergleichen Sie die Benutzerfreundlichkeit dieser Erfahrung mit der Zeit und den Ausgaben zum Bereitstellen der lokalen Stabilität.

  • Der Azure-Speicher verwaltet automatisch mehrere konsistente Kopien der Daten (weitere Informationen finden Sie unter http://sigops.org/sosp/sosp11/current/2011-Cascais/11-calder-online.pdf). Fehler auf Knotenebene für ein Speichervolume werden automatisch zu einem Failover für eine konsistente sekundäre Datenbank. Vergleichen Sie diese vollständig verwaltete Erfahrung wie bei der SQL-Datenbank mit der direkten Verwaltung des stabilen Speichers in einem lokalen Cluster oder SAN.

Der Titel dieses Abschnitts ist jedoch Verfügbarkeit, nicht Stabilität. Stabilität ist nur ein Teil des gesamten Aspekts der kontinuierlichen Bereitstellung für Benutzer innerhalb der Grenzen einer SLA. Wenn alle Infrastrukturkomponenten eines Diensts fehlerfrei sind, der Dienst aber nicht mit der erwarteten Menge von Benutzern ausgeführt werden kann, ist er nicht verfügbar und damit nutzlos.

Mobil oder sozial orientierte Arbeitsauslastungen (wie öffentliche Webanwendungen mit Anwendungen für mobile Geräte) tendieren dazu, wesentlich dynamischer als die zu sein, die auf ein unfreiwilliges Publikum abzielen. Außerdem erfordern sie einen höher entwickelten Ansatz für die Verarbeitung von Burstereignissen und Spitzenlasten. Die zum Entwerfen der Verfügbarkeit in Azure-Anwendungen zu berücksichtigenden Schlüsselkonzepte werden detailliert basierend auf diesen Punkten in diesem Dokument behandelt:

  • Jeder Dienst oder jede Komponente in Azure stellt eine bestimmte Vereinbarung zum Servicelevel (SLA) bereit; diese SLA wird nicht direkt mit der Verfügbarkeitsmetrik in Zusammenhang gebracht, die zum Ausführen Ihrer Anwendung erforderlich ist. Das Verstehen aller Komponenten in Ihrem System, der Verfügbarkeits-SLA und der Interaktion untereinander, ist wichtig, wenn Sie die allgemeine Verfügbarkeit verstehen möchten, die den Benutzern bereitgestellt werden kann.

    • Vermeiden Sie einzelne Fehlerpunkte, die die SLA beeinträchtigen, wie zum Beispiel Einzelinstanzrollen.

    • Erstellen Sie mehrere Komponenten oder greifen Sie auf diese zurück, um die Auswirkungen eines bestimmten Dienstes, der offline oder nicht verfügbar ist, zu minimieren.

  • Jeder Dienst oder jede Komponente in Azure kann ausfallen, entweder kurzfristig oder langfristig. Ihre Anwendung sollte so geschrieben werden, dass sie Ausfälle problemlos verarbeitet.

    • Für vorübergehende Fehler stellen Sie entsprechende Wiederholungsmechanismen bereit, um Vorgänge wieder zu verbinden oder erneut zu senden.

    • Für andere Fehlerereignisse stellen Sie umfangreiche Instrumentation für das Fehlerereignis (der Fehler wird gemeldet) und eine geeignete Fehlermeldung für den Benutzer bereit.

    • Greifen Sie nach Möglichkeit auf einen anderen Dienst oder Workflow zurück. Wenn beispielsweise eine Anforderung, Daten in SQL-Datenbank einzufügen, fehlschlägt (aus einem beliebigen vorübergehenden Grund, wie z. B. ein ungültiges Schema), schreiben Sie die Daten in den BLOB-Speicher in einem serialisierten Format. So könnten die Daten dauerhaft aufgezeichnet und an die Datenbank gesendet werden, nachdem das Schemaproblem gelöst wurde.

  • Alle Dienste verfügen über eine Höchstkapazität, entweder explizit (durch eine Einschränkungsrichtlinie oder Spitzenlast-Asymptote) oder implizit (durch Erreichen einer Systemressourcengrenze).

    • Entwerfen Sie die Anwendung so, dass sie beim Erreichen von Ressourcengrenzen kontrolliert beeinträchtigt wird und dass entsprechende Schritte ausgeführt werden, um die Auswirkungen für den Benutzer zu verringern.

    • Implementieren Sie eine entsprechende Backoff-/Wiederholungslogik, um einen "Konvoi"-Effekt auf Dienste zu vermeiden. Ohne entsprechenden Backoffmechanismus haben nachfolgende Dienste nach einem Spitzenereignis nie die Möglichkeit, Anschluss zu finden (da Ihre Anwendung ständig versuchen wird, mehr Last auf den Dienst zu übertragen und die Einschränkungsrichtlinie oder Ressourcenverknappung ausgelöst wird).

  • Dienste, die schnelle Burstereignisse erfahren können, müssen das Überschreiten ihrer Höchstentwurfslast kontrolliert verarbeiten, in der Regel durch Entlastungsfunktionen.

    • Ähnlich wie der menschliche Körper die Durchblutung in den Extremitäten bei großer Kälte einschränkt, entwerfen Sie Ihre Dienste so, dass bei Ereignissen mit extremer Auslastung weniger wichtige Dienste deaktiviert werden.

    • Die Folge ist hier, dass nicht alle Dienste, die von der Anwendung bereitgestellt werden, entsprechend geschäftskritisch sind und zu verschiedenen SLAs gehören können.

Diese Konzepte auf hoher Ebene werden ausführlicher in den Abschnitten angewendet, die die Azure-Kerndienste und die Verfügbarkeitsziele für die einzelnen Dienste oder Komponenten zusammen mit den Empfehlungen zum Entwurf der Verfügbarkeit beschreiben. Beachten Sie, dass das Rechenzentrum noch ein Einzelfehlerpunkt für große Anwendungen ist; von Stromversorgungen (Beispiel hier) bis zum Systemfehler (Beispiel hier) haben Infrastruktur- und Anwendungsprobleme dazu geführt, dass Rechenzentren ausgefallen sind. Anwendungen, die die längsten Betriebszeiten benötigen, sind zwar relativ selten, sollten aber in mehreren redundanten Rechenzentren bereitgestellt werden.

Das Bereitstellen von Anwendungen in mehreren Rechenzentren erfordert einige Infrastruktur- und Anwendungsfunktionen:

  • Anwendungslogik, um Benutzer der Dienste an das entsprechende Rechenzentrum weiterzuleiten (basierend auf Geografie, Benutzerpartitionierung oder einer anderen Affinitätslogik).

  • Synchronisierung und Replikation von Anwendungsstatus zwischen Rechenzentren mit entsprechenden Latenz- und Konsistenzebenen.

  • Autonome Bereitstellung von Anwendungen, sodass Abhängigkeiten zwischen Rechenzentren minimiert werden (das heißt, die Situation zu vermeiden, in der ein Fehler in Rechenzentrum A einen Fehler in Rechenzentrum B auslöst).

Wie bei der Verfügbarkeit hat das Bereitstellen von Notfallwiederherstellungslösungen (im Falle eines Rechenzentrumausfalls) viel Zeit, Energie und Kapital erfordert. Dieser Abschnitt konzentriert sich auf Ansätze und Überlegungen zum Bereitstellen von Geschäftskontinuität im Falle von Systemfehlern und Datenverlusten (vom System oder Benutzer ausgelöst), da der Begriff "Wiederherstellung im Notfall" in der Datenbankcommunity bestimmte Konnotationen bezüglich Implementierungsansätze angenommen hat.

Bei der Bereitstellung von Geschäftskontinuität geht es um Folgendes:

  • Beibehalten des Zugriffs auf und der Verfügbarkeit von wichtigen Geschäftssystemen (Anwendungen, die im permanenten Status arbeiten) im Falle eines schwerwiegenden Infrastrukturfehlers.

  • Beibehalten des Zugriffs auf und der Verfügbarkeit von wichtigen Geschäftsdaten (permanenter Status) im Falle eines schwerwiegenden Infrastrukturfehlers.

  • Beibehalten der Verfügbarkeit von wichtigen Geschäftsdaten (permanenter Status) im Falle eines Bedienungsfehlers oder eines versehentlichen Löschens, Änderns oder Beschädigens.

Die ersten beiden Elemente wurden traditionell im Kontext der geografischen Notfallwiederherstellung (geo-DR) behandelt. Das dritte Element besteht aus der Datensicherung und Datenwiederherstellung.

Azure ändert die Gleichung bezüglich der Verfügbarkeit wichtiger Geschäftssysteme deutlich und ermöglicht eine schnelle, geografisch verteilte Bereitstellung von Schlüsselanwendungen in Rechenzentren in aller Welt. Tatsächlich ist der Vorgang der Bereitstellung einer geografisch verteilten Anwendung etwas anders als die Bereitstellung eines einzelnen Cloud-Dienstes.

Die zentrale Herausforderung bleibt das Verwalten des Zugriffs auf den permanenten Status; der Zugriff auf Dienste mit permanentem Status (wie Azure-Speicher und SQL-Datenbank) über Rechenzentren hinweg erzeugt in der Regel keine optimalen Ergebnisse aufgrund der hohen und/oder variablen Latenz und erfüllt nicht die Geschäftskontinuitätsanforderung im Falle eines Rechenzentrumsausfalls.

Wie bei der Stabilität stellen viele Azure-Dienste die automatische Geo-Replikation bereit (oder haben sie in ihrer Übersicht). Beispielsweise werden alle Schreibvorgänge im Azure-Speicher (BLOB, Warteschlange oder Tabelle) automatisch zu einem anderen Rechenzentrum repliziert (jedes Rechenzentrum hat ein bestimmtes "Spiegel"-Ziel innerhalb der gleichen geografischen Region), falls nicht anderweitig konfiguriert. Dies reduziert die Zeit und den Aufwand, die erforderlich sind, um herkömmliche Notfallwiederherstellungslösungen auf Azure bereitzustellen, beträchtlich. Eine Übersicht über die Geo-Replikationsfunktionen der Azure-Kerndienste, die permanenten Status verwalten, wird in späteren Abschnitten bereitgestellt.

Für die Beibehaltung der Geschäftskontinuität bei einem Benutzer- oder Bedienungsfehler gibt es mehrere zusätzliche Überlegungen, die in Ihrem Datenbankentwurf berücksichtigt werden müssen. Während Azure-Speicher begrenzte Überwachungsfunktionen durch die Speicheranalysefunktion (in einem späteren Abschnitt beschrieben) bereitstellt, stellt er keine Zeitpunktwiederherstellungsfunktionen bereit. Dienste, die Stabilität beim versehentlichen Löschen oder Ändern benötigen, müssen anwendungsorientierte Ansätze einsetzen, zum Beispiel das regelmäßige Kopieren von BLOBs auf ein anderes Speicherkonto.

SQL-Datenbank stellt grundlegende Funktionen zum Beibehalten historischer Momentaufnahmen von Daten bereit, einschließlich DB-Kopie und Import/Export über Bacpac. Diese Optionen werden im Detail weiter unten in diesem Dokument erläutert.

Mit der elastischen Skalierung, die von der Azure-Plattform bereitgestellt wird, kann die Angebotskurve der Nachfragekurve weitestgehend entsprechen (anstatt eine große Menge zusätzlicher Kapazität für Spitzenlasten zu haben).

Bei der elastischen Skalierung werden die Warenkosten folgendermaßen gesteuert:

  • Anzahl der Skalierungseinheiten, die in einer Lösung implementiert sind; VMs, Speicherkonten usw. (für Skalierung)

  • Effizienz der von diesen Skalierungseinheiten ausgeführten Arbeit.

Die Menge der Arbeit, die für eine bestimmte Menge Kapazität ausgeführt werden kann, wird als die Dichte der Anwendung bezeichnet. Dichtere Dienste und Frameworks bieten eine größere Arbeitsmenge für eine angegebene Ressourcenbereitstellung; also wird durch die Verbesserung der Dichte die Reduzierung der bereitgestellten Kapazität (und der Kosten) oder die Möglichkeit bereitgestellt, zusätzliche Lasten mit derselben bereitgestellten Kapazität zu absorbieren. Die Dichte wird durch zwei Schlüsselfaktoren gesteuert:

  • Effizienz der Arbeitsausführung innerhalb einer Skalierungseinheit. Dies ist die herkömmliche Form der Leistungsoptimierung - Verwalten von Threadkonflikten und -sperren, Optimieren von Algorithmen und SQL-Abfragen.

  • Effizienz der Arbeitskoordination über Skalierungseinheiten hinweg. In einer Umgebung, in der die Systeme aus vielen kleineren Einheiten bestehen, ist die Möglichkeit, sie effizient zu kombinieren, wichtig für die Bereitstellung der Effizienz. Dies schließt Frameworks und Tools mit ein, die über Komponenten, wie SOAP-Messagingstapel, hinweg kommunizieren (z. B. WCF, ORMs (wie Entity Framework), TDS-Aufrufe (SQL-Clientcode) und Objektserialisierung (wie Datenverträge oder JSON).

Neben den herkömmlichen Optimierungstechniken, die für einen einzelnen Computer (oder eine Datenbank) verwendet werden, ist die Optimierung der verteilten Kommunikation und der Vorgänge von zentraler Bedeutung, um einen skalierbaren, effizienten Azure-Dienst bereitzustellen. Diese Schlüsseloptimierungen werden in späteren Abschnitten behandelt:

  • Segmentiert, nicht geschwätzig. Für jeden verteilten Vorgang (also ein Vorgang, der in einem Netzwerkaufruf resultiert) gibt es einen bestimmten Aufwand für die Paketeinbindung, -serialisierung, -verarbeitung usw. Um den Aufwand zu minimieren, versuchen Sie, Stapel mit einer kleineren Anzahl von "segmentierten" Vorgängen anstatt mit vielen "geschwätzigen" Vorgängen zu erstellen. Beachten Sie, dass das Erstellen von Stapeln für präzise Vorgänge die Latenzzeit erhöht und zum potenziellen Datenverlust führen kann. Beispiele für richtiges Stapelverarbeitungsverhalten sind:

    • SQL. Ausführen mehrerer Vorgänge in einem einzigen Stapel.

    • REST- und SOAP-Dienste (wie WCF). Nutzen von meldungsbasierten Vorgangsschnittstellen anstatt eines "geschwätzigen" RPC-Formats und möglichst Berücksichtigung eines REST-basierten Ansatzes.

    • Azure-Speicher (BLOBs, Tabellen, Warteschlangen). Veröffentlichen mehrerer Updates in einem Stapel statt einzeln.

  • Auswirkungen der Serialisierung. Verschieben von Daten zwischen Computern (sowie in den und aus dem permanenten Speicher) erfordert im Allgemeinen, dass die Daten in ein Übertragungsformat serialisiert werden. Die Effizienz (also die benötigte Zeit und der belegte Speicherplatz) dieses Vorgangs beherrscht schnell die Gesamtanwendungsleistung für Großsysteme.

    • Nutzen hoch effizienter Serialisierungsframeworks.

    • Verwenden Sie JSON für die Kommunikation mit Geräten oder für interoperable (lesbare) Anwendungen.

    • Verwenden Sie die sehr effiziente binäre Serialisierung (z. B. protobuf oder Avro) für die Dienst-zu-Dienst-Kommunikation, wenn Sie beide Endpunkte steuern.

  • Verwenden effizienter Framework. Es gibt viele umfangreiche Framework, die für die Entwicklung mit großen verfeinerten Funktionsgruppen verfügbar sind. Der Nachteil vieler dieser Frameworks besteht darin, dass Sie häufig die Leistungskosten für Funktionen tragen, die Sie nicht verwenden.

    • Isolieren Sie Dienst- und Client-APIs hinter generischen Schnittstellen, um den Austausch oder die parallele Auswertung zu ermöglichen (entweder durch statische Factorys oder eine Umkehrung des Steuerungscontainers). Stellen Sie beispielsweise eine austauschbare Zwischenspeicherebene bereit, indem Sie für eine generische Schnittstelle anstatt für eine spezielle Implementierung entwickeln (z. B. Azure-Zwischenspeicherung).

Im vorherigen Abschnitt wurden die Schlüsselkonzepte und -perspektiven des Entwurfes für das Erstellen von Anwendungen eingeführt, die die Cloudfabric nutzen, die von Azure bereitgestellt wird. In diesem Abschnitt werden die Kernplattformdienste und -funktionen erläutert und ihre Funktionen, Skalierungsgrenzen und Verfügbarkeitsmuster veranschaulicht.

Da jeder Azure-Dienst- oder jede Azure-Infrastrukturkomponente eine begrenzte Kapazität mit einer Verfügbarkeits-SLA bereitstellt, ist das Verstehen dieser Grenzen und Verhaltensweisen wichtig, wenn Sie entsprechende Entwurfsentscheidungen für Ihre Skalierbarkeitsziele und Endbenutzer-SLAs treffen. Jeder der Azure-Kerndienste wird im Kontext von vier Schlüsselpivots dargestellt: Funktionen und ihr Zweck; Dichte; Skalierbarkeit; Verfügbarkeit.

Ein Azure-Abonnement ist die grundlegende Einheit für Verwaltung, Rechnungsstellung und Dienstkontingente. Jedes Azure-Abonnement hat ein Standardkontingent, das durch den Support erhöht werden kann. Das Kontingent soll versehentliche Überschüsse und versehentlichen Ressourcenverbrauch verhindern.

Jedes Abonnement hat einen Kontobesitzer und mehrere Co-Admins, die durch Microsoft-Konten (früher Live IDs) autorisiert werden und Vollzugriff auf die Ressourcen im Abonnement durch das Verwaltungsportal haben. Sie können Speicherkonten erstellen, Cloud-Dienste bereitstellen, Konfigurationen ändern und Co-Admins hinzufügen oder entfernen.

Die Azure-Verwaltungs-APIs (REST-basierte Webdienste) stellen eine Automatisierungsschnittstelle zum Erstellen, Konfigurieren und Bereitstellen von Azure-Diensten bereit (wird durch das Verwaltungsportal verwendet). Zugriff auf diese APIs wird mithilfe der Verwaltungszertifikate beschränkt.

 

Dienst Standardlimit

Cloud Services

20

Speicherkonten

20

Kerne

20

Logische SQL-Datenbankserver

5

TipTipp
Informationen zu den aktuellen Einschränkungen zum Azure-Abonnement und -Dienst finden Sie unter Einschränkungen zum Azure-Abonnement und -Dienst, Kontingente und Beschränkungen

Ein Azure-Cloud-Dienst (früher gehosteter Dienst) ist die grundlegende Einheit der Bereitstellung und Skalierung. Jeder Cloud-Dienst besteht aus zwei Bereitstellungen (Produktion und Staging), jede mit einem Satz Rollen. Der Cloud-Dienst hat einen öffentlichen DNS-Eintrag (im Format "dienstname.cloudapp.net") für die Produktionsbereitstellung und einen DNS-Eintrag für die Stagingbereitstellung (im Format "beliebigeguid.cloudapp.net").

Jede Bereitstellung enthält mindestens eine Rolle, entweder eine Webrolle oder eine Workerrolle, die wiederum mindestens eine Instanz enthält (nicht permanente VMs). Jede Instanz enthält eine identische, unveränderliche, nicht permanente Momentaufnahme eines Softwarepakets für diese Rolle (das heißt, für alle Instanzen in einer angegebenen Rolle wird ein identischer Build bereitgestellt). Diese Instanzen führen eine spezielle Azure-Version von Windows Server aus (mit vielen standardmäßig für zusätzliche Sicherheit deaktivierten Diensten, die konfiguriert wurden, um mit Azure-Netzwerken und -Dienststrukturen usw. zu funktionen) und werden standardmäßig automatisch von der Azure-Struktur gepatcht. Das Live-Patchen wird durch ein paralleles Upgradeschema verarbeitet, das unten beschrieben wird.

Cloud-Dienste können in jedem Azure-Rechenzentrum entweder direkt (durch Auswahl der Zielregion beim Erstellen des Dienstes) oder durch eine Affinitätsgruppe bereitgestellt werden. Eine Affinitätsgruppe ist ein indirekter Verweis auf ein Bereitstellungsziel, das verwendet werden kann, um die Bereitstellung aller Komponenten einer Anwendung im gleichen Rechenzentrum zu optimieren.

Webrollen werden mit einer IIS-Instanz vorkonfiguriert, die den Anwendungscode hostet. Anwendungscode, der in den Workerrollen gehostet wird, wird im vorkonfigurierten Anwendungshost mit langer Laufzeit ausgeführt. Jeder Cloud-Dienst kann bis zu 25 Rollen haben. Die Rollen-Standardkonfiguration ist die Ausführung von .NET-Code, aber eine Rolle kann so konfiguriert werden, dass jeder Code ausgeführt wird, der mit Windows Server kompatibel ist - Java, Python, Ruby, node.js usw. Alle Plattformfunktionen, auf die in diesem Dokument verwiesen wird, sind auf allen Plattformen verfügbar, erfordern aber möglicherweise eine zusätzliche Clientproxyentwicklung um auf die REST-basierten APIs abzuzielen.

Innerhalb eines Cloud-Dienstes werden allen Instanzen private IP-Adressen zugewiesen (im 10.x-Block); alle ausgehenden Verbindungen scheinen von einer einzelnen virtuellen IP-Adresse oder VIP (die VIP der Cloud-Dienstbereitstellung) durch NAT zu kommen. Alle eingehenden Verbindungen müssen konfigurierte Endpunkte durchlaufen; diese Endpunkte bieten Lastenausgleichszugriff auf interne Rollen und Ports. Beispielsweise werden standardmäßig eingehende HTTP/HTTPS-Verbindungen (Port 80 und 443) zur Cloud-Dienstbereitstellung für alle verfügbaren Instanzen der primären Webrolle mit Lastenausgleich versehen.

Beachten Sie, dass die dienstübergreifende Latenzzeit (das heißt das Durchlaufen des NAT aus einem Cloud-Dienst und durch den Lastenausgleich in einen anderen Cloud-Dienst) wesentlich variabler als die lokale Entsprechung ist. Dies ist einer der Gründe dafür, dass gestapelte oder "segmentierte" dienstübergreifende Verbindungen für Skalierbarkeit empfohlen werden.

Die Azure-Struktur stellt auch einen Konfigurationsdienst bereit, der für alle Instanzen in der Cloud-Dienstbereitstellung verfügbar ist. Ein statischer Satz mit erwarteten Konfigurationsschlüsseln wird in der Dienstdefinition (als Teil der Programmentwicklungszeit) bereitgestellt, wobei der Anfangssatz mit Konfigurationswerten zusammen mit dem Dienst bereitgestellt wird, wenn er auf Azure veröffentlicht wird. Dieser Satz mit Konfigurationswerten ist als Laufzeitsuche für alle Instanzen in der Dienstbereitstellung verfügbar und kann zur Laufzeit durch eine REST-Schnittstelle, das Azure-Portal oder ein PowerShell-Skript geändert werden.

Wenn die Laufzeitkonfiguration geändert wird, können alle Instanzen (im Anwendungscode) die Konfigurationsänderungsbenachrichtigung übernehmen und die Konfigurationsupdates intern verarbeiten. Wenn kein Anwendungscode geschrieben wird, um das Konfigurationsänderungsereignis aufzuzeichnen, erfahren alle Instanzen in der Rolle einen Neustart, um ihre Konfiguration zu aktualisieren.

Der Status jeder Instanz ist nicht dauerhaft; jede Konfiguration oberhalb des Azure-Basisbilds (ein spezieller Windows Server-VM) erfordert die Konfiguration beim Start, um Leistungsindikatoren zu erstellen, IIS-Einstellungen zu optimieren, abhängige Software zu installieren usw. Diese Konfigurationsskripts werden normalerweise als Starttask ausgeführt, der von der Cloud-Dienstkonfiguration definiert wird.

Innerhalb eines Cloud-Dienstes stellt die Azure-Struktur Informationen zur Konfiguration, zu internen IP-Adressen, zur Dienstkonfiguration usw. bereit. Die Bereitstellung erfolgt durch die Rollenumgebung. Alle Prozesse, die auf einer Azure-Instanz ausgeführt werden, können auf die Rollenumgebungsinformationen zugreifen, um Konfigurationsdaten abzurufen, die Netzwerktopologie zu ermitteln usw. Sie können auch die Azure-Verwaltungs-APIs verwenden, um auf diese Informationen extern zuzugreifen.

Die Azure-Struktur bietet zwei Kernkonzepte zum Verwalten von Komponentenfehlern, Neukonfigurationen und Upgrades/Patches: Upgradedomänen und Fehlerdomänen.

Upgradedomänen sind logische Gruppierungen in einem Azure-Dienst; standardmäßig verfügt jeder Dienst über fünf (5) Upgradedomänen (dieser Wert kann in der Cloud-Dienstdefinition geändert werden). Alle Dienständerungen und Upgrades beeinflussen jeweils nur eine einzige Upgradedomäne Beispiele für diese Änderungen sind das Patchen des Betriebssystems, das Ändern der Größe des virtuellen Computers, das Hinzufügen von Rollen oder Rolleninstanzen zu einem ausgeführten Dienst oder das Ändern der Endpunktkonfiguration.

Dies ermöglicht die Neukonfiguration eines ausgeführten Cloud-Dienstes, während die Verfügbarkeit beibehalten wird. Für Rollen, die nur eine einzige Instanz enthalten, kann die Azure-Struktur keine Verfügbarkeit während Upgradevorgängen bereitstellen. Darum entspricht das Ausführen von Einzelinstanzrollen nicht der Azure-SLA.

Fehlerdomänen sind logische Gruppierungen auf Grundlage der zugrunde liegenden Hardware. Logische Gruppen werden nicht zwingend einer bestimmten Hardwarekonfiguration zugeordnet. Stellen Sie sich logische Gruppen als Methode der Azure-Struktur zum automatischen Trennen von Instanzen von zugrunde liegenden Ressourcen vor, die einen einzelnen Fehlerpunkt darstellt (wie ein einzelner zugrunde liegender physischer Server, ein Rack usw.). Um der Dienst-SLA zu entsprechen, muss Azure Instanzen für mindestens zwei Fehlerdomänen bereitstellen. Das ist der andere Grund dafür, dass Einzelinstanz-Rollenbereitstellungen der Azure-SLA nicht entsprechen.

Zusammengefasst:

  • Die grundlegende Einheit der Bereitstellung und Skalierung in Azure ist der Cloud-Dienst, der aus einer Gruppe von Rollen besteht. Jede Rolle enthält einen Satz identischer Rolleninstanzen, von denen jede eine spezielle für die Cloud konfigurierte Version von Windows Server ausführt.

  • Zusätzlich zur physischen Topologie (Rollen und Instanzen) und zum Anwendungscode definieren Cloud-Dienste eine dienstweite Konfiguration. Diese Konfiguration kann zur Laufzeit aktualisiert werden.

  • Jede Rolleninstanz ist nicht permanent (Änderungen, Dateien usw. werden bei Neustarts, Patches und Fehlerereignissen nicht unbedingt beibehalten).

  • Jeder Cloud-Dienst verfügt über eine einzige virtuelle IP-Adresse für ein- und ausgehenden Datenverkehr. Der Cloud-Dienst verfügt über Endpunkte, die (Roundrobin)-Zuordnung mit Lastenausgleich auf einer internen Rolle und einem internen Port bereitstellen.

  • Azure verwendet Upgradedomänen, um Gruppen von Instanzen logisch zu trennen und parallele Upgrades oder Änderungen bereitzustellen (während die Verfügbarkeit beibehalten wird).

  • Azure verwendet Fehlerdomänen, um Instanzen von einzelnen Fehlerpunkten physisch zu gruppieren (wenn zum Beispiel alle Instanzen auf dem gleichen zugrunde liegenden physischen Computer ausgeführt werden).

  • Nutzen Sie mehrere Abonnements, um Entwicklungs-, Test-, Staging- und Produktionsumgebungen zu isolieren.

Jede Rolle enthält einen Satz mit mindestens einer Instanz. Jede dieser Instanzen ist ein virtueller Computer und führt eine spezielle Version von Windows Server aus. Instanzen (VMs) sind derzeit in fünf Größen verfügbar: sehr klein bis sehr groß. Jeder dieser Größen wird ein bestimmter Wert für CPU, Arbeitsspeicher, Speicher und Bandbreite zugeordnet.

 

Größe virtueller Computer CPU-Kerne Arbeitsspeicher Speicherplatz für lokale Speicherressourcen im Internet und in den Workerrollen Speicherplatz für lokale Speicherressourcen in einer VM-Rolle Zugeordnete Bandbreite (MBit/s)

Sehr klein

Gemeinsam genutzt

768 MB

19.480 MB

(6.144 MB ist für Systemdateien reserviert)

20 GB

5

Klein

1

1,75 GB

229.400 MB

(6.144 MB ist für Systemdateien reserviert)

165 GB

100

Mittel

2

3,5 GB

500.760 MB

(6.144 MB ist für Systemdateien reserviert)

340 GB

200

Groß

4

7 GB

1.023.000 MB

(6.144 MB ist für Systemdateien reserviert)

850 GB

400

Sehr groß

8

14 GB

2.087.960 MB

(6.144 MB ist für Systemdateien reserviert)

1.890 GB

800

TipTipp
Informationen zu den aktuellen Einschränkungen zum Azure-Abonnement und -Dienst finden Sie unter Einschränkungen zum Azure-Abonnement und -Dienst, Kontingente und Beschränkungen

Falls zwei oder mehr Instanzen in anderen Fehler- und Upgradedomänen bereitgestellt werden, stellt Azure die folgenden SLAs für Cloud-Dienste bereit:

  • 99,95 % externe Konnektivität Internet-orientierte Rollen (mit externen Endpunkten)

  • 99,9 % erkennen Rolleninstanzprobleme innerhalb von zwei Minuten und beginnen mit Korrekturmaßnahmen

Die Rolleninstanzgrößen und die Rolleninstanzanzahl können dynamisch in einer ausgeführten Anwendung geändert werden (Hinweis: Das Ändern von Rolleninstanzgrößen löst eine erneute Rollenbereitstellung aus). Unter Verwendung des horizontalen Skalierungsansatzes für das Erstellen von Azure-Anwendungen ist größer nicht unbedingt besser, wenn es um die Auswahl von Instanzgrößen geht. Dies gilt für Kosten (warum für etwas zahlen, was nicht verwendet wird) und die Leistung (je nachdem, ob Ihre Arbeitsauslastung an die CPU, an E/A oder etwas anderes gebunden ist). Vorgehensweisen zum Auswählen der Anzahl der Instanzen und Instanzgrößen werden ausführlicher im Abschnitt zu den bewährten Vorgehensweisen dieses Dokuments erläutert.

Azure-Speicher ist der permanente Standarddatendienst für Azure und stellt BLOBs (Datei), Warteschlangen- und Tabellenspeicher bereit (wichtig für Werte). Das Speicherkonto ist die grundlegende Einheit für Skalierung und Verfügbarkeit und stellt die folgenden Funktionen bereit. Die gesamte Kommunikation mit dem Speicherdienst erfolgt auf der REST-Schnittstelle über HTTP.

TipTipp
Informationen zu den aktuellen Einschränkungen zum Azure-Abonnement und -Dienst finden Sie unter Einschränkungen zum Azure-Abonnement und -Dienst, Kontingente und Beschränkungen

Die Azure-Speicherverfügbarkeits-SLA garantiert, dass mindestens 99,9 % Prozent der Zeit ordnungsgemäß formatierte Anforderungen zum Hinzufügen, Aktualisieren, Lesen und Löschen von Daten erfolgreich und korrekt verarbeitet werden und dass Speicherkonten außerdem die Konnektivität zum Internetgateway haben.

Diese Begrenzungen werden bei allen Verwendungen des einzelnen Speicherkontos gemeinsam genutzt; die Anzahl von Vorgängen pro Sekunde und die Gesamtbandbreite wird gemeinsam von Tabellen, BLOBs und Warteschlangen genutzt. Wenn eine Anwendung die Gesamtanzahl von Vorgängen pro Sekunde überschreitet, gibt der Dienst möglicherweise den HTTP-Code 503 wegen eines ausgelasteten Servers zurück. Vorgänge gehören immer zu einem einzelnen Speicheraspekt (Tabellen, Warteschlangen oder BLOBs) und werden in den Unterabschnitten weiter unten erläutert.

Im Hinblick auf die zuvor verwendete Versandcontainermetapher ist jedes Speicherkonto ein Container, der eine bestimmte Kapazität bereitstellt. Ein Überschreiten der Grenze eines einzigen Kontos (Versandcontainers) erfordert die Verwendung mehrerer Konten in der gleichen Anwendung.

Azure-Speicher stellt standardmäßig Verfügbarkeit und Stabilität bereit; alle Schreibvorgänge oder Updates im Azure-Speicher werden transparent und konsistent auf drei Speicherknoten repliziert (die sich in unterschiedlichen Upgrade- und Fehlerdomänen befinden). Der Zugriff auf Azure wird mithilfe der Einfaktorauthentifizierung in Form von Zugriffsschlüsseln gesteuert. Jedes Speicherkonto verfügt über einen primären und einen sekundären Schlüssel, die kontinuierliche Verfügbarkeit ermöglichen, wenn der Primärschlüssel deaktiviert ist. Daten im Azure-Speicher werden automatisch in ein "Spiegel"-Rechenzentrum geografisch repliziert (es sei denn, diese Funktion wird mithilfe des Portals ausdrücklich deaktiviert). Die geografische Replikation ist nicht transparent und nutzt DNS-Umleitung für Failovers von Clients zum sekundären Speicherort im Falle eines Fehlers im primären Rechenzentrum.

Beachten Sie, dass, während Azure-Speicher Datenstabilität durch automatisierte Replikate bereitstellt, der Anwendungscode (oder Entwickler/Benutzer) dennoch Daten durch versehentliches oder unbeabsichtigtes Löschen, Aktualisieren usw. beschädigen kann. Das Beibehalten der Datengenauigkeit im Falle eines Anwendungs- oder Benutzerfehlers erfordert fortschrittlichere Techniken, wie das Kopieren der Daten an einen sekundären Speicherort mit einem Überwachungsprotokoll. BLOB-Speicher stellt eine Momentaufnahmefunktion bereit, die schreibgeschützte Zeitpunktmomentaufnahmen von BLOB-Inhalten erstellen kann, die als Basis einer Datengenauigkeitslösung für BLOBs verwendet werden können.

Azure-Speicher stellt Telemetriedaten durch die Speicheranalyse-Funktion zur Verfügung und sammelt und veröffentlicht Nutzungsdaten zu einzelnen Speicheraufrufen in Tabellen, Warteschlangen und BLOBs. Speicheranalyse muss für jedes Speicherkonto mit einer Sammelrichtlinie (für alle sammeln, nur für Tabellen sammeln usw.) und einer Beibehaltungsrichtlinie (wie lange Daten behalten werden) aktiviert werden.

BLOB-Speicher stellt den Dateiverwaltungsdienst in Azure bereit und bietet eine Methode mit hoher Verfügbarkeit und Kosteneffizienz zum Speichern von unstrukturierten Massendaten. Der Dienst stellt zwei Arten von BLOBs bereit:

  • Block-BLOBs. Block-BLOBs wurden für das effiziente Verwalten großer Daten-BLOBs entwickelt. Jeder Block-BLOB besteht aus bis zu 50.000 Blöcken, von denen jeder maximal 4 MB groß sein kann (mit einer maximalen Gesamt-Block-BLOB-Größe von 200 GB). Block-BLOBs unterstützen das parallele Hochladen für das effiziente und gleichzeitige Verschieben großer Dateien in Netzwerken. Einzelne Blöcke können ersetzt, eingefügt oder gelöscht werden, können aber nicht an Ort und Stelle bearbeitet werden.

  • Seiten-BLOBs. Seiten-BLOBs wurden für die effiziente Bereitstellung zufälliger Lese-/Schreibvorgänge entwickelt (wie der Zugriff auf eine VHD). Jeder Seiten-BLOB hat eine Maximalgröße von 1 TB und besteht aus Seiten mit je 512 Byte. Einzelne Seiten oder Seitengruppen können durch direktes Überschreiben hinzugefügt oder aktualisiert werden.

Die Entwurfsgrenzen für BLOB-Speicher werden in der Tabelle unten aufgeführt. Denken Sie daran, dass alle diese Vorgänge für die Gesamt-Speicherkontogrenze zählen.

 

BLOB-Kategorie Limit

Maximale BLOB-Größe (Block)

200 GB (50k-Blöcke)

Maximale Blockgröße

4 MB

Maximale BLOB-Größe (Seite)

1 TB

Seitengröße

512 Byte

Maximale Bandbreite/BLOB

480 MBit/s

Beim Überschreiten der Größen- oder Bandbreitengrenzen einzelner BLOBs können Anwendungen gleichzeitig (oder nacheinander) in mehrere BLOB-Dateien schreiben. Wenn Ihre Anwendung die Grenzen eines einzelnen Speicherkontos überschreitet, nutzen Sie mehrere Speicherkonten für zusätzliche Kapazität.

Azure-Warteschlangen stellen einen zwischengeschalteten (brokered) Messagingdienst zwischen Verlegern und Abonnenten bereit. Warteschlangen unterstützen mehrere gleichzeitige Verleger und Abonnenten, veröffentlichen systemintern aber keine Messaginggrundtypen höherer Position, wie pub/sub-Routing oder themenbasiertes Routing. Sie werden in der Regel verwendet, um Arbeitsaufgaben (wie Nachrichten, Dokumente, Tasks usw.) auf eine Gruppe von Workerrolleninstanzen (oder auf mehrere gehostete Dienste usw.) zu verteilen.

Warteschlangennachrichten werden nach 7 Tagen automatisch gelöscht, wenn sie nicht von einer Anwendung abgerufen und gelöscht werden. Sie ermöglichen das Entkoppeln zwischen Verlegern und Informationsverbrauchern; so lange beide Seiten den Speicherkontoschlüssel und den Warteschlangennamen haben, können sie kommunizieren.

 

Warteschlangenkategorie Limit

Maximale Nachrichten in der Warteschlange

N/V (bis zur Speicherkontogrenze)

Maximale Lebensdauer einer Nachricht

1 Woche (automatisch gelöscht)

Maximale Nachrichtengröße

64 kB

Maximaler Durchsatz

~ 500 Nachrichten/Sekunde

Warteschlangen dienen dazu, Steuernachrichten weiterzuleiten, aber keine Rohdaten. Wenn die Nachrichten zu groß sind, um in eine Warteschlange zu passen, gestalten Sie die Nachrichten um, indem Sie Daten und Befehl trennen. Speichern Sie die Daten in BLOB-Speicher mit einem Verweis (URI) auf die Daten und den Zweck (wie also mit den Daten im BLOB-Speicher verfahren werden soll), die in einer Warteschlangenmeldung gespeichert sind.

Um den Durchsatz innerhalb einer einzelnen Warteschlange zu erhöhen, stapeln Sie mehrere Nachrichten in einer einzelnen Nachricht und nutzen dann den Befehl zum Aktualisieren der Nachricht, um den Fortschritt der Aufgaben der kapselnden Nachricht nachzuverfolgen. Eine andere Technik besteht darin, mehrere Nachrichten in einem BLOB mit einem Verweis zum BLOB in der Warteschlangenmeldung zu platzieren.

Wenn Ihre Anwendung mehr Durchsatz erfordert, als von einer einzelnen Warteschlange bereitgestellt wird, nutzen Sie mehrere gleichzeitige Warteschlangen. In diesem Kontext muss Ihre Anwendung entsprechende Partitionierungs- und Routinglogik implementieren.

Azure-Tabellenspeicher stellt einen sehr stabilen, skalierbaren und konsistenten Speicher für Spaltendaten (zweidimensional) bereit. Er stellt einen { Partitionsschlüssel, Zeilenschlüssel } -> { Datensemantik[] } für das Speichern von und den Zugriff auf Daten bereit, wie im Diagramm unten dargestellt wird. Jede Tabelle wird durch Partitionen unterteilt, die wiederum Entitäten enthalten. Jede Entität kann ihr eigenes (flaches) Schema oder eine Liste mit Eigenschaften (Spalten) haben.

Jede Partition unterstützt bis zu 500 Vorgänge pro Sekunde; jede Tabelle unterstützt wiederum das Maximum von Vorgängen, die im Speicherkonto verfügbar sind. Da jede Entität nicht nur die tatsächlichen Daten, sondern auch die Säulenmetadaten enthält (da jede Entität ein anderes Schema haben kann), sind lange Spaltennamen, insbesondere bei einem großen Ansatz, nicht empfehlenswert.

 

Tabellenkategorie Limit

Maximale Vorgänge pro Sekunde pro Partition

500

Maximale Entitätsgröße (Spaltennamen + Daten)

1 MB

Maximale Spaltengröße (Byte[] oder Zeichenfolge)

64 kB

Maximale Zeilenanzahl

N/V (bis zur Speicherkontogrenze)

Unterstützte Datentypen

byte[], Boolean, datetime, double, Guid, int32, int64, string

Einzelne Entitäten (die Sie sich als Zeilen vorstellen können), haben eine maximale Größe von 1 MB, wobei einzelne Spalten auf maximal 64 KB beschränkt sind. Unterstützte Datentypen werden in der Tabelle oben aufgelistet; für nicht unterstützte Typen (wie DateTimeOffset) ist ein Serialisierungsproxy im Anwendungscode erforderlich (beispielsweise das Speichern von DateTimeOffset in einem Standardzeichenfolgenformat).

Tabellenspeicherung bietet Zugriff auf gespeicherte Daten mithilfe der Schlüssel, die Partitionen und Entitäten, Partitionsscans oder Entitätsscans zugeordnet sind. Sie unterstützt Filterprojektion, da ein Filterausdruck zum Tabellenspeicher als Teil der Abfrage weitergeleitet und im Tabellenspeicher ausgeführt werden kann). Tabellenspeicherung stellt keine sekundären Indizes bereit, sodass jede Suche, die nicht auf dem Partitionsschlüssel oder Entitätsschlüssel basiert, einen Tabellen- und/oder Partitionsscan erfordert. Bei Partitionen, die eine größere Anzahl von Entitäten enthalten, hat dies normalerweise drastische Auswirkungen auf die Leistung.

Jede Abfrageverarbeitung, deren Ausführung länger als 5 Sekunden dauert, gibt ein Fortsetzungstoken zurück, das die Anwendung verwenden kann, um den Empfang der Ergebnisse der Abfrage fortzusetzen. Abfragen, die mehr als 1.000 Entitäten abrufen, müssen ein Auslagerungsmodell nutzen, um Daten in Abschnitten von 1.000 Entitäten zurückzugeben (was systemintern von der Tabellenspeicher-API unterstützt wird).

Die einzigen Abfrageausdrücke, die derzeit für Tabellenspeicher unterstützt werden, sind Filtern und Auswahl (Auswählen bestimmter Eigenschaften); die Tabellenspeicherung stellt keine serverseitige Aggregation oder Gruppierungssemantik bereit. Um Anwendungen zu erstellen, die eine umfangreiche Aggregation oder analytische Funktionen erfordern, ist es häufig die bessere Wahl, Daten in aggregierter Form zu speichern oder ein relationales Modul zu verwenden, zum Beispiel die Azure SQL-Datenbank. Einige Anwendungen nutzen einen Hybridansatz, der Daten aus dem Tabellenspeicher in einer untergeordneten SQL-Datenbank aggregiert, die anschließend für Abfragen und Berichterstellung verwendet wird.

Das Auswählen einer entsprechenden Partitionierungsfunktion ist für die effiziente und effektive Verwendung des Tabellenspeichers wichtig. Es gibt zwei primäre Optionen für den Typ der Partitionierungsfunktion:

  • Zeit. Zeitbasierte Partitionierungsfunktionen, die häufig zum Speichern von Zeitfolgendaten verwendet werden, wie Azure-Diagnoseleistungsindikatoren (eine Verwendung, die im Telemetrie-Abschnitt dieses Dokuments erläutert wird), konvertieren die aktuelle Uhrzeit in einen Wert, der ein Zeitfenster darstellt (die aktuelle Minute, Stunde usw.).

    Sie ermöglichen die effiziente Suche nach einer bestimmten Partition (da die Filterklausel für Tabellenspeicher >=, <= usw. unterstützt), können jedoch eingeschränkt werden, wenn das ausgewählte Zeitfenster zu schmal ist und ein Spitzenereignis auftritt. Wenn beispielsweise die ausgewählte Partitionsfunktion die aktuelle Minute ist und ein Spitzenereignis auftritt, versuchen möglicherweise zu viele Clients, gleichzeitig auf dieselbe Partition schreiben. Dies wirkt sich nicht nur auf den Durchsatz beim Einfügen aus, sondern auch auf den Durchsatz bei Abfragen.

  • Daten. Datenorientierte Partitionierungsfunktionen berechnen den Partitionswert nach einer oder mehreren Eigenschaften der zu speichernden (oder abzurufenden) Daten. Das Auswählen einer entsprechenden datengesteuerten Partitionierungsfunktion hängt von mehreren Faktoren ab - Abfragemuster, Partitionsschlüsseldichte (wie viele Entitäten in eine Partition gelangen) und unvorhersehbares Wachstum (es kann schwierig sein, sehr große Tabellen neu zu verteilen). Allgemeine Muster umfassen folgende:

    • Einzelfeld. Der Partitionsschlüssel ist ein einzelnes Feld in den Quelldaten (wie eine Kunden-ID für Bestellinformationen).

    • Mehrfachfeld. Entweder der Partitions- oder der Zeilenschlüssel ist eine Zusammensetzung (üblicherweise einer Verkettung) aus mehreren Feldern in den Quelldaten. Wenn Sie Partitionsschlüssel auswählen, sollten Sie beachten, dass Stapelverarbeitungsvorgänge erfordern, dass sich alle Entitäten in derselben Partition befinden (also den gleichen Partitionsschlüssel haben).

    • Berechnetes Feld. Die Partitionsschlüssel wird aus einer oder mehreren Feldern basierend auf einer deterministischen Funktion berechnet. Ein allgemeines Beispiel hierfür wäre das Verteilen von Benutzerprofilen auf mehrere Partitionen. Die Benutzer-ID wird mithilfe einer Hashverfahrensfunktion hashcodiert, die für die relativ einheitliche Verteilung entworfen wurde. Dann wird Modulo für die Anzahl der gewünschten Partitionen übernommen.

Jede nicht triviale Anwendung erfordert die Verwendung von mehreren Partitionen. Sogar bei Tabellen mit wenigen Gesamtentitäten (z. B. zweihundert) sind mehrere Partitionen für den Durchsatz erforderlich, wenn die Anwendung mehrere tausend Anforderungen pro Sekunde ausführt:

  • Einzeltabelle/Einzelpartition. Einfachste Option (konstanter Partitionsschlüsselwert), die sich für geringe Arbeitsauslastungen mit eingeschränkten Datenmengen und Anforderungsdurchsatzanforderungen (< 500 Entitäten/Sekunde) eignet.

  • Einzeltabelle/Mehrfachpartition. Die typische Option für die meisten Bereitstellungen; wählen Sie die Partitionsschlüssel, die auf die Zielabfragemuster abgestimmt werden sollen, mit Bedacht aus.

  • Mehrfachspeicherkonto/Mehrfachpartition. Wenn die Last projiziert wird, um 5.000 Vorgänge pro Sekunde zu überschreiten, ist die Verwendung von Tabellen, die über mehrere Speicherkonten verteilt sind, erforderlich.

Nach der Auswahl kann das Neuverteilen (Neupartitionieren) von Daten sehr teuer sein und umfasst das Lesen und Kopieren aller Entitäten mit neuen Partitionsschlüsseln und das Löschen der alten Daten. Beachten Sie, dass es keine Mindestgrößeneinschränkung für eine Partition gibt; Partitionen können aus einer einzigen Entität (einer Zeile) bestehen.

Wenn Ihre Anwendung mehr Durchsatz als von einer einzelnen Tabelle bereitgestellt erfordert (nach der vorsichtigen Partitionsauswahl), nutzen Sie mehrere gleichzeitige Tabellen in verschiedenen Speicherkonten. In diesem Kontext muss Ihre Anwendung entsprechende Routinglogik implementieren, um das entsprechende Speicherkonto auszuwählen.

Das Netzwerk für die Inhaltsübermittlung (CDN) in Azure stellt eine effiziente Möglichkeit bereit, statischen Inhalt (aus BLOBs oder der Anwendungsausgabe) in einem global verteilten Zwischenspeichernetzwerk zwischenzuspeichern. Dadurch wird der Druck auf Ihre Anwendung für das Bereitstellen statischer Inhalte vermindert und die Gesamtbenutzerfreundlichkeit verbessert.

Die Verfügbarkeits-SLA des Netzwerks für die Inhaltsübermittlung stellt sicher, dass die zwischengespeicherten Objekte mit monatlich 99,9 % Verfügbarkeit bereitgestellt werden.

Das Verwenden des CDN erfordert, dass die Funktion für Ihr Abonnement aktiviert ist. Von dort aus können BLOB-Inhalte (aus öffentlich verfügbaren/anonymen Zugriffscontainern) und der anonyme Anwendungsausgabeinhalt (beispielsweise http://www.myapp.com/cdn/somepage.aspx) zwischengespeichert werden.

Im Allgemeinen sollten für jede große Anwendung alle häufig verwendeten statischen Inhalte (Bilder, css usw.) über CDN mit entsprechenden Cacheablaufrichtlinien bereitgestellt werden.

Stellen Sie sich beispielsweise einen Online-eBook-Shop mit einer Million Titel vor. Das Einschließen aller Inhalte (Bilder usw.) für alle Titel in das CDN wäre sehr teuer (da der Großteil des Inhalts nur selten aufgerufen wird und ständig abläuft), während das Einschließen nur der Top-Inhalte (beispielsweise die 50 wichtigsten Titel) die richtige Mischung des Zwischenspeicherns im Vergleich zum Preis bereitstellen würde.

Eines der Kernelemente des erfolgreichen Bereitstellens eines umfangreichen Dienstes ist die Telemetrie - Einblick in die Vorgänge, Leistung und Benutzerfreundlichkeit Ihrer Anwendung. Telemetrieansätze für Azure-Anwendungen müssen die horizontale Skalierung/die Verteilung der Plattform und der verfügbaren Plattformdienste für das Sammeln, Analysieren und Nutzen der Telemetrie berücksichtigen.

Die Baselinetechnologiekomponente für das Sammeln und das Verstehen der Telemetrie auf Azure ist Azure-Diagnose (WAD). WAD besteht aus einem Agent, der Daten von einzelnen Instanzen sammelt und sie an einen zentralen Sammelpunkt (Speicherkonto) weiterleitet sowie aus einem Satz von Standardstrukturen und -konventionen für das Speichern von und das Zugreifen auf Daten. Der Agent unterstützt mehrere Konfigurationsansätze, einschließlich Code (.NET), eine Konfigurationsdatei, die innerhalb des bereitgestellten Projektcodes eingebettet ist, oder eine zentrale Konfigurationsdatei, die auf dem BLOB-Speicher bereitgestellt wird. Die Konfiguration ist in der letzten Instanz teilweise dynamisch und ermöglicht, dass aktualisierte Diagnosedateien in den BLOB-Speicher verschoben und dann auf die Zielclients übertragen werden.

Die WAD-Konfiguration unterstützt einige Datenquellen; jede dieser Datenquellen wird regelmäßig erfasst, im Batchmodus durch eine Ereignisablaufverfolgungssitzung für Windows (ETW) ausgeführt und auf dem Zielspeicherkonto veröffentlicht. Der Agent behandelt vorübergehende Verbindungsprobleme, Wiederholungen usw. Die verfügbaren Datenquellen sind:

  • Leistungsindikatoren. Eine Teilmenge von Leistungsindikatorwerten (CPU, Arbeitsspeicher usw.), die in einer lokalen ETW-Sitzung erfasst und in regelmäßigen Abständen im Tabellenspeicher bereitgestellt werden.

  • Windows-Ereignisprotokolle. Eine Teilmenge mit Windows-Ereignisdatensätzen (Anwendung, System usw.), die in einer lokalen ETW-Sitzung aufgezeichnet und in regelmäßigen Abständen im Tabellenspeicher bereitgestellt werden.

  • Azure-Protokolle. Anwendungsprotokolle (Ablaufverfolgungsmeldungen), die vom Anwendungscode (über System.Diagnostics.Trace) veröffentlicht und von einem DiagnosticMonitorTraceListener-Ablaufverfolgungslistener aufgezeichnet werden. Diese Protokolle werden in der WAD-Leistungsindikatortabelle im Zielspeicherkonto veröffentlicht.

  • IIS 7.0-Protokolle. Standard-IIS-Protokollinformationen zu Anforderungen, die von IIS (nur Webrollen) protokolliert werden. Protokolle werden in lokalen Dateien gesammelten und in regelmäßigen Abständen im BLOB-Speicher bereitgestellt.

  • Fehlgeschlagene IIS-Anforderungsprotokolle. Informationen zu fehlgeschlagenen Anforderungen von IIS, die in lokalen Dateien gesammelt und in regelmäßigen Abständen im BLOB-Speicher bereitgestellt werden.

  • Absturzabbilder. Im Falle eines Systemabsturzes werden Protokolle zum Status des Betriebssystems aufgezeichnet und im BLOB-Speicher veröffentlicht.

  • Datenquelle. WAD kann zusätzliche lokale Verzeichnisse überwachen (z. B. Protokollverzeichnisse im lokalen Speicher) und die Daten in regelmäßigen Abständen in einen benutzerdefinierten Container im BLOB-Speicher kopieren.

Jede dieser Datenquellen wird mit der Teilmenge der zu erfassenden Daten (beispielsweise die Liste der Leistungsindikatoren) und des Erfassung-/Veröffentlichungsintervalls konfiguriert. Es gibt auch einige PowerShell-Skripts, die verfügbar sind, um die Laufzeitkonfiguration zu ändern oder ein sofortiges Veröffentlichen der Daten von den Agents im Zielspeicherkonto zu erzwingen.

ImportantWichtig
Protokollieren der Telemetrie in einem separaten Speicherkonto. Durch das Protokollieren der Telemetrie- und Anwendungsdaten im gleichen Speicherkonto werden ernste Konfliktprobleme beim Skalieren verursacht.

Azure SQL-Datenbank stellt eine als Dienst bereitgestellte Datenbank (DBaaS) bereit und ermöglicht es Anwendungen, Daten schnell in relationalen Datenbanken bereitzustellen und einzufügen sowie diese Datenbanken abzufragen. Sie stellt viele der vertrauten SQL Server-Funktionen und -Features bereit, während der Aufwand der Hardware, der Konfiguration, des Patchens und der Stabilität abstrahiert werden.

noteHinweis
Die SQL-Datenbank stellt keine 1:1-Funktionsparität mit SQL Server bereit und soll andere Anforderungen zu erfüllen, die eindeutig für Cloudanwendungen geeignet sind (elastische Skalierung, als Dienst bereitgestellte Datenbank zum Reduzieren von Wartungskosten usw.). Weitere Informationen finden Sie unter http://blogs.msdn.com/b/windowsazure/archive/2012/06/26/data-series-sql-server-in-windows-azure-virtual-machine-vs-sql-database.aspx.

Der Dienst wird in einer freigegebenen Umgebung mit Mehrinstanzenfähigkeit ausgeführt, wobei Datenbanken von mehreren Benutzern und Abonnements in der Infrastruktur ausgeführt werden, die auf Standardhardware basiert (horizontales Skalieren, kein zentrales Skalieren).

Datenbanken werden innerhalb von logischen Servern bereitgestellt; jeder logische Server enthält standardmäßig bis zu 150 Datenbanken (einschließlich der master-Datenbank). Standardmäßig kann jedes Abonnement fünf (5) logische Server mit der Möglichkeit bereitstellen, dieses Kontingent sowie die maximale Anzahl von Datenbanken pro logischen Server zu erhöhen, indem es sich an den Support wendet.

Jedem logischen Server wird ein öffentlicher, eindeutiger generierter DNS-Name zugewiesen (im Format [Servername].database.windows.net), wobei jeder logische Server in einem Abonnement die gleiche öffentliche IP-Adresse verwendet. Der Zugriff auf logische Server (und Datenbanken) erfolgt über den Standard-SQL-Port (TCP/1433) mit einer REST-basierten Verwaltungs-API, die über Port TCP/833 zugreift.

Standardmäßig wird der Zugriff auf den logischen Server (und alle zugehörigen Datenbanken) über IP-basierte Firewallregeln auf das Azure-Verwaltungsportal beschränkt (Regeln können für den logischen Server oder für einzelne Datenbanken festgelegt werden). Das Aktivieren des Zugriffs auf Azure-Anwendungen und die direkte Anwendungskonnektivität außerhalb von Azure (beispielsweise zum Verbinden von SQL Server Management Studio) erfordert das Konfigurieren von Firewallregeln. Diese Regeln werden durch das Azure-Verwaltungsportal mithilfe eines Verwaltungsdienst-API-Aufrufs konfiguriert.

Die SQL-Datenbank bietet Unterstützung für die meisten Schlüsselfunktionen in SQL Server, wobei es einige wichtige Ausnahmen gibt:

  • Alle Tabellen müssen einen CLUSTERED INDEX (gruppierten Index) enthalten; Daten können erst mit INSERT in die Tabelle einer SQL-Datenbank eingefügt werden, wenn ein CLUSTERED INDEX (gruppierter Index) definiert wurde.

  • Keine eingebettete Unterstützung für Common Language Runtime (CLR), Datenbankspiegelung, Service Broker, Datenkomprimierung oder Tabellenpartitionierung.

  • Keine XML-Indizes; XML-Datentyp wird unterstützt.

  • Keine Unterstützung für transparente Datenverschlüsselung (TDE) oder Datenüberwachung

  • Keine Unterstützung der Volltextsuche

Jede Datenbank wird mit einer oberen Größenbeschränkung konfiguriert. Die derzeit verfügbaren Maximalgrößen sind 1 GB, 5 GB, 10 GB, 20 GB, 30 GB, 40 GB, 50 GB, 100 GB und 150 GB (die derzeit verfügbare maximale Größe). Wenn eine Datenbank die obere Größenbeschränkung erreicht, weist sie zusätzliche INSERT- oder UPDATE-Befehle zurück (das Abfragen und Löschen von Daten ist weiterhin möglich). Auch die Größe einer Datenbank kann mithilfe des ALTER DATABASE-Befehls erstellt (vergrößert oder verkleinert) werden.

Da Datenbanken auf Grundlage der durchschnittlichen verwendeten Größe pro Tag berechnet werden, können die Anwendungen, die schnelles oder unvorhersehbares Wachstum erwarten, die maximale Größe der Datenbank zu Beginn auf 150 GB festlegen. Das Skalieren einer Datenbank über 150 GB hinaus erfordert das Verwenden eines Ansatzes für horizontales Skalieren, der ausführlicher im Abschnitt unten beschrieben wird.

Die SQL-Datenbank stellt integrierte Stabilität für Fehler auf Knotenebene bereit. Alle Schreibvorgänge in eine Datenbank werden automatisch mithilfe einer Quorum-Commit-Technik auf zwei oder mehr Hintergrundknoten repliziert (das primäre und mindestens ein sekundäres Replikat müssen bestätigen, dass die Aktivität in das Transaktionsprotokoll geschrieben wird, bevor die Transaktion als erfolgreich angesehen wird). Im Falle eines Knotenfehlers führt die Datenbank automatisch ein Failover auf eines der sekundären Replikate aus. Dies verursacht eine vorübergehende Verbindungsunterbrechung für Clientanwendungen - einer der Schlüsselgründe dafür, dass alle SQL-Datenbankclients eine Form der vorübergehenden Verbindungsverarbeitung implementieren müssen (weitere Informationen zum Implementieren der vorübergehenden Verbindungsbehandlung finden Sie weiter unten).

Die monatliche Verfügbarkeits-SLA für die Betriebszeit beträgt 99,9 %, definiert als die Fähigkeit, eine Verbindung zur SQL-Datenbank innerhalb von 30 Sekunden in einem 5-Minuten-Intervall herzustellen. Die Failoverereignisse, die im vorherigen Abschnitt beschriebenen wurden, treten in der Regel in weniger als 30 Sekunden auf und verstärken den Bedarf der Verarbeitung vorübergehender Verbindungsfehler durch die Anwendung.

Die SQL-Datenbank stellt einen Einblick in die Integrität und Leistung durch dynamische Verwaltungsansichten (DMVs) bereit; diese DMVs enthalten Informationen zu Hauptaspekten des Systems, wie Abfrageleistung, Datenbank- und Tabellengröße usw. Anwendungen sind für das regelmäßige Sammeln und Analysieren von Informationen aus den zentralen DMVs und für das Integrieren in das breitere Telemetrie- und Übersichtsframework verantwortlich.

Es gibt mehrere Optionen für Geschäftskontinuität (Sicherung, Wiederherstellung), die für die SQL-Datenbank verfügbar sind. Datenbanken können über die Funktion Datenbankkopie oder den DAC-Import/-Exportdienst kopiert werden. Datenbankkopie stellt im Gegensatz zu Bacpac (durch den Import-/Exportdienst) transaktionskonsistente Ergebnisse bereit. Beide Optionen werden als Warteschlangendienste im Rechenzentrum ausgeführt und stellen aktuell keine Verarbeitungsdauer-SLA bereit.

Beachten Sie, dass der Datenbankkopie- und -import-/-exportdienst die Quelldatenbank stark belasten und Ressourcenkonflikt- oder -Einschränkungsereignisse (im Abschnitt zu freigegebenen Ressourcen und Einschränkungen weiter unten beschrieben) auslösen kann. Während keiner dieser Ansätze denselben Grad der inkrementellen Sicherung bereitstellt, der von SQL Server unterstützt wird, wird derzeit eine neue Funktion entwickelt, um ein Zeitpunktwiederherstellungsfunktion zu ermöglichen. Die Zeitpunktwiederherstellungsfunktion ermöglicht es Benutzern, ihre Datenbank auf einen bestimmten Zeitpunkt innerhalb der letzten 2 Wochen wiederherzustellen.

Die einzige zurzeit unterstützte Authentifizierungstechnik ist die SQL-Authentifizierung, Einfaktoranmeldungen mit Benutzername/Kennwort, die auf registrierte Benutzer in der Datenbank basieren. Active Directory oder Zweifaktor-Authentifizierungsfunktionen sind noch nicht verfügbar. Es wird dringend empfohlen, die Verschlüsselung der Verbindung mit der SQL-Datenbank mithilfe der integrierten Verschlüsselungsunterstützung zu verwenden, die in ADO.NET, ODBC usw. verfügbar ist. Berechtigungen auf Datenbankebene sind mit SQL Server identisch. Eine Erläuterung der Einrichtung der Azure SQL-Datenbanksicherheit finden Sie unter Verwalten von Datenbanken und Anmeldungen in der Azure SQL-Datenbank.

Die SQL-Datenbank stellt umfangreiche dynamische Verwaltungsansichten zum Verfolgen von Abfrageleistung und Datenbankzustand bereit. Es wird jedoch keine automatische Infrastruktur zum Erfassen und Analysieren dieser Daten bereitgestellt (und vertraute Tools, z. B. ein direkt angeschlossener Profiler und Leistungsindikatoren auf Betriebssystemeben, sind nicht verfügbar). Ansätze zum Erfassen und Analysieren werden im Telemetrieabschnitt dieses Dokuments beschrieben.

Wie oben beschrieben, ist SQL-Datenbank ein mehrinstanzfähiger Dienst auf einer freigegebenen Infrastruktur. Datenbanken von unterschiedlichen Mandanten nutzen die zugrunde liegenden physischen Knoten, die auf Standardhardware betrieben werden, gemeinsam. Andere Benutzer des Systems können wichtige Ressourcen (Workerthreads, Transaktionsprotokoll, E/A usw.).auf der gleichen zugrunde liegenden Infrastruktur nutzen. Die Ressourcennutzung wird gesteuert und gestaltet, um Datenbanken innerhalb von festgelegten Ressourcengrenzen zu halten. Wenn diese Grenzen auf Ebene eines Mandanten oder des physischen Knotens überschritten werden, reagiert die SQL-Datenbank mit dem Einschränken der Nutzung oder dem Unterbrechen von Verbindungen. Diese Grenzen werden in der Tabelle unten aufgelistet.

 

Ressource Maximalwert pro Transaktion/Sitzung Maximalwert pro physischem Knoten Weicher Drosselungsgrenzwert Harter Drosselungsgrenzwert

Arbeitsthreads

Nicht zutreffend

512

305

410

Datenbankgröße

Konfigurierte maximale Größe bis zu 150 GB pro Datenbank

Nicht zutreffend

Kein(e)

100%; Einfüge- oder Updatevorgänge werden nach Erreichen des Grenzwerts nicht akzeptiert

Transaktionsprotokollwachstum

2 GB pro Transaktion

500 GB

Nicht zutreffend

Nicht zutreffend

Transaktionsprotokolllänge

20 % des gesamten Protokollspeicherplatzes (100 GB)

500 GB

Nicht zutreffend

Nicht zutreffend

Protokollanzahl

1 Million pro Transaktion

Nicht zutreffend

Nicht zutreffend

Nicht zutreffend

Blockieren von Systemtasks

20 Sekunden

Nicht zutreffend

Nicht zutreffend

Nicht zutreffend

Temp DB-Speicherplatz

5 GB

Nicht zutreffend

Nicht zutreffend

5 GB

Arbeitsspeicher

Nicht zutreffend

Nicht zutreffend

Nicht zutreffend

16 MB innerhalb von 20 Sekunden

Maximale Anzahl von gleichzeitigen Anforderungen

400 pro Datenbank

Nicht zutreffend

Nicht zutreffend

Nicht zutreffend

Wenn eine Transaktionsgrenze erreicht wird, antwortet das System, indem die Transaktion abgebrochen wird. Wenn eine Datenbank eine weiche Drosselungsgrenze erreicht, werden Transaktionen und Verbindungen verlangsamt oder abgebrochen. Das Erreichen einer festen Drosselungsgrenze wirkt sich auf alle Datenbanken (und Benutzer) auf dem zugrunde liegenden physischen Knoten aus, sodass vorhandene Vorgänge beendet werden neue Vorgänge oder Verbindungen verhindert werden, bis die Ressource unter den Drosselungsschwellenwert fällt.

Einige dieser Drosselungsgrenzen führen möglicherweise zu nicht intuitiven Einschränkungen des Entwurfs und der Leistung einer Anwendung. Beispielsweise verhindert das Einschränken des Transaktionsprotokollwachstums auf maximal 2 GB pro Transaktion das Erstellen eines Index für eine große Tabelle (wobei das Erstellen des Index ein Transaktionsprotokoll generiert, das größer als 2 GB ist). Techniken zum Ausführen solcher Vorgänge werden im Abschnitt zu den bewährten Vorgehensweisen dieses Dokuments erläutert.

Die Verarbeitung dieser Typen von Einschränkungsbedingungen und vorübergehenden Fehlern erfordert einen vorsichtigen Entwurf und eine vorsichtige Implementierung des Clientcodes; dafür ist das horizontale Skalieren der Datenbankebene erforderlich, um mehrere Datenbanken gleichzeitig zu nutzen (das horizontale Skalieren wird im nächsten Abschnitt erläutert).

Der SQL Client-Anwendungscode sollte Folgendes leisten:

  • Implementieren eines Wiederholungscodes, der die SQL-Fehlercodes berücksichtigt, die sich auf das Einschränken beziehen und entsprechende Backofflogik bereitstellen. Ohne eine Backofflogik in der Anwendung können Sie die Datenbank in einen kontinuierlichen Einschränkungsstatus sperren, indem Sie ständig Spitzenlast an die Datenbank weiterleiten.

  • Protokollieren von Einschränkungsfehlern mithilfe des Wiederholungscodes, um zwischen vorübergehender Verbindung, Einschränkung und Systemausfall zu unterscheiden – Syntax, gespeicherte Prozeduren usw. Dies hilft bei der Nachverfolgung und Problembehandlung von Problemen mit der Anwendungsverfügbarkeit.

  • Implementieren eines Sicherungsmusters. Wenn eine entsprechend ausgewählte Wiederholungsrichtlinie abgelaufen ist (Latenzzeit und Systemantwort im Verhältnis zur Anzahl der Wiederholungsversuche der Anwendung), wird ein Codepfad aufgerufen, um den nicht vorübergehenden Fehler zu behandeln (Auslösen der Sicherung). Der Anwendungscode kann dann Folgendes:

    • Fallback auf einen anderen Dienst oder Ansatz. Wenn die Anwendung keine neue Daten in die SQL-Datenbank einfügen kann (und die Daten nicht sofort verfügbar sein müssen), können die Daten stattdessen in eine DataTable (oder ein anderes XML-/JSON-Format) serialisiert und in eine Datei im BLOB-Speicher geschrieben werden. Die Anwendung kann dem Benutzer (oder API-Aufruf) dann einen Erfolgscode zurückgeben und die Daten später in die Datenbank einfügen.

    • Ohne Benachrichtigung fehlgeschlagen, indem ein NULL-Wert zurückgegeben wird, wenn die Daten oder der Workflow optional waren (wirkt sich nicht auf die Benutzerfreundlichkeit aus).

    • Schnell fehlschlagen, indem ein Fehlercode zurückgegeben wird, wenn kein nützlicher/passender Fallbackmechanismus verfügbar ist.

Die SQL-Datenbank kann problemlos viele relativ kleine Skalierungseinheiten (Datenbanken) bereitstellen. Das Implementieren von Anwendungen mit hoher Skalierbarkeit auf Azure unter Verwendung der SQL-Datenbank erfordert einen Ansatz für horizontales Skalieren, bei dem die Ressourcen mehrerer Datenbanken zusammengesetzt werden, um einen variablen Bedarf zu befriedigen. Wenn die Anwendungen bisher auf die "Titaneierschale" eines einzelnen, stabilen Datenbankservers mit horizontaler Skalierung ausgerichtet waren, ist ein durchdachter Entwurf erforderlich, um Anwendungen dazu zu bringen, einen Datenbankdienst mit horizontaler Skalierung effizient zu nutzen.

Mit der SQL-Datenbank sind, wie bei den anderen Azure-Kerndiensten, horizontale Skalierung und Zusammensetzung die Schlüssel für weitere Skalierungen (Datenbankgröße, Durchsatz) und Ressourcen (Workerthreads usw.). Es gibt zwei Kernansätze zur Implementierung der Partitionierung/Sharding (und somit für horizontales Skalieren) für die SQL-Datenbank; diese Ansätze schließen sich innerhalb einer Anwendung nicht gegenseitig aus:

  • Horizontale Partitionierung. In einem horizontalen Partitionierungsansatz werden intakte Tabellen oder Datasets in einzelne Datenbanken aufgeteilt. Beispielsweise kann für eine mehrinstanzenfähige Anwendung, die verschiedene Kundengruppen verarbeitet, eine Datenbank pro Kunde erstellen. Für eine größere Einzelmandantenanwendung kann sich die Kundentabelle auch in einer anderen Datenbank als in der befinden, in der sich die Tabelle mit den Bestellungen befindet. Der Partitionierungsschlüssel ist in der Regel der Mandantenbezeichner (z. B Kunden-ID). Im Diagramm unten ist das Dataset horizontal in drei verschiedene Datenbanken partitioniert, wobei ein Hash der E-Mail als Partitionswert verwendet wird (das heißt, der Partitionsschlüssel ist die E-Mail, die Partitionsfunktion verwendet einen Hash des Schlüssels für die Zuordnung zu einer Zieldatenbank).

  • Vertikale Partitionierung. In einem vertikalen Partitionierungsansatz wird ein Dataset über mehrere physische Tabellen oder Datenbanken hinweg basierend auf der Schemapartitionierung verteilt. Kundendaten und Auftragsdaten können beispielsweise auf unterschiedliche physische Datenbanken verteilt werden. Im folgenden Diagramm wird das Dataset vertikal in zwei verschiedene Datenbanken partitioniert. Zentrale Benutzerinformationen (Name, E-Mail) werden in DB1 gespeichert, während die Benutzerprofilinformationen (wie die URI für das Avatarabild) in DB2 gespeichert werden.

Viele Anwendungen verwenden eine Mischung aus horizontaler und vertikaler Partitionierung (Hybridpartitionierung) und integrieren zusätzliche Speicherdienste. Im Beispiel oben wurden die Avatarabilder für Benutzer beispielsweise als IDs in der Datenbank gespeichert, die die Anwendung zu einer vollständigen URL erweitert. Diese URL wird dann einem Bild zugeordnet, das im BLOB gespeichert ist.

Beim Arbeiten mit einem horizontal skalierten relationalen Datenspeicher erfolgt die Verfügbarkeitsberechnung ganz anders. Systeme mit einer größeren Anzahl von Shards haben eine höhere Wahrscheinlichkeit, dass einzelne Datensegmente offline sind, und eine geringere Wahrscheinlichkeit, dass die gesamte Anwendung nicht verfügbar ist. Anwendungen müssen die Teilverfügbarkeit von Back-End-Datenspeichern berücksichtigen. Mit einem Datenmodell für horizontales Skalieren ist Datenverfügbarkeit keine Alles-oder-nichts-Bedingung mehr.

Das Neupartitionieren von Daten kann herausfordernd sein, insbesondere wenn sich das Verwendungsmodell oder Verteilung der Daten im Laufe der Zeit ändert. Bereichsbasierte Partitionierungsschlüssel, die auf einer festen Anzahl (mithilfe eines Modulos des Hashs der Partitionierungswerte) oder auf der Verteilung der Partitionierungswerte basieren, erfordern das erneute Verteilen von Daten auf einzelne Shards. Bereichsbasierte Partitionsschemas nutzen häufig binäre Teilungen oder Zusammenfügungen, um Neuverteilungsvorgänge zu vereinfachen.

Beispielsweise beginnen Partitionierungsmethoden mit festem Bereich (wie der erste Buchstabe des Nachnamen) als ausgeglichene Verteilung, können sich aber schnell zu einer unausgeglichenen Verteilung entwickeln, wenn neue Benutzer hinzukommen (wobei die Benutzer eigene Nachnamen mitbringen, die gleichmäßig über das Alphabet verteilt sein können aber nicht müssen). Beachten Sie das Potenzial der Anforderung im Zeitverlauf zum Anpassen des Partitionierungsmechanismus und der Kosten für das erneute Verteilen von Daten.

Suchbasierte Partitionierungsschemas sind schwieriger zu implementieren und erfordern einen leistungsstarken Suchmechanismus für jeden Datenmandanten oder jede Partition, sind aber präziser neu zu verteilen, da sie es zuzulassen, dass ein einzelner Mandant individuell auf einer neuen Partition neu verteilt wird. Sie ermöglichen aus, dass zusätzliche Kapazitäten (neue Datenbanken usw.) dem System hinzugefügt werden, ohne dass Daten kopiert werden müssen.

Unabhängig von der Mischung der Sharding-Ansätze bringt der Übergang zu einer horizontalen Skalierung relationaler Shard-Datenbanken bestimmte Einschränkungen mit sich, die einen anderen Ansatz für Datenverwaltung und -abfrage erfordern:

  • Traditionell "gute" Entwürfe für SQL-Datenspeicherung und -abfrage wurden für Speicherung und Konsistenz optimiert, indem stark normalisierte Datenmodelle genutzt werden. Dieser Ansatz nimmt einen global zusammenhängenden Datenbereich an und nutzt Querverweise und JOINs zwischen Tabellen. Mit Daten, die über physisch verteilte Knoten verteilt sind, sind JOINs und Querverweise nur innerhalb einer einzelnen Shard sinnvoll. Die SQL-Datenbank unterstützt keine verteilten Abfragen über mehrere Datenbanken hinweg; die Datenzusammenfügung muss auf der Clientebene erfolgen, und die Denormalisierung und Replikation von Daten muss über Shards hinweg erfolgen.

  • Verweisdaten und Metadaten werden in der Regel in Verweistabellen zentralisiert. Bei einem Ansatz mit horizontalem Skalieren müssen diese Verweistabellen und alle Daten, die nicht vom allgemeinen Partitionierungsschlüssel getrennt werden können, über Shards hinweg repliziert und konsistent gehalten werden.

  • Es gibt keine praktische Möglichkeit, skalierbare, leistungsstarke verteilte Transaktionen über Shards hinweg bereitzustellen; Daten (und Schemaupdates!) sind zwischen Shards niemals transaktionskonsistent. Anwendungscode muss einen Grad an "freier" Konsistenz zwischen Shards annehmen und berücksichtigen.

  • Der Anwendungscode muss den Shardingmechanismus (horizontaler / vertikaler Partitionierungstyp) interpretieren können, um eine Verbindung zu den jeweiligen Shards herzustellen.

  • Allgemeine objektrelationale Mappings (ORMs), wie Entity Framework, verstehen Datenmodellen mit horizontaler Skalierung nicht automatisch. Anwendungen, die häufig umfangreiche ORMs nutzen, müssen daher möglicherweise signifikant umgestaltet werden, damit sie mit dem horizontalen Sharding kompatibel sind. In Entwürfen, bei denen Mandanten (Kundensätze) in einem Ansatz mit vertikalem Sharding in einer einzelnen Datenbank isoliert werden, sind meist weniger Änderungen auf Datenzugriffsebene erforderlich. Der Nachteil eines rein vertikalen Shardingmodells besteht darin, dass jeder einzelne Shard durch die Kapazität der jeweiligen Datenbank beschränkt ist.

  • Abfragen, die mehrere Shards betreffen (Lesen oder Schreiben), müssen mit einem Scatter-Gather-Muster realisiert werden, bei dem separate Abfragen der Zielshards ausgeführt und der Ergebnissatz auf Clientdatenzugriffsebene zusammengestellt wird.

Das horizontale Skalieren erfolgt bei SQL-Datenbanken, indem Daten über mehrere SQL-Datenbanken manuell bzw. horizontal partitioniert werden (Sharding). Dieser Ansatz der horizontalen Skalierung ermöglicht einen nahezu linearen Kostenanstieg mit Skalierung. Flexibles Wachstum oder bedarfsgesteuerte Kapazität können bei Bedarf gegen Mehrkosten erweitert werden. Nicht alle Anwendungen unterstützen dieses Modell der horizontalen Skalierung ohne umfangreiche Umgestaltung.

  • Schemaupdates sind nicht notwendigerweise transaktionskonsistent, insbesondere wenn eine große Anzahl von Shards aktualisiert wird. Anwendungen müssen entweder geplante Ausfallzeiten in Kauf nehmen oder über mehrere parallele Versionen des bereitgestellten Schemas verfügen.

  • Geschäftskontinuitätsprozesse (z. B. Sicherung/Wiederherstellung) müssen mehrere Datenshards berücksichtigen.

Die Entwurfsempfehlungen und bewährten Vorgehensweisen angesichts dieser Herausforderungen werden im Abschnitt 'Bewährte Vorgehensweisen' dieses Dokuments behandelt.

Im Rest des Dokuments werden bewährte Vorgehensweisen für die Bereitstellung hochskalierbarer Anwendungen mit Azure und SQL-Datenbanken auf der Grundlage praktischer Erfahrungen und den daraus gezogenen Schlussfolgerungen veranschaulicht. Zu jeder bewährten Vorgehensweise werden die angestrebten Optimierungen und Komponenten, der Implementierungsansatz und die damit verbundenen Vorteile erläutert. Wie bei jeder bewährten Vorgehensweise sind diese Empfehlungen stark vom Kontext abhängig, in dem sie angewendet werden. Bewerten Sie jede bewährte Vorgehensweise hinsichtlich ihrer Eignung ausgehend von den konkreten Plattformfunktionen, wie im vorherigen Abschnitt erläutert wurde.

noteHinweis
Diese Erfahrungen gehen auf verschiedene Kundeninteraktionen zurück, die nicht dem klassischen OLTP-Muster (Onlinetransaktionsverarbeitung) folgen. Beachten Sie, dass einige dieser bewährten Vorgehensweisen möglicherweise nicht direkt auf Anwendungen anwendbar sind, die eine strenge Datenkonsistenz erfordern. Nur Sie kennen die genauen geschäftlichen Anforderungen Ihrer Anwendung und Umgebung.

Jede bewährte Vorgehensweise bezieht sich auf einen oder mehrere Optimierungsaspekte:

  • Durchsatz. So erhöhen Sie die Anzahl der Vorgänge (Transaktionen, Dienstaufrufe usw.) über das System und reduzieren Konflikte.

  • Latenzzeit. So reduzieren Sie die Latenzzeit bei aggregierten und individuellen Vorgängen.

  • Dichte. So reduzieren Sie Konfliktpunkte bei der Erstellung von Diensten in direkten Kontexten (beispielsweise Anwendungscode zu SQL-Datenbank) und aggregierten Kontexten (Verwendung mehrerer Speicherkonten für erweiterte Skalierbarkeit).

  • Verwaltbarkeit. Diagnose, Telemetrie und Einblicke ‑ So ermitteln Sie den Zustand und die Leistung Ihrer bereitgestellten Dienste mit Skalierung.

  • Verfügbarkeit. So erhöhen Sie die allgemeine Anwendungsverfügbarkeit durch Verringerung der Auswirkungen von Fehlerpunkten und Modi (Verfügbarkeit unter Last wird unter Durchsatz/Latenzzeit/Dichte abgedeckt).

Eine Grundvoraussetzung in Azure sind der sorgfältige Entwurf und die sorgfältige Bereitstellung von gehosteten Dienste für hochskalierbare, hochverfügbare Dienste.

  • Die Anzahl der Instanzen und Upgradedomänen innerhalb eines gehosteten Dienstes kann sich maßgeblich auf die zum Bereitstellen, Konfigurieren und Aktualisieren des gehosteten Dienstes benötigte Zeit auswirken. Setzen Sie die Leistungs- und Skalierbarkeitsvorteile mit der höheren Komplexität in Bezug, die erforderlich ist, um diese Vorteile zu erreichen. Eine Verbesserung von Skalierbarkeit und Flexibilität geht im Allgemeinen mit höheren Entwicklungs- und Verwaltungskosten für die Lösung einher.

  • Vermeiden Sie Einzelinstanzrollen. Eine solche Konfiguration erfüllt nicht die Anforderungen des Azure-SLA. Während eines Knotenfehlers oder Upgradeereignisses wird eine Einzelinstanzrolle offline geschaltet. Verwenden Sie diese daher nur für 'Verwaltungsaufgaben' mit niedriger Priorität.

  • Jedes Rechenzentrum hat eine beschränkte (wenn auch große) Kapazität und kann in seltenen Fällen zur Fehlerquelle werden. Dienste, die eine maximale Skalierung und Verfügbarkeit benötigen, müssen eine Mehrfachrechenzentrumstopologie mit mehreren gehosteten Dienste implementieren. Aber:

  • Wenn die maximale Verfügbarkeit nicht benötigt wird (siehe letzten Punkt), müssen Sie sicherstellen, dass sich die Anwendungen und abhängigen Dienste vollständig innerhalb eines einzelnen Rechenzentrums befinden. Beachten Sie in Fällen, in denen die Lösung mehrere Rechenzentren benötigt, folgende Richtlinien:

    • Vermeiden Sie rechenzentrumsübergreifende Netzwerkaufrufe für aktive Vorgänge (außerhalb der geplanten siteübergreifenden Synchronisierung). Langstreckenlatenzzeiten zwischen Rechenzentren können stark variieren und zu unerwarteten oder unerwünschten Anwendungsleistungsmerkmale führen.

    • Es sollten so wenige Funktionen wie möglich auf Dienste in anderen Rechenzentren zugreifen. In der Regel betrifft dies Aktivitäten im Zusammenhang mit Geschäftskontinuität und Datenreplikation.

Für große verteilte Anwendungen ist der Zugriff auf zustandsbehaftete Anwendungsdaten wichtig. Der Anwendungsdurchsatz und die Latenzzeit werden in der Regel dadurch beschränkt, wie schnell die erforderlichen Daten und der Kontext abgerufen, freigegeben und aktualisiert werden können. Als Reaktion hierauf wurden verteilte Cachedienste entwickelt, wie Azure Caching und memcached. Anwendungen sollten eine verteilte Cacheplattform nutzen. Beachten Sie die folgenden Richtlinien:

  • Nutzen Sie eine verteilte Cacheplattform als Workerrolle innerhalb des gehosteten Dienstes. Die große Nähe zu den Clients des Caches reduziert die Latenzzeit und Durchsatzbarrieren, die beim Durchlaufen des Lastenausgleichs entstehen. Der rolleninterne Cache im Azure-Cache hostet das Caching für Workerrollen innerhalb des Cloud-Diensts.

  • Verwenden Sie die verteilte Cacheplattform als primäres Repository für den Zugriff auf allgemeine Anwendungsdaten und -objekte (z. B. Benutzerprofil und Sitzungsstatus) mit Unterstützung der SQL-Datenbank oder eines anderen permanenten Speichers in einem Nur-Lese- oder cachefremden Ansatz.

  • Cacheobjekte haben eine Laufzeit, die bestimmt, wie lange sie in dem verteilten Cache aktiv sind. Anwendungen legen die Laufzeit der gecachten Objekte entweder explizit fest oder konfigurieren eine Standardlaufzeit für den Cachecontainer. Wägen Sie bei der Laufzeit zwischen Verfügbarkeit (Cachetreffer) und Arbeitsspeicherlast sowie Überalterung der Daten ab.

  • Caches weisen eine 'key->byte[]'-Semantik auf. Seien Sie sich der Möglichkeit bewusst, dass überlappende Schreibvorgänge inkonsistente Daten im Cache produzieren können. Verteilte Caches stellen im Normalfall keine API für unteilbare Updates gespeicherter Daten bereit, da sie die Struktur von gespeicherten Daten nicht erkennen.

    • Verwenden Sie bei Anwendungen, die eine strikte Konsistenz gleichzeitiger Schreibvorgänge erfordern, eine Cacheplattform mit einem Sperrmechanismus für die Updates von Entitäten. Im Fall von Azure Caching wird dies mittels GetAndLock/ PutAndUnlock implementiert. Hinweis: Hierdurch wird der Durchsatz beeinträchtigt.

  • Die Cacheleistung ist auf Anwendungsebene durch die erforderliche Zeit zum Serialisieren und Deserialisieren von Objekten beschränkt. Nutzen Sie zum Optimieren dieses Prozesses ein relativ symmetrisches (dieselbe Zeit zum Codieren/Decodieren von Daten), hocheffizientes binäres Serialisierungsprogramm wie protobuf.

    • Um die benutzerdefinierte Serialisierung erfolgreich zu verwenden, entwerfen Sie die Datenübertragungsobjekte (DTOs) für die Serialisierung im Cache, verwenden Sie ordnungsgemäße Anmerkungen für die Serialisierung, vermeiden Sie zyklische Abhängigkeiten und verwenden Sie Komponententests zur Nachverfolgung einer effizienten Serialisierung.

Standardmäßig sind Verbindungen zwischen Dienstebenen (einschließlich eingehender Verbindungen über den Lastenausgleich) abhängig von einem Roundrobin-Zuordnungsschema mit restriktiver Verbindungsfesthaltung. Die folgenden Diagramme veranschaulichen ein typisches Verbindungsgitter zwischen Ebenen und externen Diensten (die linke Seite zeigt eine typische Anwendung auf Webebene). Diese Gitter zieht zwar keine nennenswerten Leistungsprobleme für einfache Verbindungsprotokolle (wie HTTP) nach sich, bestimmte Verbindungen sind jedoch aufwendig herzustellen/zu initialisieren oder stellen eine geregelte (begrenzte) Ressource dar. In diese Kategorie fallen beispielsweise SQL-Datenbankverbindungen. Um die Auslastung dieser externen Dienste und Komponenten zu optimieren, wird empfohlen, Ressourcenaufrufe bestimmten Instanzen zuzuordnen.

In der obigen Abbildung hat die Topologie rechts separate Web- und Workerebenen (Rollen) innerhalb desselben gehosteten Dienstes. Zudem hat diese Topologie eine implementierte Affinität zwischen Web- und Anwendungsschicht, um Aufrufe bestimmter Datenbanken von bestimmten Anwendungsinstanzen festzuhalten. Um beispielsweise Daten aus Datenbank 1 (DB1) abzufragen, müssen Webinstanzen die Daten über die Anwendungsinstanzen 1 oder 2 anfordern. Da der Azure-Lastenausgleich derzeit nur eine Roundrobin-Technik implementiert, erfordert die Bereitstellung von Affinität in der Anwendung einen sorgfältigen Entwurf und eine sorgfältige Implementierung.

  • Entwerfen Sie die Anwendung mit separaten Web- und Anwendungsebenen, die partitions- oder ressourcenbewusste Affinität zwischen der Web- und Anwendungsebene liefern.

  • Implementieren Sie Routinglogik, die dienstinterne Aufrufe transparent zu einer Zielanwendungsinstanz weiterleitet. Verwenden Sie die Informationen des Partitionierungsmechanismus, der von den externen oder nachgeschalteten Ressourcen verwendet wird (z. B. SQL-Datenbank).

Die praktische Implementierung dieser Multi-Tier-Architektur erfordert eine hocheffiziente Dienstkommunikation zwischen Web- und Anwendungsebene mittels einfacher und effizienter Protokolle.

Die Entwicklungstechniken für eine Azure-Anwendung unterscheiden sich nicht grundlegend von den Entwicklungstechniken für Windows Server. Die elastische Struktur verdeutlich jedoch die Notwendigkeit und die Vorteile von effizientem Code, der die Verarbeitungsressourcen möglichst effektiv nutzt.

  • Angenommen alle Dienste, Netzwerkaufrufe und abhängigen Ressourcen sind potenziell unzuverlässig und anfällig für vorübergehende und fortlaufende Fehlermodi (z. B. die Implementierung von Wiederholungslogik für SQL-Datenbanken, die im nachfolgenden Abschnitt erläutert wird):

    • Implementieren Sie geeignete Wiederholungrichtlinien für alle Dienstaufrufen (SQL-Datenbank, Speicher usw.), um vorübergehende Fehlerbedingungen und Konnektivitätsverluste zu handhaben.

    • Implementieren Sie Backoffrichtlinien in der Wiederholungslogik, um 'Konvoieffekte' zu vermeiden (Ansammlung von Wiederholungen für den Dienst, durch die Ausfälle verlängert werden).

    • Implementieren Sie eine umfangreiche clientseitige Telemetrie für die Protokollierung von Fehlermeldungen und Fehlerereignissen mit Kontextinformationen (Zieldienst, Benutzer-/Kontokontext, Aktivität usw.).

  • Erstellen Sie Threads zum Planen der Arbeit nicht direkt. Nutzen Sie stattdessen ein Planungs- und Parallelitätsframework wie .NET Task Parallel Library. Threads sind relativ große Objekte und nicht leicht zu erstellen und freizugeben. Zeitplanungsmodule, die einen freigegebenen Threadpool nutzen, können Arbeit effizienter planen und ausführen. Diese Architektur stellt zudem eine übergeordnete Semantik zum Beschreiben der Fortsetzung und Fehlerbehandlung bereit.

  • Optimieren Sie die Datenübertragungsobjekte (DTOs) für Serialisierung und Netzwerkübertragung. Angesicht des hohen Maßes an Verteilung von Azure-Anwendungen wird die Skalierbarkeit dadurch beschränkt, wie effizient die einzelnen Komponenten des Systems über das Netzwerk kommunizieren können. Alle Daten, die zu Kommunikations- oder Speicherzwecken über das Netzwerk übertragen werden, sollten JSON-Textserialisierung oder ein effizienteres binäres Format mit entsprechenden Hinweisen implementieren, um die Menge der Metadaten zu minimieren, die über das Netzwerk übertragen werden (z. B. kürzere Feldnamen).

    • Wenn Interoperation wichtig ist, verwenden Sie ein effizientes Textformat, wie JSON, für Interoperabilität und In-Band-Metadaten.

    • Ist ein höherer Durchsatz erforderlich, wie beispielsweise bei der Kommunikation zwischen Diensten, deren beide Enden Sie kontrollieren, sollten Sie ein hocheffizientes, komprimiertes Binärformat, wie bson oder protobuf, in Betracht ziehen.

      • Vermeiden Sie 'geschwätzige' (häufige) Datenübertragungen von kleinen Objekten (Chattiness). Eine solche 'geschwätzige' Kommunikation zwischen Diensten verschwendet beträchtliche Systemressourcen für aufwendige Aufgaben und ist anfällig für Antworten mit variabler Latenzzeit.

      • Tests der Serialisierung und Deserialisierung von Objekten sollten eine Kernkomponente des automatisierten Testframeworks sein. Funktionalitätstests stellen sicher, dass Datenklassen serialisierbar sind und dass keine zyklischen Abhängigkeiten vorhanden sind. Leistungstests überprüfen die erforderlichen Latenzzeiten und Codierungsgrößen.

  • Falls möglich, nutzen Sie einfache Frameworks für die Kommunikation zwischen Komponenten und Dienste. Viele herkömmliche Technologien im .NET-Stapel stellen vielfältige Funktionen bereit, die möglicherweise nicht auf die verteilte Struktur von Azure abgestimmt sind. Komponenten mit einem hohem Maß an Abstraktion zwischen Zweck und Ausführung gehen häufig mit hohen Leistungseinbußen einher.

    • Wenn eine Protokollinteroperation oder erweiterte Protokollunterstützung nicht benötigt wird, sollten Sie bei der Implementierung von Web-Services die ASP.NET-Web-API anstelle von WCF für die Untersuchung verwenden.

    • Sollten Sie die umfangreichen Funktionen von Entity Framework nicht benötigen, führen Sie die Untersuchung mithilfe eines Micro-ORM, wie Dapper, durch, um die SQL-Clientebene zu implementieren.

  • Reduzieren Sie die aus dem Rechenzentrum bereitgestellte Datenmenge, indem Sie die HTTP-Komprimierung in IIS für ausgehende Daten aktivieren.

  • Ordnen Sie Verbindungen zwischen Ebenen zu, um 'Chattiness' und Kontextwechsel von Verbindungen zu reduzieren.

  • Um die Auslastung der Anwendung zu verringern, verwenden Sie zum Bereitstellen umfangreicher statischer Inhalte (> 100 KB) einen BLOB-Speicher.

  • Um die Auslastung der Anwendung zu verringern, verwenden Sie zum Bereitstellen statischer Inhalte, wie Images oder CSS, das Netzwerk für die Inhaltsübermittlung (CDN) über BLOB-Speicher.

  • Verwenden Sie die SQL-Datenbank nicht für Sitzungsdaten. Nutzen Sie stattdessen einen verteilten Cache oder Cookies.

Azure-Speicher ist der beständige Datenbackbone in einer Azure-Anwendung. Anspruchsvolle Anwendungen sorgen zwar unmittelbar für eine höchst zuverlässige und skalierbare Benutzererfahrung, sie erfordern jedoch angemessene Entwurfs- und Verwendungsrichtlinien.

  • Nutzen Sie mehrere Speicherkonten für eine höhere Skalierbarkeit, entweder für größere Größen (> 100 TB) oder einen höheren Durchsatz (> 5.000 Vorgänge pro Sekunde). Stellen Sie sicher, dass der Anwendungscode für die Verwendung mehrerer Speicherkonten konfiguriert werden kann, einschließlich geeigneter Partitionierungsfunktionen zum Weiterleiten von Arbeit an die Speicherkonten. Planen Sie die Möglichkeit zum Hinzufügen weiterer Speicherkonten als Konfigurationsänderung, nicht als Codeänderung ein.

  • Wählen Sie die Partitionierungsfunktionen für Tabellenspeicher sorgfältig aus, um die gewünschte Skalierung hinsichtlich Einfüge- und Abfrageleistung zu erreichen. Streben Sie einen zeitbasierten Partitionierungsansatz für Telemetriedaten mit zusammengesetzten Schlüsseln auf Grundlage von Zeilendaten nach nicht zeitliche Daten an. Achten Sie darauf, dass die Partitionen in einem geeigneten Größenbereich liegen, um eine optimale Leistung zu erzielen. Sehr kleine Partitionen schränken die Möglichkeit ein, Batchvorgänge auszuführen (einschließlich Abfragen), während sehr große Partitionen mit Leistungseinbußen bei der Abfrage einher gehen (was Engpässe bei umfangreichen, gleichzeitigen Einfügevorgängen zur Folge haben kann).

    • Die Auswahl der Partitionierungsfunktion wirkt sich auch maßgeblich auf die Abfrageleistung aus. Tabellenspeicher ermöglicht eine effiziente Suche nach {Partitionsschlüssel, Zeilenschlüssel} mit weniger effizienter Verarbeitung von {Partitionsschlüssel, Zeilenabgleichungsfilter} und {Partitionsschlüsselabgleichungsfilter, Zeilenschlüsselabgleichungsfilter}. Abfragen, die einen globalen Tabellenscan erfordern ({Zeilenschlüsselabgleichungsfilter}).

    • Kleine Partitionen können aus einer einzelnen Entität bestehen. Dies bietet hochoptimierte Leistung für reine Sucharbeitslasten, z. B. bei der Einkaufswagenverwaltung.

  • Batchvorgänge im Speicher, wenn möglich. Schreibvorgänge in die Tabelle können als Batch ausgeführt werden, in der Regel mit der SaveChanges-Methode in der .NET-Client-API. Fügen Sie eine Reihe von Zeilen in eine Tabelle ein, und übergeben Sie die Änderungen dann in einem einzelnen Batch mit der SaveChanges-Methode. Updates des BLOB-Speichers sollten mithilfe der PutBlockList-Methode ebenfalls als Batch übergeben werden. Rufen Sie wie bei der Tabellenspeicher-API die PutBlockList-Methode für einen Bereich von Blöcken anstelle einzelner Blöcke auf.

  • Wählen Sie kurze Spaltennamen für Tabelleneigenschaften aus, da die Metadaten (Eigenschaftsnamen) 'in-band' gespeichert werden. Die Spaltennamen werden auf die maximale Zeilengröße von 1 MB angerechnet. Sehr lange Eigenschaftsnamen gehen zu Lasten der Systemressourcen.

Wie im Abschnitt 'Durchsuchen von Azure' erläutert, stellt die SQL-Datenbank eine sofort einsetzbare relationale Datenbank als Dienst bereit und ermöglicht so einen skalierbaren Zugriff auf die Datenspeicher in Form einer horizontalen Skalierung. Die erfolgreiche Verwendung der SQL-Datenbank in umfangreichen Anwendungen setzt eine sorgfältige Entwurfs- und Implementierungsauswahl voraus. In diesem Abschnitt werden die wichtigsten Entwurfsaspekte und bewährten Vorgehensweisen vorgestellt.

Viele Anwendungen erfordern eine Metadatentabelle zum Speichern von Details, wie Routing, Partitionierung und Mandanteninformationen. Durch das Speichern dieser Metadaten in einer einzelnen Datenbank entsteht sowohl eine Fehlerquelle als auch ein Skalierbarkeitsengpass. Zentrale Metadatenspeicher sollten mittels folgender Kombination horizontal skaliert werden:

  • Aggressives Caching. Die Informationen in der Konfigurationsdatenbank sollten strikt (aggressiv) in einem verteilten Cache zwischengespeichert werden (z. B. memcached oder Azure Caching).

    • Bedenken Sie die Auswirkungen, die das aggressive Laden des Caches aus mehreren Workerthreads beim Start der Anwendung haben kann. Dies führt in der Regel zu einer hohen Last und Datenbankeinschränkungen. Wenn Ihre Anwendung einen vorab geladenen Cache erfordert, delegieren Sie die Zuständigkeit für das Laden von Daten an eine dedizierte Workerrolle (bzw. geplante Task) mit einer konfigurierbaren Laderate.

    • Wenn die Anwendungsleistung oder -zuverlässigkeit vom Vorhandensein eines bestimmten Datensegments im Cache abhängt, kann die Anwendung eingehende Anforderungen ablehnen, bis der Cache aufgefüllt wurde. Die Anwendung sollte bis zum Laden der Daten eine entsprechende Fehlermeldung oder einen Code zurückgeben.

  • Horizontales Skalieren. Partitionieren Sie die Daten entweder vertikal (Tabelle) oder horizontal (Segmenttabelle über mehrere Shards), um die Last auf mehrere Datenbanken zu verteilen.

Die Gesamtskalierbarkeit einer partitionierten SQL-Datenbank wird von der Skalierung der einzelnen Datenbank (Shard) und von der Effizienz und Effektivität begrenzt, mit der diese Shards für ein höheres Maß an Skalierung zusammengestellt werden können:

  • Da die Transaktionsprotokollgrenzwerte größere Transaktionen, z. B. das Neuerstellen von Indizes, einschränken, sollten die einzelnen Tabellen ungefähr 10 GB nicht überschreiten (beachten Sie, dass der tatsächliche Grenzwert von der Größe der Zieltabellenindizes abhängt, sodass er für Ihre konkrete Datenbank mehr oder weniger als 10 GB betragen kann). Unterteilen Sie große Einzeltabellen in mehrere kleinere Tabellen, und verwenden Sie eine partitionierte Ansicht, um eine einheitliche Überlagerung bereitzustellen.

    • Indem die einzelnen Tabellen klein gehalten werden, verringern Sie die Auswirkungen einer Schemaänderung oder einer Indexneuerstellung während eines stufenweisen Upgrades. Änderungen an mehreren kleinen Tabellen minimieren die Ausfallzeit und Latenzzeit aufgrund von Sperrvorgängen.

    • Diese Partitionierung erschwert jedoch die Verwaltungsmethoden. Vorgänge wie das Neuerstellen des Indexes müssen iterativ für alle Komponententabellen ausgeführt werden.

  • Halten Sie die einzelnen Datenbanken (Shards) relativ klein. Kontinuitätsvorgänge wie das Kopieren von Datenbanken oder das Exportieren aus Datenbanken mit mehr als 50 GB können mehrere Stunden in Anspruch nehmen (der Dienst bricht Vorgänge nach 24 Stunden ab).

In einer Welt, in der Dienste kontinuierlich bereitgestellt werden, müssen verteilte Datenbankupdates oder Schemaänderungen mit der gebotenen Sorgfalt und Aufmerksamkeit verwaltet werden, um einen nahtlosen Upgradepfad zu gewährleisten. Alle herkömmlichen Methoden zur Kontrolle der Schema- und Metadatenvorgänge in einem Produktionsdatenspeicher sind wichtiger als je zuvor. Beispielsweise ist die Fehlerbehebung und Lösung bei einer versehentlich gelöschten gespeicherten Prozedur in 1 von 100 Datenbanken wesentlich komplexer.

Da Schemaupdates und Datenänderungen hinsichtlich der Transaktionen nicht über mehrere Shards hinweg konsistent sind, müssen Anwendungsupdates während der Übergangsphase mit den alten und den neuen Schemas kompatibel sein. Diese Anforderung bedeutet für gewöhnlich, dass jede Version der Anwendung mindestens mit der aktuellen Version und der Vorgängerversion des Schemas kompatibel sein muss.

Der Wechsel zu einer Datenbanksammlung mit horizontaler Skalierung geht mit gewissen Herausforderungen bei der Verbindungsverwaltung einher. Jede SQL-Datenbankverbindung ist eine relativ verarbeitungsintensive Ressource, was sich in der umfangreichen Verwendung von Verbindungspooling in Client-APIs zeigt (ADO.NET, ODBC, PHP usw.). Anstatt dass jede Anwendungsinstanz mehrere Verbindungen zu einem zentralen SQL-Server aufrecht erhält, muss jede Anwendungsinstanz Verbindungen zu mehreren Datenbankservern haben.

Da Verbindungen jedoch eine ressourcenintensive und möglicherweise knappe Ressource sind, müssen Anwendungen diese Verbindungen entsprechend verwalten, indem Poolverbindungen rechtzeitig zurückgegeben werden. Der Anwendungscode sollte eine automatische Verbindungsfreigabe verwenden. Eine bewährte Vorgehensweise in .NET ist, die gesamte Verwendung von SqlConnection in eine using-Anweisung einzuschließen. Beispiel:

using (var conn = new SqlConnection(connStr))
{
    // SQL client calls here
}

Wie bereits beschrieben, unterliegen die Verbindungen mit einer SQL-Datenbank vorübergehenden Verbindungsfehlern. Daher muss für alle Verbindungen und Befehle Wiederholungslogik zum Schutz vor diesen vorübergehenden Fehlern verwendet werden (weitere Informationen siehe unten).

SQL-Datenbanken unterstützen nur TCP-Verbindungen (keine Named Pipes), und es wird dringend empfohlen, die Verbindung zwischen Anwendungscode und SQL-Datenbank zu verschlüsseln. Um unbeabsichtigte Verbindungsversuche zu verhindern (z. B. die Verwendung von Named Pipes), sollten Anwendungen die SQL-Verbindungszeichenfolgen wie folgt formatieren:

Server=tcp:{servername}.database.windows.net,1433;Database={database};User ID={userid}@{database};Password={password};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;

Bei umfangreichen Anwendungsbereitstellungen kann die Standardanzahl von möglichen Verbindungen zwischen einer gehosteten Dienstbereitstellung und logischen SQL-Datenbankservern in einem SQL-Datenbankcluster (die jeweils eine einzelne externe IP-Adresse haben) exponentiell ansteigen. Nehmen Sie beispielsweise einen gehosteten Dienst mit 100 Instanzen, 50 Datenbanken und der Standardanzahl von Verbindungen, d. h. 100 Verbindungen in ADO.NET.

MaxConnections=DatabaseCount*Instance Count*MaxConnectionPoolSize

Schauen Sie sich die Netzwerktopologie für einen gehosteten Dienst an. Jede Seite der Verbindung (der gehosteten Dienst und der logische SQL-Datenbankserver) befindet sich hinter einem Azure-Lastenausgleich. . Jeder Azure-Lastenausgleich hat eine Obergrenze von 64.000 Verbindungen zwischen zwei beliebigen IPv4-Adressen. Die Kombination dieser Netzwerktopologie mit der Standardanzahl von verfügbaren Verbindungen führt bei größeren Anwendungen zu schweren Netzwerkfehlern.

  • Stellen Sie größere Anwendungen über mehrere gehosteten Dienste bereit.

  • Stellen Sie Datenbanken in mehreren Abonnements bereit (nicht nur mehrere logische Server im gleichen Abonnement), um eindeutigere IP-Adressen zu erhalten.

  • Implementieren Sie Anwendungen mit mehreren Ebenen, um ausgehende Vorgänge einer Zielanwendungsinstanz zuzuordnen (siehe vorheriger Abschnitt zu gehosteten Diensten).

  • Bedenken Sie, dass Verbindungspools pro eindeutiger Verbindungszeichenfolge verwaltet werden und jeweils einer eindeutigen Kombination aus Datenbankserver, Datenbank und Anmeldung entsprechen. Verwenden Sie SQL-Clientverbindungspooling, und schränken Sie die maximale Größe des SQL-Verbindungspools explizit ein. Die SQL Clientbibliotheken verwenden Verbindungen nach Bedarf erneut. Ein kleiner Verbindungspool kann zu potenziell höheren Latenzzeiten führen, während Anwendungen auf verfügbare Verbindungen warten.

Die folgende Liste enthält Empfehlungen zum Reduzieren der Anzahl von erforderlichen aktiven Verbindungen:

Der Wechsel zu einem verteilten Datenmodell kann Änderungen am Entwurfs- und Datenbankschema sowie Änderungen an bestimmten Abfragetypen erforderlich machen. Anwendungen, die die Verwendung von verteilten Transaktionen über mehrere Datenbanken erfordern, verfügen möglicherweise über ein ungeeignetes Datenmodell oder eine ungeeignete Implementierung (die z. B. versucht, globale Konsistenz zu erzwingen.) Diese Entwürfe müssen neu gestaltet werden.

Aufgrund von Verfügbarkeits- und Skalierbarkeitseinschränkungen sollte die Verwendung einer zentralen Sequenzgenerierungsfunktion für alle nicht trivialen Aspekte der Anwendung vermieden werden. Viele Anwendungen nutzen Sequenzen, um GUIDs (Globally Unique Identifier) bereitzustellen, wobei mithilfe eines zentralen Nachverfolgungsmechanismus die Sequenz bei Bedarf erhöht wird. Diese Architektur erzeugt einen globalen Konfliktpunkt und Engpass, mit denen sich jede Komponente des Systems auseinandersetzen müsste. Dieser Engpass ist insbesondere für potenziell nicht verbundene, mobile Anwendungen problematisch.

Stattdessen sollten Anwendungen Funktionen nutzen, die global eindeutige Kennungen (GUIDs) in einem verteilten System generieren können. Grundsätzlich sind GUIDs nicht sequenziell, sodass sie Fragmentierungen verursachen, wenn sie als CLUSTERED INDEX (gruppierter Index) in einer großen Tabelle verwendet werden. Um die Auswirkungen der Fragmentierung von GUIDs in einem großen Datenmodell zu reduzieren, gliedern Sie die Datenbank in Shards, und halten Sie die einzelnen Shards relativ klein. Dies ermöglicht der SQL-Datenbank, die Datenbanken während eines Replikatfailovers automatisch zu defragmentieren.

Der Clientanwendungscode muss verschiedenen Aspekten bei der Übermittlung eines verteilten Datenmodells Rechnung tragen:

  • Partitionsschlüssel. Partitionsschlüssel sollten Teil jeder Datenklasse oder jedes Modells sein und möglicherweise um ein Attribut ergänzt werden, das eine Ermittlung des Partitionsschlüssels ermöglicht.

  • Telemetrie. Die Datenzugriffsebene sollte automatisch Informationen zu jedem SQL-Aufruf protokollieren, einschließlich Ziel, Partition, Kontext, Latenzzeit und aller Fehlercodes oder Wiederholungen.

  • Verteilte Abfragen. Die Ausführung von Shard-übergreifenden Abfragen birgt eine Reihe neuer Herausforderungen, darunter Routing, Partitionsauswahl und das Konzept des partiellen Erfolgs (einige Shards geben erfolgreich Daten zurück, andere nicht). Die Datenzugriffsebene sollte Delegaten zum Ausführen von verteilten Abfragen in asynchroner (paralleler) Scatter-Gather-Weise bereitstellen, die ein zusammengesetztes Ergebnis zurückgeben. Verteilte Abfragen müssen auch der Beschränkung der zugrunde liegenden Ressourcen Rechnung tragen:

    • Der maximale Grad an Parallelität (zur Vermeidung von übermäßigem Thread- und Verbindungsdruck).

    • Die maximale Abfragezeit (zur Reduzierung der Gesamtlatenzzeit bei Abfragen mit langer Ausführungszeit oder langsamen Shards).

Es gibt zudem einige fortlaufende Verwaltungsaufgaben, die ausgeführt werden müssen:

  • Verweistabellen. Ohne einen global kohärenten Abfrageraum müssen Verweisdaten für JOINs in Abfragen in jeden einzelnen Shard kopiert werden. Es ist erforderlich, die Daten in den Verweistabellen in den einzelnen Shards zu verwalten und zu replizieren, um angemessen konsistente lokale Verweisdaten bereitzustellen.

  • Neuverteilen von Partitionen. Einzelne Partitionen können unausgeglichen werden und entweder zu viele Ressourcen beanspruchen und einen Engpass verursachen oder eine unzureichende Auslastung zeigen und Ressourcen vergeuden. In diesen Situationen müssen die Partitionen neu verteilt werden, um Ressourcen neu zuzuordnen. Der Neuverteilungsmechanismus ist stark von der Partitionierungsstrategie und Implementierung abhängig. In den meisten Szenarien umfasst die Neuverteilung:

    • Das Kopieren der verbleibenden Daten in einem Shard in einen oder mehrere neue Shards entweder über einen Teilungs-/Zusammenführungsmechanismus (für bereichsbasierte Partitionierung) oder über eine Kopie auf Entitätsebene und Neuzuordnung (für suchbasierte Partitionierung).

    • Das Aktualisieren der Shardzuordnung auf das neue Shard und das anschließende Kompensieren aller in die alten Shards geschriebenen Daten während des Übergangs.

  • Datenbereinigung. Wenn eine Anwendung wächst und Daten sammelt, sollten Sie eine regelmäßige Bereinigung älterer, ungenutzter Daten in Betracht ziehen, um den verfügbaren Toleranzbereich und die Kapazität im Primärsystem zu erhöhen. Bereinigte (gelöschte) Daten werden nicht gleichzeitig auch aus der SQL-Datenbank gelöscht. Sie werden vielmehr zum Löschen gekennzeichnet und durch einen Hintergrundprozess bereinigt. Eine gängige Methode zum Kennzeichnen von Daten zum Löschen ist eine Flagspalte, die eine Zeile als aktiv, inaktiv oder zu löschen kennzeichnet. Dadurch können Daten aus Abfragen für einen bestimmten Zeitraum maskiert werden, sodass die Daten problemlos zurück in die Produktionsumgebung verschoben werden können, wenn sie Benutzerangaben zufolge weiterhin benötigt werden.

    Das Löschen von Daten kann eine Fragmentierung auslösen, die für effiziente Abfrageoperationen unter Umständen eine Indexneuerstellung erforderlich macht. Ältere Daten können wie folgt archiviert werden:

    • Ein Onlinespeicher (sekundäre SQL-Datenbank). Dies erhöht den Toleranzbereich im Primärsystem, senkt aber nicht die Kosten.

    • Ein Offlinespeicher, wie eine bcp- oder bacpac-Datei im BLOB-Speicher. Dies erhöht den Toleranzbereich im Primärsystem und senkt die Kosten.

    • Bit-Bucket. Sie können auswählen, dass die Daten dauerhaft vom Primärsystem gelöscht werden sollen, um den Toleranzbereich zu vergrößern.

Zahlreiche Komponentenvorkommen in der SQL-Datenbank können vorübergehende Verbindungsfehler auslösen, z. B. einen Replikatfailover. Anwendungen müssen geeigneten Code implementieren, um vorübergehende Fehler zu beheben und um angemessen auf Ressourcenengpässe und -einschränkung zu reagieren:

  • Behandlung vorübergehender Verbindungsfehler mittels Wiederholungen. Der Datenzugriffscode sollte einen richtlinienbasierten Wiederholungsmechanismus nutzen, um vorübergehende Verbindungsfehler auszugleichen. Der Wiederholungsmechanismus muss temporäre Verbindungsfehler erkennen, eine erneute Verbindung mit der SQL-Zieldatenbank herstellen und den Befehl erneut ausgeben.

  • Behandlung von Einschränkungen mittels Wiederholungs- und Backofflogik. Der Datenzugriffscode muss einen richtlinienbasierten Wiederholungs- und Backoffmechanismus für den Umgang mit Einschränkungsbedingungen nutzen. Der Wiederholungsmechanismus sollte Einschränkungen erkennen und Versuche, den Befehl erneut auszugeben, schrittweise zurücknehmen (um einen Konvoieffekt zu vermeiden, der die Einschränkungsbedingung verlängern könnte).

    • Der Datenzugriffscode sollte zudem die Möglichkeit bieten, auf einen alternativen Datenspeicher auszuweichen, z. B. auf einen BLOB-Speicher. Dieser alternative Speicher bietet einen dauerhaften Mechanismus zum Aufzeichnen von Aktivitäten, Daten und Statusangaben und vermeidet Datenverluste im Fall andauernder Einschränkungen oder Verfügbarkeitsereignisse.

.NET-Anwendungen können ein auf der SQL-Datenbank basierendes Wiederholungs- und Backofflogikframework verwenden, wie Cloud Application Framework (CloudFx) oder Enterprise Library Transient Fault Handler. Diese Frameworks stellen Wrapper für allgemeine Datenzugriffsklassen (wie SqlConnection und SqlCommand) sowie Richtlinien bereit, die direkt aufgerufen werden können.

var retryPolicy = RetryPolicy.Create<SqlAzureTransientErrorDetectionStrategy>(
    retryCount: 3, 
    initialInterval: TimeSpan.FromSeconds(5),
    increment: TimeSpan.FromSeconds(2));
                
using (var conn = new ReliableSqlConnection(connStr))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {

    }
    conn.Close();
}

Der vorherige Codeausschnitt zeigt die Verwendung der CloudFx-Klasse ReliableSqlConnection, um vorübergehende Verbindungsfehler beim Arbeiten mit der SQL-Datenbank zu behandeln.

Besondere Sorgfalt und Aufmerksamkeit erfordert die Protokollierung der API-Aufrufe von Diensten, z. B. SQL-Datenbank, mit potenziell schwierigen Fehlermodi. Versuchen Sie, die wichtigsten Kontext- und Leistungsinformationen aufzuzeichnen. Beispielsweise verfügen alle SQL-Datenbanksitzungen über eine Sitzungs-ID, die bei Supportanrufen zur direkten Isolierung des zugrunde liegenden Problems beitragen können. Es wird empfohlen, alle Aufrufe, Befehle und Abfragen im SQL-Datenbankprotokoll festzuhalten:

  • Server- und Datenbankname. Bei möglicherweise mehreren Hundert Datenbanken ist der Zielserver für die Nachverfolgung und Isolierung von Problemen entscheidend.

  • Die gespeicherte Prozedur oder der Befehlstext in SQL, sofern angemessen. Achten Sie darauf, dass Sie keine vertraulichen Informationen in die Protokolldatei ausgeben. Im Allgemeinen sollten Sie die Protokollierung von Befehlstext vermeiden.

  • Die End-to-End-Latenzzeit des Aufrufs. Binden Sie den Aufruf mittels Stoppuhr oder einem anderen einfachen Zeitgeber in einen Zeitdelegaten ein.

  • Der Ergebniscode des Aufrufs (Erfolg oder Fehler) sowie die Anzahl der Wiederholungen und die Fehlerursache (Verbindung getrennt, eingeschränkt usw.).

  • Die Sitzungs-ID der Verbindung, auf die über die Eigenschaft CONTEXT_INFO() zugegriffen werden kann (oder über die SessionTracingId-Eigenschaft, wenn ReliableSqlConnection verwendet wird). Rufen Sie die Sitzungs-ID-Eigenschaft CONTEXT_INFO() jedoch nicht bei jedem Clientaufruf ab, da dieser Befehl einen weiteren Roundtrip zum Server auslöst.

Für eine möglichst effiziente Nutzung der SQL-Datenbank sollten Abfragen und Dateneinfügungen für die SQL-Datenbank als Batch verarbeitet und nach Möglichkeit asynchron ausgeführt werden. Dies verbessert nicht nur die Anwendungseffizienz, sondern reduziert auch die Gesamtsystemlast für die SQL-Datenbank (was einen höheren Durchsatz ermöglicht).

  • Einfügung als Batch. Bei fortlaufenden Dateneinfügevorgängen, z. B. der Registrierung neuer Benutzer, sollten die Daten als Batch verarbeitet und mit den Zielshards abgestimmt werden. Diese Batches sollten in regelmäßigen Intervallen (asynchron) und auf Grundlage von Triggern, wie Zielbatchgröße oder Zeitfenster, in die SQL-Datenbank geschrieben werden. Für Batchgrößen unter 100 Zeilen sind Tabellenwertfunktionen in der Regel effizienter als ein Massenkopiervorgang.

  • Vermeiden 'geschwätziger' Schnittstellen. Reduzieren Sie die Anzahl der erforderlichen Roundtrips zur Datenbank für eine Abfrage oder eine Gruppe von Vorgängen. 'Geschwätzige' Schnittstellen zeichnen sich durch ein hohes Maß an Aufwand aus, der die Last im System erhöht und Durchsatz sowie Effizienz reduziert. Versuchen Sie, miteinander verbundene Vorgänge mithilfe einer gespeicherten Prozedur zusammenzuführen, um Roundtrips zu reduzieren.

Im Rahmen eines allgemeinen Ansatzes für Geschäftskontinuität sollten die in der SQL-Datenbank gespeicherten Daten regelmäßig in einen BLOB-Speicher exportiert werden. Der BLOB-Speicher unterstützt standardmäßig Verfügbarkeit und Georeplikation.

Implementieren Sie eine geplante Task, durch die in regelmäßigen Abständen Datenbanken in den BLOB-Speicher exportiert werden. Verwenden Sie ein dediziertes Speicherkonto. Diese Task sollte in demselben Rechenzentrum wie die Zieldatenbanken ausgeführt werden und nicht von einem lokalen Desktop oder Server aus.

Planen Sie die Exporttask für einen aktivitätsschwachen Zeitpunkt, um die Auswirkungen auf die Endbenutzererfahrung zu minimieren. Wenn Sie mehrere Datenbanken exportieren, beschränken Sie die Anzahl der parallelen Exporte, um die Auswirkungen auf das System zu reduzieren.

Der Einblick in den Zustand, die Leistung und den Toleranzbereich der SQL-Datenbanken ist eine wichtige Komponente der allgemeinen Dienstbereitstellung. Die SQL-Datenbank stellt die erforderlichen reinen Informationen über dynamische Verwaltungsansichten bereit, es gibt jedoch derzeit keine sofort einsetzbare Infrastruktur für die Aufzeichnung, Analyse und Berichterstellung von Schlüsselmetriken. Um diese Möglichkeit für die SQL-Datenbank bereitzustellen, können Sie wie folgt vorgehen:

  • Implementieren Sie eine regelmäßige Task, um wichtige Leistungsdaten zur Systemauslastung, zu den verwendeten Ressourcen (Workerthreads, Speicherplatz) und zu den Daten in einem gemeinsamen Repository zu erfassen. Verwenden Sie beispielsweise die von Azure-Diagnose verwendeten Tabellen. Diese Task muss Daten aus allen Datenbanken erfassen, die zu der Anwendung gehören. Diese Erfassung erfolgt üblicherweise mit einer auf der horizontalen Skalierung basierenden Methode (Sammeln von Daten aus mehreren Datenbanken gleichzeitig).

  • Implementieren Sie eine regelmäßige Task, um diese Informationen zusammenzustellen und Key Performance Indicators für den Zustand und die Kapazität der bereitgestellten Datenbanken zu erstellen.

Azure-Diagnose dient als Grundlage für die Erfassung von Telemetriedaten auf Anwendungs- und Instanzebene. Um Einblicke in anspruchsvolle Anwendungen zu ermöglichen, die unter Azure ausgeführt werden, ist jedoch eine sorgfältige Konfiguration und Verwaltung der Datenflüsse notwendig. Im Gegensatz zu zentralen Anwendungen mit vertikaler Skalierung, die funktionsreiche Windows-Diagnoseprogramme nutzen können, muss die Diagnose in einem verteilten System mit horizontaler Skalierung implementiert werden, bevor das System in Betrieb genommen wird. Sie kann nicht im Nachhinein hinzugefügt werden.

Fehlerbehandlung, kontextabhängige Nachverfolgung und Telemetrieaufzeichnung sind für ein grundlegendes Verständnis der Fehlerereignisse, Ursachen und Lösungen von großer Bedeutung.

  • Veröffentlichen Sie keine aktiven Websitedaten und Telemetrie in demselben Speicherkonto. Verwenden Sie ein dediziertes Speicherkonto für die Diagnose.

  • Erstellen Sie separate Kanäle für segmentierte (Einzeldaten mit hohem Volumen und hoher Latenzzeit) und 'geschwätzige' (Daten mit hohem Volumen, niedriger Latenzzeit und hohem Wert) Telemetrie.

    • Verwenden Sie die Standardquellen von Azure-Diagnose, wie Leistungsindikatoren und Ablaufverfolgung, für 'geschwätzige' Informationen.

    • Verwenden Sie allgemeine Protokollierungsbibliotheken, wie Enterprise Application Framework Library, log4net oder NLog, um eine Massenprotokollierung in lokale Dateien zu implementieren. Verwenden Sie eine benutzerdefinierte Datenquelle in der Diagnosemonitorkonfiguration, um diese Informationen regelmäßig in den BLOB-Speicher zu kopieren.

  • Protokollieren Sie alle API-Aufrufe von externen Diensten, einschließlich Kontext, Ziel, Methode, Zeitdaten (Latenzzeit) und Ergebnissen (Erfolg/Fehler/Wiederholungen). Verwenden Sie einen segmentierten Protokollierungskanal, um das Diagnosesystem nicht mit Telemetriedaten zu überlasten.

  • Daten, die in den Tabellenspeicher geschrieben werden (Leistungsindikatoren, Ereignisprotokolle, Ablaufverfolgungsereignisse), werden einer temporären Partition von 60 Sekunden Länge hinzugefügt. Der Versuch, zu viele Daten zu schreiben (für viele Punktquellen, zu kleines Erfassungsintervall), kann diese Partition überlasten. Stellen Sie sicher, dass die Fehlerspitzen keine umfangreichen Einfügungsversuche in den Tabellenspeicher auslösen, da dies ein Einschränkungsereignis zur Folge haben kann.

    • Wählen Sie für die Erfassung aus diesen Quellen hochwertige Daten aus, unter anderem Schlüsselleistungsindikatoren, kritische Ereignisse/Fehlerereignisse oder Ablaufverfolgungsdatensätze.

    • Wählen Sie ein geeignetes Erfassungsintervall (5 Minuten - 15 Minuten) aus, um die Datenmenge zu reduzieren, die übertragen und analysiert werden muss.

  • Stellen Sie sicher, dass die Protokollierungskonfiguration zur Laufzeit geändert werden kann, ohne dass Instanzen zurückgesetzt werden müssen. Überprüfen Sie außerdem, ob die Konfiguration ausreichend genau ist, um eine Protokollierung bestimmter Aspekte des Systems zu ermöglichen, beispielsweise Datenbanken, Cache oder andere Dienste.

Azure-Diagnose ermöglicht keine Datensammlung für abhängige Dienste, wie SQL-Datenbank oder verteilter Cache. Um eine umfassende Ansicht der Anwendung und ihrer Leistungsmerkmale zu erhalten, fügen Sie Infrastruktur zum Erfassen von Daten für abhängige Dienste hinzu:

  • Erfassen Sie Schlüsselleistungsmerkmale und Auslastungsdaten von abhängigen Diensten, und veröffentlichen Sie diese im WAD-Repository als Leistungsindikatordatensätze.

    • Azure-Speicher über Azure-Speicheranalyse.

    • SQL-Datenbank über dynamische Verwaltungsansichten

    • Verteilter Cache über Leistungsindikatoren oder Systemüberwachungs-API.

  • Analysieren Sie in regelmäßigen Abständen die unformatierten Telemetriedaten, um Zusammenstellungen und Rollups zu erstellen (als geplante Task).

Fanden Sie dies hilfreich?
(1500 verbleibende Zeichen)
Vielen Dank für Ihr Feedback.
Anzeigen:
© 2014 Microsoft