Blog
Ereignisgesteuerte Architektur: Die wesentlichen Komponenten jenseits von Kafka

Was ist eine ereignisgesteuerte Architektur? Und warum ist Kafka allein keine ereignisgesteuerte Plattform?
Die ereignisgesteuerte Architektur (EDA) ermöglicht es Anwendungen, über Ereignisse zu kommunizieren, und unterstützt Unternehmen dabei, skalierbare, lose gekoppelte Echtzeitsysteme aufzubauen. Zwar bildet Apache Kafka häufig die Grundlage dieser Architekturen, doch der Aufbau einer unternehmensgerechten ereignisgesteuerten Plattform erfordert weit mehr als nur einen Event-Broker.
Wenn Teams eine ereignisgesteuerte Architektur einführen, ist das erste große Problem in der Regel nicht Kafka. Es ist vielmehr alles, was um Kafka herum aufgebaut werden muss. Der Broker ist eine Standardkomponente: gut verstanden, gut instrumentiert, gut unterstützt. Was ein ereignisgesteuertes System von einem Projekt unterscheidet, bei dem es lediglich heißt „Wir haben jetzt Kafka“, ist der unterstützende Stack: Erkennung, Verträge, Beobachtbarkeit, Sicherheit, Governance und die Entwicklererfahrung, die all diese Aspekte miteinander verbindet.
Wir haben die letzten Jahre damit verbracht, eine Referenzumgebung aufzubauen, die diese Bereiche ernst nimmt. Es handelt sich nicht um eine Produktpräsentation. Es ist ein praxiserprobter Stack mit End-to-End-Implementierungen für jeden dieser Aspekte. Es geht nicht um die Werkzeuge. Es geht um die Natur des Problems und die Abwägungen, auf die wir auf jeder Ebene immer wieder zurückkommen. Dieser Beitrag bietet einen Überblick über diese Bereiche auf der Ebene von „Was ist wichtig und warum?“, wobei für jeden Bereich separate vertiefende Beiträge folgen werden.
Wenn Ihr Unternehmen den Schritt von „Wir verfügen über einen Kafka-Cluster“ hin zu „Wir verfügen über eine demokratisierte, selbstbedienbare, ereignisgesteuerte Plattform“ vollzieht, finden Sie im Folgenden eine Übersicht über die Aspekte, die Sie dabei berücksichtigen müssen.
Die wesentlichen Komponenten einer ereignisgesteuerten Plattform
Im Kern ist ein ereignisgesteuertes System trügerisch einfach: Produzenten veröffentlichen Inhalte auf einer Streaming-Plattform, Konsumenten lesen diese, und Schemata werden mit jedem Ereignis weitergegeben. Dieser Kern bleibt stets unverändert. Was sich darum herum entwickelt, ist eine Reihe von Themenbereichen, von denen jeder für sich eine eigenständige Disziplin darstellt.

