Broker Pattern

Broker Pattern

vg

Das Broker Pattern ist ein Strukturmuster, das in verteilten Systemen verwendet wird. Es ermöglicht die Kommunikation zwischen verschiedenen Clients und Servern, indem ein Broker als Vermittler agiert. Der Broker übernimmt die Verantwortung für die Anforderung und Ausführung von Operationen auf entfernten Objekten, die auf verschiedenen Maschinen laufen können. Dadurch wird die direkte Kommunikation zwischen den Clients und den Servern vermieden, was die Flexibilität und Wartbarkeit des Systems erhöht.

Das Muster wird hauptsächlich in verteilten Systemen und Service-orientierten Architekturen (SOA) eingesetzt, bei denen es auf die Entkopplung von Komponenten ankommt. In diesem Zusammenhang handelt es sich bei einem Broker um eine zentrale Instanz, die sowohl als Vermittler als auch als Koordinator von Anfragen fungiert. Dies ermöglicht eine klare Trennung der Verantwortlichkeiten und erleichtert die Verwaltung von Netzwerkkommunikationen.

Funktionsweise des Broker Patterns

Im Broker Pattern gibt es mehrere Hauptkomponenten:

  1. Client: Der Client ist der Benutzer oder die Anwendung, die eine Anfrage an ein entferntes Objekt stellen möchte.
  2. Broker: Der Broker empfängt Anfragen vom Client, vermittelt sie an das entsprechende entfernte Objekt und gibt das Ergebnis zurück.
  3. Server: Der Server stellt das entfernte Objekt zur Verfügung, das die angeforderten Operationen ausführt.
  4. Remote Objects: Diese Objekte sind auf einem Server oder mehreren Servern verteilt und bieten eine API für den Zugriff.

Die Kommunikation erfolgt typischerweise über Netzwerkprotokolle wie HTTP, TCP oder RPC (Remote Procedure Call). Der Broker übernimmt die Aufgabe, die korrekte Zuordnung der Anfragen zu den Servern vorzunehmen und das Ergebnis zurückzugeben.

Beispiel in C++

Angenommen, wir entwickeln eine einfache verteilte Anwendung in C++, bei der Clients über einen Broker mit einem entfernten Service kommunizieren. Wir haben eine einfache Serveranwendung, die eine add-Methode zur Addition von zwei Zahlen bereitstellt. Der Broker wird die Anfrage empfangen, an den Server weiterleiten und das Ergebnis zurück an den Client senden.

Broker

#include <iostream>
#include <memory>
#include <unordered_map>

class Service {
public:
    virtual int add(int a, int b) = 0;
};

class AddService : public Service {
public:
    int add(int a, int b) override {
        return a + b;
    }
};

class Broker {
public:
    void registerService(const std::string& name, std::shared_ptr<Service> service) {
        services[name] = service;
    }

    std::shared_ptr<Service> getService(const std::string& name) {
        return services[name];
    }

private:
    std::unordered_map<std::string, std::shared_ptr<Service>> services;
};

int main() {
    Broker broker;
    std::shared_ptr<Service> addService = std::make_shared<AddService>();
    broker.registerService("addService", addService);

    std::shared_ptr<Service> service = broker.getService("addService");
    int result = service->add(3, 4);

    std::cout << "Result of addition: " << result << std::endl;
    return 0;
}

In diesem Beispiel haben wir einen Broker, der einen Service registriert und die Anfrage vom Client an den Service weitergibt. Der Client ruft die Methode add auf, und der Broker sorgt dafür, dass der Server (AddService) die Anfrage bearbeitet.

Beispiel in Python

Hier ist ein einfaches Beispiel für das Broker Pattern in Python:

Broker Pattern Beispiel

from abc import ABC, abstractmethod

# Die Server-Klasse (Provider)
class Server(ABC):
    @abstractmethod
    def handle_request(self, request):
        pass

# Ein konkreter Server, der eine Anfrage verarbeitet
class ConcreteServer(Server):
    def handle_request(self, request):
        return f"Anfrage '{request}' wurde vom Server verarbeitet."

