Windows Azure Service Bus - Distributed Web Counter

Technologie: Windows Azure Service Bus

Fokus: Neue Lösungseinsätze mit Verwendung von PaaS

von Damir Dobric (MVP)

Dn425057.7B654F178A3842F7F616A829DC6DF588(de-de,MSDN.10).png

September, 2013

Entwickler verteilter Anwendungen kennen aus Erfahrung die Situation, dass oft durch einen Beteiligten im System die Notwendigkeit besteht, einen Sequence Counter zu implementieren, welcher eine neue Nummer generiert, die von jeder im verteilten System beteiligten Anwendung in Anspruch genommen werden kann. Anders ausgedrückt, stellen Sie sich einige Anwendungen vor, die miteinander explizit nichts zu tun haben. Nehmen wir weiter an, diese Anwendungen sind Bestandteil eines Bestellungssystems. Unabhängig davon was diese Anwendungen tun und wie sie dies tun, am Ende müssen alle eine Bestellung generieren. Das Ziel ist, dass jede Bestellung eine Bestellnummer hat, die eine Nummer im Kontext dieses Bestellsystems ist. Wenn zum Beispiel die erste Anwendung eine Bestellung mit der Nummer 1 generiert, soll die nächste Bestellnummer, egal von welcher Anwendung sie generiert wird, die Nummer 2 sein und so weiter. Diese Aufgabenstellung soll in diesem Artikel mithilfe des Service Bus gelöst werden.

Vor langer Zeit als Client Server-Architekturen implementiert wurden, war dies relativ einfach durch die Sequenznummerierung ** der Datenbank zu lösen. Jeder Client hatte direkte Verbindung zur Datenbank und daher einfach die nächste Nummer gezogen bzw. generiert. Im Zeitalter der Dienste wurde die Aufgabe der Lösung des Counter-Problems an einen Dienst übergeben. Jetzt, in der Welt von SOA und Services, verlagerte man diese Lösung logischerweise in einen Service. Dies geschah nicht einfach deshalb, weil Services cooler sind als Datenbanken, sondern vor allem weil in einem System mit verteilten Anwendungen die Datenbank sehr selten vom Client aus erreichbar ist. Des Weiteren wird durch die Verwendung von Services in der Architektur eine fast unendliche Skalierung ermöglicht. Dies ist mit Datenbanken nur sehr begrenzt möglich und mit den stark verteilten Systemen im Web nahezu unmöglich, ganz abgesehen von den Schwierigkeiten moderne Sicherheitsansprüche zufriedenzustellen.

Daraus folgt, dass ein fest zugeordneter Dienst implementiert wird, der die Rolle eines Counter Generator übernimmt. Wie das folgende Bild zeigt, konsumieren zwei Geräte den Sequence Generator Service. Der Service verwendet vermutlich im Hintergrund eine Datenbank oder sogar einen Distributed Cache. Aus der Sicht des Consumers ist dies aber nur ein unwichtiges Implementierungsdetail.

Dn425057.27B0939C73F0AA074F28F5343D6A7BE5(de-de,MSDN.10).png

So lange Sie die Kontrolle über die Infrastruktur und Geräte haben, ist dies eine valide Lösung, die heute noch in Unternehmen verwendet wird. Aber wie sieht es aus, wenn Ihr System über das Web verteilt ist?

Ähnlich wie im Falle eines Unternehmens, kann man im Grunde dasselbe tun. Sie können einen Dienst als Worker Role (dies ist eine Möglichkeit, die dediziert für Windows Azure geeignet ist) erstellen und eine Datenbank ** (oder Table Storage) ** erzeugen, die den Wert des Counters speichert. Um dies zu tun, benötigen Sie einen öffentlichen Service (mit Public IP) und eine Datenbank. Für die Realisierung muss der Service implementiert und installiert und die Datenbank konzipiert und installiert werden. Am Ende sind die Aufwände für die Infrastruktur nicht zu vergessen.

