Cloud Computing

Synchronisieren von mehreren Knoten in Windows Azure

Josh Twist

Downloaden des Codebeispiels

Die Wolke stellt eine wichtige Technologie-Schicht und viele Branchenexperten Vorhersagen von dieser Änderung ist eine Skala wir nur alle 12 Jahre sehen oder dies.Diese Ebene der Spannung ist kaum überraschend, wenn Sie viele Vorteile die Wolke verspricht: deutlich reduziert Kosten, hohe Verfügbarkeit und nahezu unbegrenzte Skalierbarkeit, Namen, aber ein paar ausgeführt.

Selbstverständlich stellt eine solche Verschiebung auch der Branche mit einer Reihe von Herausforderungen, nicht mindestens denen Entwickler heute konfrontiert sind.Angenommen, wie erstellen wir Systeme, die optimal um zu nutzen, die speziellen Features von der Wolke positioniert werden?

Glücklicherweise gestartet im Februar Microsoft Windows Azure Plattform, die enthält eine Reihe von recht große Teile, die Erstellung von Anwendungen zu unterstützen, die enorme Anzahl von Benutzern unterstützen können, bleiben Sie hohe Verfügbarkeit.Jedoch ist für alle Anwendungen zu erzielen, das volle Potenzial, wenn in der Wolke bereitgestellt, die Onus auf die Entwickler des Systems zu nutzen, was wohl größte Feature der Wolke ist: Elasticity.

Elasticity ist eine Eigenschaft der Cloud-Plattformen, die zusätzliche Ressourcen (Rechenleistung, Speicherung und so weiter) bereitgestellte bedarfsgesteuerten, bieten die Möglichkeit, Ihre Webfarm in wenigen Minuten nicht Monaten weitere Server hinzugefügt werden kann.Ebenso wichtig ist die Möglichkeit, diese Ressourcen genauso schnell zu entfernen.

Einen wichtigen Grundpfeiler der Wolke Pay-as-you-go Geschäftsmodell, wobei Sie nur Zahlen Sie verwenden berechnet wird.Mit Windows-Azure bezahlen Sie nur für die Zeit, die ein Knoten (Web oder Worker-Rolle auf einem virtuellen Computer ausgeführt) bereitgestellt wird, und verringert so die Anzahl der Knoten, wenn Sie nicht mehr erforderlich sind oder ruhigen Zeiten des Unternehmens, wodurch eine direkte Kosteneinsparungen.

Daher ist es sehr wichtig, dass Entwickler Elastische Systeme erstellen, die automatisch auf die Bereitstellung zusätzlicher Hardware, mit minimalen Eingabe- oder von Systemadministratoren erforderliche Konfiguration zu reagieren.

Szenario 1: Erstellen die Bestellung Zahlen

Vor kurzem war ich an eine Machbarkeitsstudie arbeiten, die beim Verschieben einer vorhandenen Infrastruktur der Web-Anwendung in der Wolke mit Windows Azure sah Glück.

Erhalten die partitionierte Natur der Daten der Anwendung, war es ein gutes Kandidat für Windows Azure Table-Speicher. Diese einfache, aber leistungsfähige Speichermechanismus – mit seiner Unterstützung für nahezu unbegrenzte Skalierbarkeit – ist die ideale Wahl mit nur einem bedeutende Nachteil bezüglich der eindeutige Bezeichner.

Die Zielanwendung zulässig Kunden bestellen Sie und Ihre Auftragsnummer abzurufen.Mithilfe von SQL Server oder SQL Azure, es würde haben bereits leicht, einen einfachen numerischen, eindeutigen Bezeichner generiert, aber Windows Azure Tabelle Speicher bietet Primärschlüssel automatisch erhöht.Stattdessen 
developers Windows Azure Table-Speicher mit eine GUID erstellen und verwenden Sie dies als “ Schlüssel ” in der Tabelle:

505EAB78-6976-4721-97E4-314C76A8E47E