# Der Broker, der als Vermittler fungiert
class Broker:
    def __init__(self):
        self._servers = {}

    def register(self, server_name, server):
        self._servers[server_name] = server

    def unregister(self, server_name):
        if server_name in self._servers:
            del self._servers[server_name]

    def handle_request(self, server_name, request):
        if server_name in self._servers:
            server = self._servers[server_name]
            return server.handle_request(request)
        else:
            return f"Server '{server_name}' nicht gefunden."

# Client, der eine Anfrage über den Broker stellt
class Client:
    def __init__(self, broker):
        self.broker = broker

    def make_request(self, server_name, request):
        return self.broker.handle_request(server_name, request)

# Beispiel der Anwendung
if __name__ == "__main__":
    broker = Broker()

    # Server registrieren
    server1 = ConcreteServer()
    broker.register("Server1", server1)

    # Client erstellen
    client = Client(broker)

    # Anfrage über den Broker senden
    print(client.make_request("Server1", "Datenanfrage"))
    print(client.make_request("Server2", "Datenanfrage"))

Erklärung:

  • Server: Eine abstrakte Klasse, die die Schnittstelle für Server definiert.
  • ConcreteServer: Ein konkreter Server, der eine Anfrage bearbeitet.
  • Broker: Der Broker verwaltet Server und leitet Anfragen an den entsprechenden Server weiter.
  • Client: Der Client stellt Anfragen über den Broker, ohne sich um den konkreten Server kümmern zu müssen.

Ausgabe:

Anfrage 'Datenanfrage' wurde vom Server verarbeitet.
Server 'Server2' nicht gefunden.

In diesem Beispiel stellt der Client eine Anfrage, die vom Broker an den richtigen Server weitergeleitet wird. Der Broker ist dafür verantwortlich, die Kommunikation zu verwalten, ohne dass der Client direkt mit einem bestimmten Server kommunizieren muss.

Vorteile des Broker Patterns

  1. Entkopplung von Client und Server: Der Broker vermittelt zwischen dem Client und dem Server, sodass diese Komponenten nicht direkt miteinander kommunizieren müssen. Der Client muss keine Details über den Server kennen, was die Flexibilität und Wartbarkeit des Systems erhöht.
  2. Erhöhte Flexibilität: Der Broker kann Anfragen dynamisch an verschiedene Server weiterleiten, abhängig von verschiedenen Faktoren wie Verfügbarkeit oder Last. Dies macht das System skalierbar und anpassbar.
  3. Zentralisierte Fehlerbehandlung: Fehlerbehandlung und Protokollierung können im Broker zentralisiert werden, was die Wartung vereinfacht. Fehler werden nicht mehr auf den Clients oder Servern, sondern im Broker behandelt.
  4. Wiederverwendbarkeit und Modularität: Durch die Trennung von Anwendungslogik und Kommunikationsmechanismen können Server und Clients wiederverwendet und geändert werden, ohne dass die gesamte Architektur beeinflusst wird.
  5. Einfache Erweiterung: Neue Server können leicht zum Broker hinzugefügt werden, ohne dass die bestehenden Clients Änderungen erfordern. Dies erleichtert das Hinzufügen neuer Funktionen.