Wir gliedern diese Anliegen in fünf Bereiche, die sich jeweils in zwei Unterbereiche unterteilen, sowie eine übergreifende Ebene, die alle anderen Bereiche umfasst:
- Demokratisierung von Ereignissen: Ereignisse auffindbar und durchsuchbar machen: eine kuratierte Oberfläche für den Ereigniskatalog und die Ereignissuche sowie eine Rohdaten-Oberfläche für Kafka und die Ereignissuche.
- Kafka-Management: Betrieb der Plattform: Governance und Self-Service zur Festlegung, wer welche Aufgaben ausführen darf, sowie Überwachung des Betriebszustands.
- Beobachtbarkeit und Fehlerbehebung: Das Laufzeitverhalten verstehen: Ereignistopologie und -herkunft ( die quasi statische Darstellung, wer mit wem kommuniziert) sowie Tracing (die kausale Abfolge pro Anfrage).
- Datenqualität: Gewährleistung der Zuverlässigkeit von Nutzdaten: Schema-Registry und -Weiterentwicklung sowie Qualitätsprüfungen und Vertragstests.
- Datensicherheit: Schutz der Daten und des Zugriffs darauf: Zugriffskontrolle und Verschlüsselung sowie DSGVO / personenbezogene Daten / Compliance.
- Entwicklerportal / Marktplatz (bereichsübergreifend): eine einheitliche Self-Service-Oberfläche für alle oben genannten Bereiche: ein Katalog, eine zentrale Anlaufstelle für Zugangsanfragen, ein zentraler Einstiegspunkt.
Jeder dieser Bereiche ist eine Kombination aus Methodik und Werkzeugen. Die zu frühe Auswahl eines Werkzeugs ist der häufigste Grund für Misserfolge, den wir beobachten. Im Folgenden erläutern wir unsere Sichtweise auf die einzelnen Bereiche sowie die beiden damit verbundenen Aspekte.
Demokratisierung von Veranstaltungen
Die wichtigste Umstellung, die ereignisgesteuerte Teams vornehmen, besteht darin, Ereignisse als Produkte mit Verantwortlichen, Vereinbarungen, Nutzern und Lebenszyklen zu betrachten und nicht als flüchtige Nachrichten auf einem Bus. Die Demokratisierung ist es, die dies für den Rest der Organisation greifbar macht: Wenn Mitarbeiter ein Ereignis nicht finden können, ist es kein Produkt, sondern ein Geheimnis.
Veranstaltungskatalog und -suche
Sie benötigen einen Katalog, der auflistet, welche Ereignisse es gibt, wem sie zugeordnet sind, was sie bedeuten und welche Abläufe darauf aufbauen. Wir bauen dies auf einem automatisch gefüllten Ereigniskatalog auf, der den Änderungsereignisstrom der Schema-Registrierung abhört: Jedes Mal, wenn ein Schema oder eine Spezifikation registriert wird, spiegelt der Katalog dies innerhalb von Sekunden wider. Organisatorische Metadaten (Teams, Domänen, Zuständigkeiten) werden aus der Versionskontrolle übernommen, wo sie hingehören.
Der Kompromiss, den wir stets im Blick behalten: Ein Katalog, der manuell gepflegt werden muss, ist bereits nach einem Quartal veraltet. Ein vollständig auf Metadaten basierender Katalog gibt jedes interne Thema an jeden Entwickler weiter. Der ideale Mittelweg liegt in der automatischen Erkennung und manuellen Kuratierung: Der Katalog erfasst Ereignisse aus der Registry, zeigt jedoch nur das an, was die Produzenten ausdrücklich deklarieren, sodass die Teams die Kontrolle darüber behalten, was öffentlich zugänglich ist.
Kafka-Benutzeroberfläche und Ereignissuche
Der Katalog beantwortet die Fragen„Welche Ereignisse gibt es und was bedeuten sie?“. Er beantwortet jedoch nicht die Fragen„Was wird derzeit tatsächlich unter orders-completed angezeigt, und warum sieht diese eine Meldung falsch aus?“. Das ist die operative Ergänzung: eine Benutzeroberfläche, über die Sie Themen durchsuchen, Live-Meldungen einsehen, nach Schlüssel oder Inhalt suchen und die Offsets der Verbrauchergruppen überprüfen können.
Diese Unterscheidung ist von Bedeutung. Der Katalog stellt die kuratierte Ansicht auf Vertragsebene dar : das Produktregal. Die operative Benutzeroberfläche ist die rohe Ansicht auf Byte-Ebene: die Laderampe. Teams greifen auf die erste Oberfläche zurück, um ein Ereignis zu entwerfen, und auf die zweite, um es zu debuggen. Werden beide miteinander vermischt, entsteht entweder ein mit betrieblichen Störsignalen überladener Katalog oder ein Debugging-Tool, das so tut, als seien die Nutzdaten stets wohlgeformt. Wir behalten sie als zwei separate Oberflächen bei, die jeweils zwei unterschiedlichen Fragestellungen dienen.
Kafka-Verwaltung
Sobald Ereignisse erfassbar sind, muss die ihnen zugrunde liegende Plattform bedienbar sein: von vielen Teams, ohne dass ein zentraler Gatekeeper zum Engpass wird und ohne den Überblick darüber zu verlieren, ob sie einwandfrei funktioniert.
Governance und Self-Service
Jede Änderung der Zugriffsrechte („Kann mein neuer Dienst auf ‚orders-completed‘ zugreifen?“) stellt eine potenzielle Schwachstelle dar. Wenn ein Mitarbeiter für jede Zugriffsgewährung eine YAML-Datei bearbeiten und einen Pull-Request einreichen muss, wird sich innerhalb weniger Wochen eine Warteschlange aus ausstehenden Anfragen bilden. Wenn sich jeder selbst beliebige Zugriffsrechte gewähren kann, bricht das Sicherheitsmodell zusammen.
Die Antwort lautet: deklarative Steuerung in Verbindung mit einem darüber liegenden Self-Service-Workflow :
- Ein einziger Deskriptor in Git enthält die verwalteten Themen, die Zugriffsberechtigungen und die Teamverantwortung. Die tatsächlich auf den Cluster angewendeten Artefakte (die ACLs, die Richtliniendaten und alles, was Ihre Engine benötigt) werden aus diesem Deskriptor abgeleitet; sie werden niemals manuell bearbeitet.
- Über ein Self-Service-Portal können Entwickler über eine vertraute Benutzeroberfläche Zugriff beantragen; ein Genehmiger führt die erforderlichen Schritte durch; das Ergebnis wird wieder in den Deskriptor übernommen.
- Der aktuelle Zustand des Clusters lässt sich stets auf eine PR-geprüfte Deklaration zurückführen. Abweichungen zwischen dem Deskriptor und dem Cluster sind in CI erkennbar.
Überwachung
Die Governance legt fest, wer die Plattform nutzen darf; die Überwachung gibt Aufschluss darüber, ob sie den Anforderungen gewachsen ist. Beobachten Sie den Zustand der Broker (Durchsatz, Anzahl der Partitionen, synchronisierte Replikate, Latenz bei Anfragen, Heap) sowie – was den Metrik-Teams als Erstes auffällt – die Verzögerung der Konsumenten pro Gruppe: Denn ein Konsument, der unbemerkt in Rückstand gerät, ist der häufigste Grund dafür, dass ein ereignisgesteuertes System an Leistung verliert, ohne einen Fehler auszugeben.
Das Prinzip, an das wir uns hier halten , lautet: Der Broker ist Teil des Systems und nicht nur dessen Grundlage. Cluster-Metriken und das Anwendungsverhalten gehören auf ein und denselben Bildschirm, da die meisten Vorfälle, bei denen „Kafka langsam ist“, in Wirklichkeit darauf zurückzuführen sind, dass „ein Consumer nicht mehr mithalten konnte“ – eine Frage, die Sie nur beantworten können, wenn Sie beides gleichzeitig betrachten.
Beobachtbarkeit und Fehlerbehebung
Die Überwachung gibt Ihnen Aufschluss darüber, ob die Plattform insgesamt einwandfrei funktioniert. Observability beantwortet die Frage, die sich jedes ereignisgesteuerte Team um 3 Uhr morgens stellt: „Was ist gerade bei diesem Ereignis passiert?“ Die herkömmliche Lösung – „tail -f“ über viele Dienste hinweg – ist nicht skalierbar. Zwei sich ergänzende Ansichten sind es hingegen.
Ereignistopologie und Herkunftsverfolgung
Bevor Sie einen Datenfluss debuggen können, müssen Sie wissen, dass dieser Datenfluss überhaupt existiert. Wer erzeugt Bestellereignisse? Wer nimmt diese auf? In welche Richtungen verzweigt sich der Datenfluss? Wir erhalten diese Informationen auf zwei sich gegenseitig ergänzende Arten: Produzenten und Konsumenten deklarieren ihre Themen in ihren Spezifikationen (Absicht), und die Tracing-Ebene beobachtet tatsächliche Produzent→Konsument-Verbindungen im Live-Datenverkehr (Realität). Wo diese beiden Informationen voneinander abweichen – beispielsweise bei einem deklarierten Konsumenten, der niemals Daten liest, oder einer beobachteten Verbindung, die niemand dokumentiert hat –, stellt diese Diskrepanz an sich bereits einen Befund dar.
Das Prinzip: Die Abstammungsbeziehungen sollten sich aus dem beobachteten Datenverkehr ergeben und nicht manuell gepflegt werden. Ein manuell erstelltes Topologiediagramm ist bereits am Tag nach der Bereitstellung veraltet.
Rückverfolgung
Für die „Per-Request“-Story verketten wir einen OpenTelemetry-Kontext über jeden Hop hinweg, der in einem Kafka-Header übertragen wird. Entscheidend ist, dass wir jede Trace-ID anhand der Geschäfts-UUID am Root-Producer generieren, sodass eine Trace-ID kein undurchsichtiger Hex-Blob ist; sondern es handelt sich um die Auftrags-ID, die Ereignis-ID – also genau das, was Menschen bereits verwenden, um über eine Transaktion zu sprechen. Wenn Sie das Trace-Backend nach der Geschäfts-UUID durchsuchen, erhalten Sie den vollständigen Kausalzusammenhang über alle Dienste hinweg. Ansonsten ist die Trace-Ebene payload-unabhängig; nachgelagerte Dienste müssen das Geschäftsfeld nicht kennen.
Zusätzlich zum Tracing fügen wir RED-Kennzahlen (Rate, Fehler, Dauer pro Thema, pro Dienst) hinzu, die direkt aus den Spans abgeleitet werden; es ist keine separate Instrumentierung in jedem einzelnen Dienst erforderlich. Das Prinzip: Beobachten Sie an der Schnittstelle (jedes „Produce“, jedes „Consume“) und lassen Sie alles andere sich von selbst ergeben. Verlangen Sie von den Entwicklern nicht, mehr zu instrumentieren, als ihnen ihr Framework standardmäßig zur Verfügung stellt.
Sicherstellung der Datenqualität in einer ereignisgesteuerten Architektur
Wenn Ereignisse als Produkte betrachtet werden, müssen ihre Nutzdaten vertrauenswürdig sein: sowohl strukturell (entspricht dies einem Vertrag?) als auch im Zeitverlauf (kann ich den Vertrag weiterentwickeln, ohne dass ein Verbraucher, der nicht vor Ort ist, davon beeinträchtigt wird?).
Schema-Registrierung und -Weiterentwicklung
Schemas stellen den Schnittstellenvertrag eines Ereignisses dar. Die Herausforderung liegt in der Weiterentwicklung: Sobald Sie einen Vertrag veröffentlicht haben, können Sie ihn nicht mehr ändern, ohne dass dies für andere Auswirkungen hat. Eine Schema-Registrierung dient als „Quelle der Wahrheit“ und sorgt bei der Registrierung für Kompatibilität: rückwärts, vorwärts, vollständig; wählen Sie die Regel je nach Thema aus und setzen Sie sie an der Schnittstelle durch, sodass eine inkompatible Änderung bereits im Vorfeld abgelehnt wird, anstatt erst in der Produktion entdeckt zu werden.
Außerdem speichern wir den Vertrag und den Code im selben Repository. Die Spezifikation eines Produzenten befindet sich direkt neben dem entsprechenden Quellcode; Schemata werden beim Start registriert. Es gibt keine „Spezifikationsabweichung“, da die Spezifikation selbst den Build darstellt.
Qualitätsprüfungen und Vertragstests
Die Kompatibilität mit dem Registry-System ist notwendig, aber nicht ausreichend: Sie stellt sicher, dass ein neues Schema kompatibel ist, nicht jedoch, dass es gut ist. Der zweite Aspekt deckt den Rest ab, vor allem im Rahmen der CI: die Überprüfung der Spezifikationen (Wird für jedes Thema ein Eigentümer deklariert? Sind die Operations-IDs konsistent? Werden bei Verbrauchsoperationen Verbrauchergruppen deklariert?) sowie der Abgleich auf bruchbehaftete Änderungen gegenüber dem Basis-Zweig, sodass Probleme bereits vor dem Zusammenführen des Codes zutage treten und nicht erst, nachdem die Produzenten ihre Änderungen veröffentlicht haben.
Dies führt naturgemäß zur Validierung zur Laufzeit. Linting und Diffing belegen, dass der Vertrag wohlgeformt ist; sie können jedoch nicht nachweisen, dass die tatsächlich über ein Topic fließenden Nachrichten diesen Vertrag einhalten: dass der Betrag tatsächlich größer als Null ist, dass eine feldübergreifende Invariante gilt, dass ein Produzent nicht unbemerkt begonnen hat, Nullwerte in einem Feld auszugeben, das er zu füllen versprochen hat. Der nächste Schritt gemäß bewährter Praxis besteht darin, die Validierung auf den Live-Datenverkehr zu verlagern: ein Vertragsmonitor oder ein Validierungsgateway, das semantische Regeln anhand realer Ereignisse überprüft und bei Verstößen eine Warnung ausgibt (oder diese isoliert), sodass eine fehlerhafte Nutzlast bereits im Moment ihrer Veröffentlichung abgefangen wird und nicht erst drei Hops weiter, wenn ein Konsument ausfällt. Betrachten Sie dies als zwei Ebenen derselben Disziplin: strukturelle Verträge, die zum Zeitpunkt der Zusammenführung durchgesetzt werden, und semantische Verträge, die zur Laufzeit durchgesetzt werden; und betrachten Sie die Laufzeitebene als das Ziel einer sich weiterentwickelnden Plattform, auch wenn Sie mit der CI-Ebene beginnen.
Sicherheit einer ereignisgesteuerten Plattform
Dies ist der Bereich, in dem am häufigsten gesagt wird: „Darüber kümmern wir uns später“, und in dem man sechs Monate später am meisten bereut. Die Sicherheit in ereignisgesteuerten Systemen ist mehrschichtig aufgebaut, und ein Schwachpunkt auf einer beliebigen Ebene macht den Rest zunichte.
Zugriffskontrolle und Verschlüsselung
Die grundlegenden Ebenen, die jeweils eine eigenständige Hürde darstellen:
- Transport: TLS für jeden Anwendungs-Listener. Dies ist nicht verhandelbar.
- Identität: Von einem Identitätsanbieter ausgestellte Dienstidentitäten, sodass der Auftraggeber, der einen Vorgang autorisiert, auf einen echten Kunden zurückgeführt werden kann und nicht auf eine statische Datei mit Anmeldedaten.
- Berechtigung: Explizite, pro Prinzipal erteilte Berechtigungen, wer Beiträge zu einem Thema erstellen oder Inhalte aus einem Thema abrufen darf. Standardmäßig „verweigern“, niemals standardmäßig „zulassen“. Die Wahl zwischen nativen Broker-ACLs und einer externen Policy-Engine ist ein echter Kompromiss (Thema eines separaten Beitrags); beides kann gut umgesetzt werden, jedoch nur, wenn die Berechtigungen deklarativ verwaltet werden und nicht durch manuelle Bedienerbefehle.
- Verschlüsselung im Ruhezustand: Das Protokollverzeichnis des Brokers sollte für alle Personen, die Zugriff auf die Festplatte haben und nicht der Broker sind, unlesbar sein.
Ein übergreifender Aspekt: Identität, Autorisierung und Entschlüsselung sind drei verschiedene Kontrollpunkte. Ein Dienst kann sich zwar authentifizieren und die Zugriffskontrollliste (ACL) des Brokers passieren, ist jedoch möglicherweise dennoch nicht in der Lage, sensible Felder zu lesen, da seinem Schlüsselverwaltungstoken die Berechtigung zur Entschlüsselung fehlt. Jeder Kontrollpunkt hat seinen Grund; werden sie zusammengelegt, entstehen blinde Flecken.
DSGVO / personenbezogene Daten / Compliance
An dieser Stelle hören die meisten Teams zu früh auf. Ein durch ACLs geschütztes Thema enthält immer noch Nutzdaten im Klartext, die jeder autorisierte Nutzer lesen kann. Wenn ein Analyse-Nutzer die Aktion und den Zeitstempel eines Benutzerereignisses rechtmäßig benötigt, warum muss er dann die E-Mail-Adresse des Benutzers einsehen können? Das ist nicht der Fall, und durch die Verschlüsselung auf Feldebene für mit PII gekennzeichnete Felder – mit einem KMS-gestützten „Envelope“, der durch dienstbezogene Entschlüsselungsberechtigungen geschützt ist – setzen Sie das Prinzip der geringsten Berechtigungen direkt auf die Nutzdaten selbst durch.
Kennzeichnen Sie die sensiblen Felder, verschlüsseln Sie diese an der Schnittstelle, und dasselbe Ereignis enthält je nach Leser unterschiedliche lesbare Inhalte. Die kryptografische Grundlage bildet zudem die Grundlage für die anspruchsvolleren Compliance-Maßnahmen: das Recht auf Löschung durch die vernichtung von Schlüsseln auf Personenebene (Crypto-Shredding), für das wir zwar ein Konzept entwickelt, das wir jedoch noch nicht umgesetzt haben.
Die bereichsübergreifende Ebene: Entwicklerportal / Marktplatz
Jeder der fünf Bereiche verfügt über eine eigene Benutzeroberfläche: einen Ereigniskatalog, einen Schema-Browser, ein Governance-Portal, eine operative Kafka-Benutzeroberfläche, Dashboards und Traces. Für ein einzelnes Team ist dies in Ordnung. In einer Organisation mit mehreren Teams muss man jedoch sechs Registerkarten durchgehen, um eine bestimmte Information zu finden.
Die übergeordnete Ebene, die je nach Kontext als internes Entwicklerportal, Servicekatalog oder Event-Marktplatz bezeichnet wird, dient dazu, alle Dienste an einem Ort auffindbar zu machen, wobei deren Verantwortliche, Verträge, Dashboards, Runbooks und Zugriffsanfragen miteinander verknüpft sind. Sie fungiert als zentrale Self-Service-Anlaufstelle für die Bereiche Erfassung, Governance, Qualität und Sicherheit: ein Katalog, ein Abonnementablauf, ein Weg zur Beantragung des Zugriffs.
Wir betrachten diese Ebene als wertvoll auf Organisationsebene, nicht auf Teamebene: Kleine Teams profitieren kaum davon, doch eine Organisation mit hundert Entwicklern zieht aus einem einzigen durchsuchbaren Katalog und einem einzigen Self-Service-Konzept sich gegenseitig verstärkende Vorteile. Die Art der Investition unterscheidet sich vom Rest des Stacks: Es geht weniger darum, neue Inhalte hinzuzufügen, als vielmehr darum, das bereits Vorhandene zu bündeln.
Übergreifende Grundsätze
In allen von uns erschlossenen Bereichen lassen sich bestimmte Muster immer wieder erkennen:
- Die Quelle der Wahrheit in Git: für Schemata, Governance und Topologie. Der Cluster entspricht dem aktuellen Zustand des Repositorys. Alles andere weicht davon ab.
- Verträge an der Schnittstelle: Spezifikationen neben dem Quellcode; Registrierung beim Systemstart; Kompatibilität wird auf Ebene der Registrierungsstelle sichergestellt; nicht kompatible Änderungen werden in der CI erkannt.
- Observability ist keine Funktion, sondern eine Eigenschaft der Art und Weise, wie das System aufgebaut ist. Der Trace-Kontext wird standardmäßig weitergegeben; Metriken leiten sich aus Spans ab; die Herkunft lässt sich aus dem beobachteten Datenverkehr ableiten.
- Überall gilt das Prinzip „Standardmäßig verweigert“: Autorisierung, Verschlüsselung und Feldzugriff sind zunächst gesperrt. Zugriffsberechtigungen werden explizit erteilt und können überprüft werden.
- Selbstbedienung mit Sicherheitsvorkehrungen: Die Mitarbeiter beantragen das, was sie benötigen, über ein Portal; der Antrag durchläuft jedoch einen Genehmigungsprozess und wird schließlich deklarativ erfasst.
- Ehrlichkeit hinsichtlich des Umfangs: Wir geben nicht vor, dass bereits alles umgesetzt ist. Zu wissen, was noch nicht gelöst ist, gehört zu dieser Disziplin.
Warum das wichtig ist
In jedem Bereich ist das Muster dasselbe: Der einfache Weg besteht darin, ein Werkzeug auszuwählen. Der sinnvolle Weg besteht darin, zunächst die Natur des Problems, das Sie lösen möchten, die Kompromisse, die Sie eingehen, und die Leitplanken, die Sie festlegen, zu verstehen. Werkzeuge ändern sich alle zwei Jahre. Kompromisse hingegen nicht.
Was wir geschaffen haben, ist kein Produkt. Es handelt sich um eine Architekturvorlage, die Dutzende von bewusst getroffenen Entscheidungen samt deren Begründung festhält. Diese Begründung ist es, die sich in Ihren Kontext, Ihre Werkzeuge und Ihr Team überträgt, wenn wir miteinander sprechen.
Sollten Sie gerade eine ereignisgesteuerte Plattform aufbauen oder eine betreiben, die über ihre ursprünglichen Annahmen hinausgewachsen ist, würden wir uns freuen, uns mit Ihnen auszutauschen.
Häufig gestellte Fragen
Verfasst von
Piotr Pękala
Contact