Das Problem bei der Verwendung von GUIDs ist, dass Sie für Menschen mit schwierig sind.Angenommen, Ihre Bestellnummer GUID über das Telefon an einen Operator ausgelesen werden müssen, oder notieren Sie in Ihrem Tagebuch.Haben GUIDs natürlich gleichzeitig in jedem Kontext eindeutig sein, sodass Sie sehr komplex sind.Die Auftragsnummer hat andererseits, nur in der Orders-Tabelle eindeutig sein.

Erstellen eine einfache eindeutige ID in Windows Azure

Eine Reihe von relativ einfache Lösungen für das Problem der GUID wurden berücksichtigt werden:

  1. Verwenden Sie zum Erstellen von eindeutigen IDs Azure SQL: Eine Reihe von Gründen, die Machbarkeitsstudie hatte bereits abgezogen SQL Azure zugunsten von Windows Azure Tabelle Speicher – in erster Linie auf die Notwendigkeit für das System viele Knoten Skalieren mit vielen Threads, die für die Daten ausgeführt.
  2. Verwenden Sie zum Verwalten von einem Wert erhöht Blob-Speicher: Speichern Sie einen zentralen Zähler in Windows Azure Blob-Speicher. Knoten konnte lesen und aktualisieren die Nummer des Fertigungsauftrags, einfache sequenziell Number Generation Mechanismus für die Verwendung durch mehrere Knoten bereitstellt. Allerdings würde der Konflikt für einem stark ausgelasteten System erfordern viele neue Auftragsnummern pro Sekunde an diesem Punkt wahrscheinlich die Skalierbarkeit des Systems beeinträchtigen.
  3. Partition mit eindeutigen IDs für jeden Knoten: Erstellen Sie einen einfachen im Arbeitsspeicher Zähler, der eindeutige Auftragsnummern generiert. Um Eindeutigkeit auf allen Knoten zu gewährleisten, würde jeder Knoten einen Nummernbereich, reserviert werden wie in Abbildung 1.

Abbildung 1 Zuweisen von eine Bereich von zu Zahlen zu jeder Knoten an die eindeutigen IDs

Knoten Range
a 0-1,000,000
B 1,000,001-2,000,000

Diese Methode löst jedoch eine Reihe von Fragen.Was geschieht, wenn ein Knoten einen Bereich erschöpft?Was geschieht, wenn gleichzeitig hunderte von Knoten zum System hinzugefügt werden?Was geschieht, wenn ein Knoten stürzt ab und wird von der Laufzeit Windows Azure mit einem neuen Knoten ersetzt?Administratoren müssen genau überwachen diese Bereiche und achten, um sicherzustellen, dass die Konfiguration richtig ist oder beschädigte Daten stoßen.

Stattdessen war ein wesentlich Eleganter Ansatz erforderlich – eine Lösung, die keine Konfiguration pro Knoten erforderlich veranschaulichten wenig Konflikte und Eindeutigkeit jederzeit gewährleistet.Um dies zu erreichen, wurde eine Mischung aus der zweiten und dritten Optionen erstellt.

Das Konzept war relativ einfach: Verwenden Sie eine kleine Textdatei, die in einem Blob-Speicher, um die Nummer des letzte Auftrags zu speichern.Wenn eine neue Nummer erforderlich ist, kann ein Knoten Zugriff auf diesem Blob, erhöhen Sie den Wert und zurück auf den Datenträger geschrieben.Natürlich ist eine sinnvolle Wahrscheinlichkeit, dass ein anderer Knoten das Blob mit der Absicht, dieselbe während dieses Vorgangs Inkrement-Schreib-/ zugegriffen haben, wird.Ohne eine Art Parallelitätsverwaltung die Auftragsnummern wäre nicht eindeutig, und würden die Daten beschädigt werden.Traditionell, könnte ich betrachtet haben erstellen Sie einen Sperrmechanismus, mehrere Knoten verhindert das Blob gleichzeitig arbeiten.Allerdings Sperren teuer sind und wenn Durchsatz und massive Skalierbarkeit Designs für die Implementierung verstehen, sind, vermieden werden.