Nachteile des Broker Patterns

  1. Leistungseinbußen: Die zusätzliche Vermittlung durch den Broker kann zu einer Verzögerung in der Kommunikation führen. Die Performance kann beeinträchtigt werden, insbesondere wenn der Broker über das Netzwerk kommuniziert und eine große Anzahl von Anfragen verarbeitet.
  2. Komplexität des Brokers: Der Broker kann eine komplexe zentrale Instanz werden, die viele Aufgaben übernimmt. Diese Komplexität kann dazu führen, dass der Broker schwer wartbar oder erweiterbar wird, wenn die Anforderungen steigen.
  3. Single Point of Failure: Der Broker stellt einen zentralen Punkt dar, durch den alle Anfragen gehen. Fällt der Broker aus, wird das gesamte System beeinträchtigt, was zu einem Single Point of Failure führen kann.
  4. Verwaltung von Remote-Objekten: In einem verteilten System müssen die Server sicherstellen, dass ihre Remote-Objekte korrekt verwaltet und aktualisiert werden. Der Broker muss dafür sorgen, dass die Server korrekt miteinander kommunizieren, was zusätzliche Komplexität in der Verwaltung erzeugt.
  5. Sicherheit: Da der Broker als Vermittler fungiert, muss er sicherstellen, dass die Kommunikation zwischen den Komponenten sicher ist. Andernfalls könnte ein Angreifer den Broker kompromittieren, um Zugriff auf vertrauliche Daten oder Dienste zu erhalten.

Wann sollte man den Broker Pattern einsetzen?

Das Broker Pattern sollte verwendet werden, wenn es notwendig ist, die Kommunikation zwischen verteilten Komponenten oder Diensten zu vermitteln, ohne dass diese direkt miteinander kommunizieren müssen. Es hilft, Systeme zu entkoppeln, und bietet eine zentrale Instanz, die Anfragen von Clients empfängt und an die entsprechenden Server oder Dienste weiterleitet.

Hier sind einige Szenarien, in denen das Broker Pattern sinnvoll ist:

1. Verteilte Systeme

  • Wenn du ein System hast, in dem mehrere Server oder Dienste in einem Netzwerk miteinander kommunizieren müssen, ohne dass die einzelnen Komponenten direkt voneinander wissen. Der Broker stellt sicher, dass die Kommunikation transparent und einfach bleibt, ohne dass die Clients wissen müssen, wo und wie die Anfragen verarbeitet werden.
  • Beispiel: In einem Microservices-Architektur, bei der verschiedene Dienste (z. B. Authentifizierungs-, Zahlungs– und Benutzerdaten-Dienste) über das Netzwerk miteinander interagieren müssen.

2. Entkopplung von Clients und Servern

  • Der Broker Pattern hilft, die Kopplung zwischen den Clients und den Servern zu reduzieren. Clients müssen nicht wissen, welcher Server die Anfrage bearbeitet oder wie die Backend-Logik aufgebaut ist. Sie senden einfach ihre Anfragen an den Broker, der sie an den richtigen Server weiterleitet.
  • Beispiel: In einem Webservice-Client, der über den Broker eine Anfrage stellt, ohne sich um die spezifische Implementierung des Zielservers zu kümmern.

3. Load Balancing und Lastverteilung

  • Wenn du die Lastverteilung zwischen mehreren Servern automatisieren möchtest, kann der Broker als Vermittler die Anfragen gleichmäßig auf verschiedene Server verteilen. Dies ist besonders nützlich, wenn du eine skalierbare Architektur benötigst.
  • Beispiel: Ein Broker, der eingehende HTTP-Anfragen an verschiedene Webserver verteilt, um die Last gleichmäßig zu verteilen.

4. Fehlerbehandlung und Überwachung

  • Der Broker kann auch dafür verantwortlich sein, Fehler zu handhaben, Anfragen neu zu versuchen oder Serverstatus zu überwachen. Dies macht das System robuster, da der Broker in der Lage ist, mit Ausfällen von Servern oder Komponenten umzugehen, ohne dass der Client davon betroffen ist.
  • Beispiel: Wenn ein Server ausfällt, kann der Broker automatisch eine Anfrage an einen anderen Server weiterleiten.

5. Integration heterogener Systeme

  • Der Broker ist hilfreich, wenn du unterschiedliche Systeme oder Protokolle integrieren möchtest. Da der Broker als Vermittler fungiert, kann er unterschiedliche Kommunikationsmethoden (z. B. REST, SOAP, gRPC) miteinander verbinden.
  • Beispiel: Ein Broker, der Anfragen von Clients empfängt, die RESTful API-Aufrufe machen, und diese Anfragen an einen Server weiterleitet, der eine SOAP-basierte API verwendet.