Dieser Artikel will zeigen, dass Windows Azure als Cloud Computing-Plattform eine ganze Reihe PaaS-Funktionen (Platform as a Service) bietet, mit denen derartige Aufgabenstellungen viel einfacher gelöst werden können.

In diesem konkreten Fall wird gezeigt, wie der Windows Azure Service Bus für diesen Zweck eingesetzt werden kann. Im Grunde wird eine sehr einfache Lösung konzipiert, die den Service Bus als State Maschine verwendet. Sie werden merken, dass diese Lösung nicht nur günstiger und schneller zu realisieren ist als andere Lösungen, sondern darüber hinaus auch Notifications, extrem hohe Skalierung, verschiedene Protokolle (Service Bus native Protokoll, AMQP und REST) und keine Infrastruktur-Aktivitäten bietet. Um dies zu demonstrieren, wurde ein Prototyp-API auf Basis des Service Bus SDK (unterstützt von Versionen ab 1.8) implementiert.

Folgendes Bild zeigt wie die Architektur jetzt im Falle eines Cloud Counters aussieht:

Dn425057.040799E9EB29352F1380D2AABDFC5D62(de-de,MSDN.10).png

In diesem Falle gibt es keinen expliziten Dienst mehr, den man implementieren und installieren muss. Vielmehr wird die Cloud als einzige Dependency verwendet.

Das WebCounter API, welches die Counter-Funktionalität implementiert, sollte hinter dem Service Bus Feature Set verborgen werden. Diejenigen, die sich mit Messaging-Szenarien gut auskennen, sollten versuchen, den vereinfachten Codeausschnitt zu verstehen. Die anderen sollten einfach davon ausgehen, dass es ein WebCounter API (Bibliothek) gibt, welches nach „außen“ keine Spur des Service Bus hergibt.

Die Beispiel-Implementierung sieht aus der Sicht eines Entwicklers folgendermaßen aus:

WebCounter counter = new WebCounter(config parameters);
var val = counter.GetNext();

Optional kann man den Counter auch zurücksetzen:

counter.ResetValue(7);

In Bezug auf das API ist dies mehr oder weniger schon alles. Es sieht sehr trivial aus und man benötigt nicht einmal eine Dokumentation um zu loszulegen. Und das ist genau die Idee dieses Artikels, zu zeigen, wie nützliche Szenarien unter Zuhilfenahme von PaaS gestaltet werden können.

Wie funktioniert es?

Zu Beginn muss das WebCounter API im Hintergrund eine Queue erzeugen, welche benutzt wird, um den Counter-Wert zu persistieren. Um dies zu tun, muss die Initialisierung wie folgt eingeleitet werden:

public WebCounter(string connStr, string contextName, string counterName)

connStr ist der Service Bus Connection string und vergleichbar mit:

Endpoint=sb://xyzuvw.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=…obfuscated.="

Dieser Parameter ist das Einzige, das der Entwickler vom Service wissen muss.

contextName definiert die Business Domain des counters, z.B. ‘MyClinicalDevicesCounter’.

counterName definiert den Namen des Subkontextes innerhalb des Business-Kontextes wie ‘BloothTestCounter’ oder ‘RentgenScanCounter’. Somit können Sie mehrere Counters mit einem Connection String verwenden, die verschiedene Systeme verwenden können.

Im Hintergrund wird der Service Bus zwei Queues mit den Namen “MyClinicalDevicesCounter/BloothTestCounter” und “MyClinicalDevicesCounter/RentgenScanCounter” erzeugen. Diese Queues werden den Wert der Counter in der Form einer Message halten.

Intern wird die Queue wie folgt kreiert:

private void createCounterQueue() 
{ 
NamespaceManager namespaceManager = NamespaceManager.CreateFromConnectionString(m_ConnStr); 
QueueDescription desc = new QueueDescription(getQueueName()); 
desc.RequiresSession = true; 

try 
{ 
var qD = namespaceManager.CreateQueue(desc); 
} 
catch (Microsoft.ServiceBus.Messaging.MessagingEntityAlreadyExistsException) 
{ 

} 
} 