Stattdessen ist ein Ansatz, die vollständige Parallelität günstig.Mit vollständiger Parallelität können wir mehrere Akteure für die Interaktion mit einer Ressource.Wenn die Ressource durch ein Akteur abgerufen wird, wird der Akteur auch ein Token ausgestellt, die die Version der Ressource angibt.Eine Aktualisierung stattfindet, kann das Token enthalten, um anzugeben, welche Version der Ressource geändert wird sein.Wenn die Ressource bereits durch einen anderen Akteur geändert, dann schlägt die Aktualisierung fehl und der ursprüngliche Akteur kann die neueste Version abrufen und versuchen, das Update erneut.Vollständiger Parallelität funktioniert gut, vorausgesetzt die Wahrscheinlichkeit von Konflikten auf Aktualisierungen niedrig sind.Die Kosten und die Komplexität einer Sperre wird vermieden, und die Ressource vor Beschädigung geschützt ist.

Stellen Sie sich vor, dass Sie während der Spitzenzeiten, das System etwa 100 neue Bestellungen pro Sekunde ausgibt.Dies würde bedeuten, dass 100 Anforderungen zum Aktualisieren des BLOBs pro Sekunde, eine extrem hohe Wahrscheinlichkeit von Konflikten, die Anzahl der erneuten bedeuten würde, dass die Situation exacerbating.Um diese auftreten zu vermeiden, wollte ich daher Auftragsnummern in Bereichen zugewiesen werden.

Eine Klasse mit dem Namen der UniqueIdGenerator wurde erstellt, um dieses Verhalten zu kapseln.Die Klasse entfernt einen Nummernbereich von Blob-Speicher erhöhen Sie den Wert in konfigurierbaren Segmenten.Befand sich jede UniqueIdGenerator jeweils 1.000 Auftragsnummern reservieren, würde das Blob nur durchschnittlich 10 Sekunden, erheblich verringert die Wahrscheinlichkeit von Konflikten aktualisiert werden.Jede UniqueIdGenerator ist davon überzeugt, dass keine andere Instanz der Klasse auf dieselbe Ressource Blob zeigen die gleichen Bestellnummer ausstellt, frei, um die reservierte 1.000 Reihenfolge werden Zahlen am ausstellen.

Mit dieser neuen Komponente testbare vornehmen, wurde eine Schnittstelle namens IOptimisticSyncStore, die UniqueIdGenerator aus der bestimmten Speichermechanismus de-coupled angegeben.Dies hat einen zusätzlichen Vorteil: Die Komponente konnte in der Zukunft eine andere Art der Datenspeicherung bei Bedarf verwenden.Hier ist die Schnittstelle:

public interface IOptimisticSyncStore
{
  string GetData();
  bool TryOptimisticWrite(string data);
}

Wie Sie sehen können, ist es ziemlich einfache Schnittstelle mit nur zwei Methoden: eine zum Abrufen der Daten und eine andere aktualisieren, die letztere Rückgabe eines booleschen Wertes False gibt, in denen es wurde ein Fehler bei der vollständigen Parallelität und den Prozess sollte wiederholt werden.

Eine Implementierung der IOptimisticSyncStore, verwendet Speicher blob ist im Codedownload (Details am Ende des Artikels) verfügbar.In den meisten Fällen ist die Implementierung einfach;Allerdings lohnt Betrachtung der TryOptimisticWrite Methode näher zu verstehen, wie vollständigen Parallelität implementiert wurde.

Es ist einfach, vollständigen Parallelität beim Aktualisieren von Ressourcen in Windows Azure Blob Speicher Dank an Vorbedingungen und Entity-Tags (ETags) zu verwenden.Eine Voraussetzung ist eine Anweisung, die ein Entwickler Bestätigungen für eine HTTP-Anforderung erfolgreich ist wahr sein muss.Wenn der Webserver die Anweisung false ergibt, sollte er mit einem HTTP-Status Code 412 Antworten: “ Vorbedingung fehlgeschlagen ”. ETags sind ebenfalls Teil der HTTP-Spezifikation, und identifizieren eine bestimmte Version einer Ressource, wie z. B. ein Blob.Wenn das Blob ändert, sollten auch, wie hier gezeigt das ETag ändern:

try
{


  _blobReference.UploadText(


    data,


    Encoding.Default,


    new BlobRequestOptions { 


    AccessCondition = AccessCondition.IfMatch(

    _blobReference.Properties.ETag) });


}

Eine Vorbedingung im Code angeben möchten, verwenden Sie den BlobRequestOptions und legen Sie die Eigenschaft AccessCondition.Wenn dieser Zugriff Bedingung erfüllt ist nicht (z. B., wenn ein anderer Knoten das Blob in kurzer Zeit aktualisiert seit es abrufen), die ETags würde nicht übereinstimmen, und ein StorageClientException würde ausgelöst werden:

catch (StorageClientException exc)
{
  if (exc.StatusCode == HttpStatusCode.PreconditionFailed)
  {
    return false;
  }
  else
  {
    throw;
  }
}
return true;

Die Implementierung die Ausnahme für den Statuscode PreconditionFailed überprüft und gibt in diesem Fall false zurück.Eine andere Art von Ausnahme ist ein schwerwiegender Fehler und erneut ausgelöst wird, für die Behandlung und Protokollierung auf Weiter.Keine Ausnahme bedeutet, dass das Update wurde ausgeführt, und die Methode gibt true zurück.Die vollständige Liste der UniqueIdGenerator-Klasse wird im Abbildung 2 angezeigt.

Abbildung 2 Die vollständige UniqueIdGenerator-Klasse

public class UniqueIdGenerator
{ 
    private readonly object _padLock = new object();
    private Int64 _lastId;
    private Int64 _upperLimit;
    private readonly int _rangeSize;
    private readonly int _maxRetries;
    private readonly IOptimisticSyncStore _optimisticSyncStore;

    public UniqueIdGenerator(
      IOptimisticSyncStore optimisticSyncStore,
      int rangeSize = 1000,
      int maxRetries = 25)
    {
      _rangeSize = rangeSize;
      _maxRetries = maxRetries;
      _optimisticSyncStore = optimisticSyncStore;


      UpdateFromSyncStore();
    }

    public Int64 NextId()
    {
      lock (_padLock)
      {
        if (_lastId == _upperLimit)
        {

          UpdateFromSyncStore();
        }
        return _lastId++;
      }
    }

    private void UpdateFromSyncStore()
    {
      int retryCount = 0;
      // maxRetries + 1 because the first run isn't a 're'try.
      while (retryCount < _maxRetries + 1)
      {
        string data = _optimisticSyncStore.GetData();

        if (!Int64.TryParse(data, out _lastId))
        {
          throw new Exception(string.Format(
            "Data '{0}' in storage was corrupt and " +

            "could not be parsed as an Int64", data));
        }

        _upperLimit = _lastId + _rangeSize;

        if (_optimisticSyncStore.TryOptimisticWrite(

          _upperLimit.ToString()))
        {
          return;
        }

        retryCount++;
        // update failed, go back around the loop
      }

      throw new Exception(string.Format(
        "Failed to update the OptimisticSyncStore after {0} attempts",
        retryCount));
    }
}

Der Konstruktor akzeptiert drei Parameter.Die erste ist eine Implementierung der IOptimisticSyncStore, wie unsere BlobOptimisticSyncStore bereits erläutert wurde.Der zweite Parameter ist RangeSize, ein ganzzahliger Wert, der angibt, wie groß der Zahlenbereich vom Blob zugeordnet werden soll.Das Vergrößern dieses Bereichs, die weniger Gefahr von Konflikten.Jedoch würde mehr Zahlen verloren wären dieses Knotens zu einem Absturz.Der letzte Parameter ist MaxRetries, eine ganze Zahl, die angibt, wie oft der Generator sollten versuchen, das Blob im Falle eines Fehlers vollständige Parallelität zu aktualisieren.Über diesen Punkt hinaus wird eine Ausnahme ausgelöst.