6. Verwaltung von Kommunikation in komplexen Architekturen

  • In großen, komplexen Systemen mit vielen miteinander kommunizierenden Diensten oder Anwendungen hilft der Broker, die Kommunikation zu vereinfachen, indem er als zentraler Vermittler fungiert. So müssen sich die einzelnen Komponenten nicht um die Interaktion mit anderen Systemen kümmern, sondern nur um den Broker.
  • Beispiel: Ein Broker, der als Middleware zwischen einem Frontend (Client) und verschiedenen Backend-Diensten fungiert.

Du solltest das Broker Pattern verwenden, wenn du die Kommunikation zwischen verteilten Systemen oder verschiedenen Komponenten verwalten und koordinieren musst, ohne dass die einzelnen Teile direkt miteinander kommunizieren. Es ist besonders hilfreich bei der Entkopplung von Clients und Servern, der Lastverteilung, der Fehlerbehandlung und der Integration unterschiedlicher Systeme. Es ist also ideal für große, skalierbare, verteilte Systeme.

Was ist der Unterschied zwischen Broker Pattern und Mediator Pattern?

Der Mediator Pattern und der Broker Pattern sind beide Verhaltensmuster, die die Kommunikation zwischen verschiedenen Komponenten vermitteln, aber sie unterscheiden sich in ihrer Funktionsweise und ihrem Einsatzbereich.

1. Mediator Pattern:

Das Mediator Pattern konzentriert sich auf die zentrale Verwaltung der Kommunikation zwischen verschiedenen Objekten, um die Komplexität zu reduzieren und direkte Abhängigkeiten zu vermeiden.

  • Ziel: Der Mediator fungiert als zentraler Vermittler, der die Kommunikation zwischen mehreren Objekten oder Komponenten steuert. Anstatt dass Objekte direkt miteinander kommunizieren, sprechen sie nur mit dem Mediator, der dann dafür sorgt, dass die Kommunikation zwischen den Objekten korrekt weitergeleitet wird.
  • Funktionsweise: In einem Mediator-Pattern ist der Mediator ein Objekt, das alle Interaktionen zwischen den Komponenten steuert. Die Komponenten (auch „Colleagues“ genannt) kommunizieren nicht direkt miteinander, sondern nur über den Mediator. Dadurch wird der Code vereinfacht und die Kopplung zwischen den Komponenten reduziert.
  • Verwendung: Es wird häufig in Anwendungen verwendet, bei denen mehrere Objekte miteinander interagieren müssen, aber die direkte Kommunikation zwischen ihnen zu einer zu starken Kopplung und komplexem Code führen würde.

Beispiel: Stellen Sie sich eine Chat-Anwendung vor, bei der mehrere Benutzer miteinander kommunizieren möchten. Statt dass jeder Benutzer direkt mit jedem anderen Benutzer Nachrichten austauscht, verwenden alle Benutzer einen zentralen Chat-Mediator, der die Nachrichten an die entsprechenden Empfänger weiterleitet.

class Mediator:
    def send(self, message, colleague):
        pass

class ConcreteMediator(Mediator):
    def __init__(self):
        self.colleague1 = None
        self.colleague2 = None

    def set_colleague1(self, colleague):
        self.colleague1 = colleague

    def set_colleague2(self, colleague):
        self.colleague2 = colleague

    def send(self, message, colleague):
        if colleague == self.colleague1:
            self.colleague2.receive(message)
        else:
            self.colleague1.receive(message)

class Colleague:
    def __init__(self, mediator):
        self.mediator = mediator

    def send(self, message):
        self.mediator.send(message, self)

class ConcreteColleague1(Colleague):
    def receive(self, message):
        print(f"Colleague1 erhält Nachricht: {message}")

class ConcreteColleague2(Colleague):
    def receive(self, message):
        print(f"Colleague2 erhält Nachricht: {message}")

2. Broker Pattern:

Das Broker Pattern wird vor allem in verteilten Systemen verwendet, um die Kommunikation zwischen verschiedenen, dezentralen Komponenten oder Diensten zu ermöglichen.

  • Ziel: Der Broker agiert als Vermittler, der Anfragen von Clients entgegennimmt und sie an den entsprechenden Server oder Dienst weiterleitet. Es sorgt dafür, dass die Clients und Server voneinander entkoppelt sind, was bedeutet, dass Clients nicht wissen müssen, welcher Server oder Dienst die Anfrage tatsächlich verarbeitet.
  • Funktionsweise: In einem Broker Pattern gibt es einen zentralen Broker, der als Zwischeninstanz fungiert. Der Broker empfängt Anfragen von Clients und leitet diese an die entsprechenden Server oder Dienste weiter. Der Broker sorgt dabei für die Vermittlung und Verwaltung der Kommunikation, kann aber auch Funktionen wie Lastenverteilung und Fehlerbehandlung übernehmen.
  • Verwendung: Das Broker Pattern wird typischerweise in verteilten Systemen oder in Architekturen verwendet, in denen unterschiedliche Dienste oder Server über ein Netzwerk kommunizieren müssen.

Beispiel: Ein Broker könnte in einem Service-orientierten Architektur (SOA) verwendet werden, bei dem ein Client eine Anfrage an den Broker sendet, der dann den entsprechenden Service im Backend aufruft.

class Broker:
    def __init__(self):
        self.servers = {}

    def register(self, server_name, server):
        self.servers[server_name] = server

    def forward_request(self, server_name, request):
        if server_name in self.servers:
            return self.servers[server_name].handle_request(request)
        else:
            return f"Server {server_name} nicht gefunden."

class Server:
    def handle_request(self, request):
        pass

class ConcreteServer(Server):
    def handle_request(self, request):
        return f"Verarbeite Anfrage: {request}"

Hauptunterschiede:

MerkmalMediator PatternBroker Pattern
ZweckZentralisiert die Kommunikation zwischen Objekten.Vermittelt die Kommunikation zwischen Clients und Servern.
Typ der KomponentenIn der Regel ein einfaches Zusammenspiel zwischen Objekten in einer Anwendung.Meistens in verteilten Systemen mit mehreren Servern oder Diensten.
KommunikationObjekte kommunizieren nur über den Mediator.Clients kommunizieren mit dem Broker, der Anfragen an die Server weiterleitet.
KomplexitätEinfach, dient zur Vermeidung von direkter Kopplung.Komplexer, da es mit verteilten Systemen und Netzwerkkommunikation arbeitet.
BeispielEin Chat-System, bei dem Nachrichten über einen zentralen Mediator gesendet werden.Ein Client sendet eine Anfrage an einen Broker, der diese an einen Server weiterleitet.

Zusammenfassend lässt sich sagen, dass der Mediator mehr für die Vereinfachung der Kommunikation zwischen Objekten innerhalb einer Anwendung zuständig ist, während der Broker als Vermittler in einem verteilten System fungiert, um Anfragen von Clients zu Servern zu leiten.

Fazit

Das Broker Pattern ist ein äußerst nützliches Architektur-Pattern für verteilte Systeme, das die Kommunikation zwischen verschiedenen Komponenten vereinfacht und flexibler gestaltet. Besonders in großen, skalierbaren Systemen oder Service-orientierten Architekturen (SOA) ist es von Vorteil. Dennoch ist es wichtig, sich der möglichen Nachteile bewusst zu sein, insbesondere hinsichtlich der Leistung und der zentralen Fehlerbehandlung. Bei der Wahl des Broker Patterns sollte immer abgewogen werden, ob die Vorteile die potenziellen Performanceprobleme und die zusätzliche Komplexität überwiegen.

Zur Pattern-Übersicht: Liste der Design-Pattern

com

Newsletter Anmeldung

Bleiben Sie informiert! Wir informieren Sie über alle neuen Beiträge (max. 1 Mail pro Woche – versprochen)