Die Queue ist dabei eine Session-Enabled-Queue. Dies bedeutet, dass nur eine Anwendung zu einem Zeitpunkt die Queue nutzen kann. Da die Queue in dieser Implementierung benutzt wird, um die Message mit dem letzten Counter-Wert zu erhalten, werden keine weiteren Messages in der Queue erwartet.

Nun werfen wir einen Blick darauf, wie der Counter-Wert generiert wird. Als erstes wird eine Receiver Session erstellt. Der Receiver wird entweder eine NULL-Message zurückschicken (beim ersten Call) oder dem Counter Value einen Wert zuweisen.

Danach wird der nächste Wert kalkuliert (0 falls dies die erste Message ist oder Value++). Direkt nachdem die Message erhalten wurde, wird der neue Wert in die Queue geschrieben. Da der Session Receiver offen ist, während die Message geschrieben wird, kann kein anderer Client Messages erhalten. Während die Annahme blockiert ist, wird der Client den neuen Wert schreiben, usw.

Leider hat jeder Client im Web in diesem Szenario die Möglichkeit der Queue eine Message zu senden. In diesem Fall könnte ein Anbieter solcher Clients theoretisch die Möglichkeit haben, das System zu kompromittieren.
So lange der Queue-Name verschleiert ist, die Message verschlüsselt und der Client auf dem Gerät sicher ist, sollte dies aber kein großes Problem darstellen. Nichtsdestotrotz sollte man sich dieses Risikos zumindest bewusst sein.

Dieser Codeschnipsel zeigt, wie das „Counting“ implementiert wird:

public long GetNext()
        {
            QueueClient client = QueueClient.CreateFromConnectionString(m_ConnStr, getQueueName(), ReceiveMode.PeekLock);

            while (true)
            {
                MessageSession sessionReceiver = null;

                try
                {
                    sessionReceiver = client.AcceptMessageSession(m_QueueName, TimeSpan.FromSeconds(10));

                    long cnt = 1;

                    var msgs = sessionReceiver.ReceiveBatch(100);
                   
                    if (msgs.Count() > 0)
                    {
                        BrokeredMessage msg = msgs.Last();

                        cnt = msg.GetBody<long>();

                        cnt++;

                        client.Send(createMessage(cnt));
                    }
                    else
                        client.Send(createMessage(0));

                    foreach (var msg in msgs)
                    {
                         msg.Complete();
                    }
                 

                    return cnt;
                }
                catch (SessionCannotBeLockedException)
                {

                }
                catch (SessionLockLostException)
                {
                    throw new Exception("SessionLockLostException");
                }
                catch (Exception ex2)
                {
                    throw;
                }
                finally
                {
                    if (sessionReceiver != null)
                        sessionReceiver.Close();
                }
            }
        }

Fazit:

Dieser Artikel zeigt, dass durch die Verwendung von Cloud Plattform-Komponenten viele neue Einsatz- und Implementierungsmöglichkeiten entstehen. In einer Zeit, in der viel über das Thema Datenschutz diskutiert wird und die Akzeptanz von Cloud-Angeboten noch gering ist, ist sehr wichtig zu verstehen, dass es sich bei Windows Azure um eine neue Technologie mit neuen Ansätzen handelt:

Windows Azure bietet zahlreiche Plattform-Komponenten an, welche viele neue Möglichkeiten für innovative Konzepte und Lösungen bieten. Das in diesem Artikel beschriebene Szenario mag von der Anforderung her eher trivial und gewöhnlich erscheinen, es zeigt aber durchaus, dass auch einfache Szenarien in einer stark verteilten und hybriden Webumgebung zu einer größeren Herausforderung werden können. Gerade im Kontext der Devices und Services-Strategie, die zunehmend an Bedeutung gewinnt, stellt ein „Service Bus“ eine immer wichtigere Rolle dar, die es ermöglicht, ganz neue Wege der Lösungsfindung und Softwareentwicklung zu bestreiten.

von Damir Dobric (MVP)

| Home | Entwicklerbibliothek | Community