Die NextId-Methode ist der nur öffentliche Member der Klasse UniqueIdGenerator und wird verwendet, um die nächste eindeutige Zahl abzurufen.Der Text der Methode wird sichergestellt, dass jede Instanz der Klasse threadsicher ist und konnte, z. B. zwischen den Threads, die Ihre Webanwendung ausführen freigegeben werden synchronisiert.Eine Anweisung überprüft, wenn der Generator die Obergrenze der Ressourcenzuordnung des Bereichs erreicht hat, und wenn dies der Fall, ruft UpdateFromSyncStore einen neuen Bereich von Blob-Speicher abrufen.

Die UpdateFromSyncStore-Methode ist der endgültige jedoch interessanteste Teil der Klasse.Die Implementierung der IOptimisticSyncStore zum Abrufen der Obergrenze der vorherigen Zuweisung ausgegeben.Durch den Generator Bereichsgröße erhöht wird, und dies wird zurück in den Speicher geschrieben.Eine einfache “ while-Schleife ” schließt den Textkörper, um sicherzustellen, dass die richtige Anzahl von Wiederholungen ausgeführt, wird Wenn TryOptimisticWrite false zurückgibt.

Der folgende Codeausschnitt zeigt ein UniqueIdGenerator konstruiert wird, eine Datei mit einem BlobOptimisticSyncStore “ ordernumber.dat ” in ein Container namens “ Uniqueids ” aufgerufen (Hinweis: Container im Blob-Speicher müssen Kleinbuchstaben Namen haben):

IOptimisticSyncStore storage = new BlobOptimisticSyncStore(
  CloudStorageAccount.DevelopmentStorageAccount, 
  "uniqueids", 
  "ordernumber.dat");
UniqueIdGenerator
  generator = new UniqueIdGenerator(storage, 1000, 10);

Diese Instanz 1.000 IDs vom zentralen Bereich entfernt und wiederholt zehnmal im Falle eines Fehlers vollständige Parallelität vor dem Auslösen einer Ausnahme.

Verwenden die UniqueIdGenerator ist noch einfacher.Wenn Sie eine neue eindeutige Bestellnummer benötigen, rufen Sie einfach NextId:

Int64 orderId = generator.NextId();

Der Beispielcode zeigt eine Windows Azure Worker-Rolle, die mehrere Threads, verwendet um schnell eindeutige Auftragsnummern zuordnen und diese in einer SQL-Datenbank geschrieben werden.Die Verwendung von SQL in dieser Instanz ist einfach zu beweisen, dass jeder Nummer eindeutig ist, eine Verletzung dieser würde dazu führen, dass eine Verletzung der Primärschlüssel und eine Ausnahme auslösen.

Der Vorteil dieses Ansatzes, außer das Blob erstellen und dessen Wert auf 0 festlegen, am Anfang der Lebensdauer der Anwendung sehr – ist, dass kein Aufwand des Systemadministrators erforderlich ist.Die UniqueIdGenerator die Zuweisung von Kennungen, die basierend auf den Einstellungen verwaltet, ordnungsgemäß im Falle eines Fehlers wiederhergestellt sorgfältig und mühelos selbst in die Elastische Umgebungen skaliert.

Szenario 2: Veröffentlichung der Hounds!

Eine weitere interessante Anforderung, die durch die Anwendung war die Notwendigkeit, große Mengen von Daten, die nach ein angegebenen Ereignis, das zu einem Zeitpunkt ca. bekannten auftreten würde schnell zu verarbeiten.Aufgrund von der Art der Verarbeitung konnte nicht die Arbeit auf die Daten erst nach diesem Ereignis begonnen.

Worker-Funktionen sind in diesem Szenario eine offensichtliche Wahl, und es wäre möglich, Fragen Sie einfach Windows Azure bereitstellen, die erforderliche Anzahl von Worker-Rollen als Reaktion auf das Ereignis oben genannten gewesen.Jedoch neue Rollen bereitstellen kann bis zu 30 Minuten dauern und Geschwindigkeit der das wesentliche in diesem Szenario wurde.Daher wurde entschieden, dass die Rollen im Voraus jedoch in einem angehaltenen Status, bis durch den Administrator freigegeben hydrated würden – I bezeichnet dies “ Release der Hounds ”! Zwei mögliche Ansätze wurden berücksichtigt, und ich werde jede wiederum überprüfen.

Es sollte beachtet werden, da Windows Azure Worker-Funktionen belastet werden basierend auf der Uhrzeit, die Sie bereitgestellt werden (nicht auf diese wie aktiv die CPU verwenden) dieser Ansatz wäre Kosten mehr einfach verglichen mit Erstellen der Worker-Rollen als Reaktion auf das Ereignis.Der Kunde war jedoch klar, dass dieser Kapitalanlage war sinnvoll, um sicherzustellen, dass die Verarbeitung so schnell wie möglich beginnen konnte.

Ansatz I: Abrufen

Der erste Ansatz ist in Abbildung 3 dargestellte hat jeder Knoten einen zentralen Statusflag in regelmäßigen Abständen abzufragen (wieder in ein Windows-Azure Blob gespeichert) zu bestimmen, ob Arbeit noch begonnen werden konnte.

Knoten Polling Central Status-Flag

Abbildung 3 Knoten Polling Central Status-Flag

Un anhalten die Knoten eine Client-Anwendung einfach musste dieses Flag auf True festgelegt, und mit der nachfolgenden Poll würde jeder Knoten freigegeben werden.Der Hauptnachteil dieser Ansatz ist Latenz, möglicherweise so groß wie das Abrufintervall.Auf der anderen Seite ist dies eine sehr einfache und zuverlässige Mechanismus implementieren.

Dieser Entwurf ist verfügbar, in dem Beispielcode PollingRelease-Klasse veranschaulicht.Um die Testbarkeit zu unterstützen, wurde Speichermechanismus für die Kennzeichnung hinter einer Schnittstelle in fast genauso wie für die UniqueIdGenerator Klasse abstrahiert.Die Schnittstelle IGlobalFlag und die zugehörige Implementierung für Blob-Speicher sind in dargestellten Abbildung 4.

Abbildung 4 und Blob-Storage-Implementierung der IGlobalFlag

public interface IGlobalFlag
{
  bool GetFlag();
  void SetFlag(bool status);
}

public class BlobGlobalFlag : IGlobalFlag
{
  private readonly string _token = "Set";
  private readonly CloudBlob _blobReference;
  public BlobGlobalFlag(CloudStorageAccount account, string container,    
    string address)
  {
    var blobClient = account.CreateCloudBlobClient();
    var blobContainer =   
      blobClient.GetContainerReference(container.ToLower());
    _blobReference = blobContainer.GetBlobReference(address);
  }

  public void SetFlag(bool status)

  {
    if (status)
   {
      _blobReference.UploadText(_token);
    }
    else
    {
      _blobReference.DeleteIfExists();
    }
  }

  public bool GetFlag()
  {

    try
    {
      _blobReference.DownloadText();
      return true;
    }
    catch (StorageClientException exc)
    {
      if (exc.StatusCode == System.Net.HttpStatusCode.NotFound)
      {
        return false;
      }
      throw;
    }
  }
}

Beachten Sie, dass in diesem Beispiel das bloße Vorhandensein einer Datei im Blob-Speicher true, unabhängig davon, welcher Inhalt angibt.

PollingRelease-Klasse selbst ist einfach, wie Abbildung 5 mit nur eine öffentliche Methode mit dem Namen warten zeigt.

Abbildung 5 Die PollingRelease-Klasse

public class PollingRelease 
{
  private readonly IGlobalFlag _globalFlag;
  private readonly int _intervalMilliseconds;

  public PollingRelease(IGlobalFlag globalFlag, 
    int intervalMilliseconds)
  {
    _globalFlag = globalFlag;
    _intervalMilliseconds = intervalMilliseconds;
  }

  public void Wait()
  {
    while (!_globalFlag.GetFlag())
    {
      Thread.Sleep(_intervalMilliseconds);
    }
  }
}

Diese Methode blockiert alle Aufrufer, solange die Implementierung IGlobalFlag gibt an, dass sein Status auf false festgelegt ist.Der folgende Codeausschnitt zeigt die PollingRelease-Klasse verwendet:

BlobGlobalFlag globalFlag = new BlobGlobalFlag(
  CloudStorageAccount.DevelopmentStorageAccount,
  "globalflags",
  "start-order-processing.dat");
PollingRelease pollingRelease = new PollingRelease(globalFlag, 2500);
pollingRelease.Wait();

Eine BlobGlobalFlag-Instanz erstellt, auf den in ein Container namens “ Globalflags ”. The PollingRelease class will poll every 2.5 seconds for the presence of a file called “start-order-processing.dat”; any call to the Wait method will be blocked until this file exists.

Ansatz II: Abhören

Der zweite Ansatz verwendet die Windows Azure AppFabric Service Bus, um gleichzeitig alle Worker-Funktionen direkt kommunizieren, und lassen Sie (siehe Abbildung 6 ).

mithilfe der Windows Azure AppFabric Service Bus gleichzeitig Kommunikation mit Rollen für alle Worker

Abbildung 6 mithilfe der Windows Azure AppFabric Service Bus gleichzeitig Kommunikation mit Rollen für alle Worker

Der Service Bus ist eine umfangreiche messaging und Konnektivität-Dienst auch auf Windows Azure erstellt. Sichere Kommunikation zwischen den verschiedenen Komponenten einer verteilten Anwendung vereinfacht. Der Service Bus bietet eine ideale Methode zum Verbinden von zwei Anwendungen, die andernfalls schwer zu, aufgrund von Ihrer Position hinter NAT (Netzwerkadressübersetzung) eine Netzwerkgrenze-Adresse oder eine IP-Adresse häufig ändern, z. B. kommunizieren finden es würde. Es ist nicht Gegenstand dieses Artikels, um eine detaillierte Übersicht der Windows Azure AppFabric Service Bus zu verleihen, aber eine ausgezeichnete Lernprogramm steht auf MSDN unter msdn.microsoft.com/library/ee706736-.

Um diesen Ansatz zu veranschaulichen, wurde eine Klasse namens ListeningRelease erstellt, der eine öffentliche Methode wie PollingRelease, Wait aufgerufen hat.Diese Methode stellt eine Verbindung mit dem Service Bus und verwendet ein ManualResetEvent, um den Thread zu blockieren, bis ein Signal empfangen wird:

public void Wait()
{
  using (ConnectToServiceBus())
  {
    _manualResetEvent.WaitOne();
  }
}

Die vollständige ConnectToServiceBus-Methode ist in aufgeführt Abbildung 7. Typen von Assemblys, die System.ServiceModel und Microsoft.ServiceBus verwendet, um eine Klasse namens UnleashService in der Wolke über die Windows Azure AppFabric Service Bus, dargestellt in verfügbar machen acht.

Abbildung 7 Die Methode ConnectToServiceBus

private IDisposable ConnectToServiceBus()
{
  Uri address = ServiceBusEnvironment.CreateServiceUri("sb",  
    _serviceNamespace, _servicePath);
  TransportClientEndpointBehavior sharedSecretServiceBusCredential =  
    new TransportClientEndpointBehavior();
  sharedSecretServiceBusCredential.CredentialType =  
    TransportClientCredentialType.SharedSecret;
  sharedSecretServiceBusCredential.Credentials.SharedSecret.
    IssuerName = _issuerName;
  sharedSecretServiceBusCredential.Credentials.SharedSecret.
    IssuerSecret = _issuerSecret;

  // Create the single instance service, which raises an event
  // when the signal is received.
  UnleashService unleashService = new UnleashService();
  unleashService.Unleashed += new  
    EventHandler(unleashService_Unleashed);

  // Create the service host reading the configuration.
  ServiceHost host = new ServiceHost(unleashService, address);

  IEndpointBehavior serviceRegistrySettings = 
    new ServiceRegistrySettings(DiscoveryType.Public);

  foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
  {
    endpoint.Behaviors.Add(serviceRegistrySettings);
    endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
  }

  host.Open();

  return host;
}

Abbildung 8 die UnleashService-Klasse

[ServiceBehavior(InstanceContextMode= InstanceContextMode.Single)]
public class UnleashService : IUnleashContract
{
  public void Unleash()
  {
    OnUnleashed();
  }

  protected virtual void OnUnleashed()
  {
    EventHandler temp = Unleashed;
    if (temp != null)
    {
      temp(this, EventArgs.Empty);
    }
  }

  public event EventHandler Unleashed;
}

Die UnleashService von Windows Communication Foundation (WCF) als einzelne Instanz gehostet wird, und implementiert den IUnleashService Vertrag, der nur eine Methode besitzt: Nutzen.ListeningRelease überwacht einen Aufruf dieser Methode über das weiter oben aufgeführte Unleashed-Ereignis.Wenn die Klasse ListeningRelease dieses Ereignis folgt, ManualResetEvent, die derzeit alle Anrufe warten blockiert festgelegt, und alle blockierten Threads freigegeben werden.

In der Konfiguration für den Dienst verwendet die NetEventRelayBinding, die durch die Service Bus, so dass eine beliebige Anzahl von Verlegern und Abonnenten über einen einzelnen Endpunkt zu kommunizieren Multicasting unterstützt.Die Beschaffenheit der broadcast Kommunikation erfordert, dass alle Operationen von der Schnittstelle IUnleashContract unidirektional sind:

[ServiceContract]
public interface IUnleashContract
{
  [OperationContract(IsOneWay=true)]
  void Unleash();
}

Der Endpunkt ist mit einem gemeinsamen geheimen Schlüssel (Benutzername und komplexes Kennwort) gesichert.Mit diesen Informationen kann jeder Client mit Zugriff auf das Internet Unleash Methode aufrufen – einschließlich, z. B. im Beispiel bereitgestellten Verwaltungskonsole (siehe Abbildung 9 ).

die Verwaltungskonsole

Abbildung 9 die Verwaltungskonsole

Obwohl der ListeningRelease Ansatz sofort mit der inhärenten Wartezeit in der PollingRelease-Klasse ist, ist immer noch einiger Wartezeit für den Umgang mit.Der Hauptnachteil bei überwachenden Ansatz ist jedoch seine zustandsfrei sind, so dass alle Knoten bereitgestellt werden, nachdem das Release-Signal übertragen wurde ebenfalls nicht dieses Ereignis und angehaltenen bleiben würde.Natürlich eine offensichtliche Lösung möglicherweise zum Kombinieren der Service Bus, und ein globales Flag im Blob-Speicher, aber ich werde, die als Übung für den Leser lassen.

Beispielcode

Die zugehörigen Beispielprojektmappe ist verfügbar unter code.msdn.microsoft.com/mag201011Sync-und enthält eine ReadMe-Datei, die die erforderlichen Komponenten enthält und die Anweisungen zu Setup und Konfiguration. Das Beispiel verwendet die ListeningRelease PollingRelease und UniqueIdGenerator in einer einzigen Worker-Rolle.

Josh Verflechtung  ist principal Anwendung Development Manager mit den Premier Support für Entwickler-Team in Großbritannien und Blogging unter thejoyofcode.com-gefunden werden können.

Dank an die folgenden technischen Experten für die Überprüfung der in diesem Artikel: David Goon, Morgan Skinner und Wade Wegner