# Warum sollten Sie wahrscheinlich Microservices verwenden?

<!--category-- Architecture, Microservices, Opinion -->
<datetime class="hidden">2025-12-29T20:00</datetime>

Microservices sind das Standard-System geworden

Wenn Sie reif klingen möchten, sprechen Sie über Service-Netze.,. Event-Busse.,. verteiltes Traceting, ,. und unabhängige Einsatzfähigkeit. ".. Wenn Sie unternehmenstauglich aussehen wollen, zeichnen Sie Boxen, bis das Diagramm wie eine Schüssel Spaghetti aussieht, die jemand auf ein Whiteboard geworfen hat.

Aber hier sind die korrektiven meisten Junioren

**Microservices sind keine Upgrades der Anwendungsarchitekturen.Sie sind eine organisatorische Skalierungsstrategie.**

Wenn du nicht bereits die organisatorischen Schmerzen haben, die sie lösen, ,... sie früh zu adoptieren doesn-'... macht dich zukunftsfähig-.

Dies ist ein theoretisches Argument ,. , es macht nur Sinn, wenn Sie die Steuer verstehen, die Sie zahlen , und was Sie erhalten im Gegenzug ..

I'®ve war so schuldig wie jeder andere von Microservices zu tun, ohne den organisatorischen Overhead, den sie mit sich bringen, vollständig zu verinnerlichen..... Es ist einfach, sich in das Vokabular einzumischen und zu vergessen, dass die eigentliche Herausforderung darin besteht, Komplexität über Teams und Systeme hinweg zu verwalten.

Am Ende kommt es auf das älteste Muster in der Software-Engineering. **KISS** Bewahren Sie es einfach auf

[TOC]

## Der Mythos von Microservices

Microservices werden als Standard-Architektur verkauft, weil die Erzählung verführerisch ist.

* Kleine Dienstleistungen sind
* Verteilte Systeme sind ", moderne ",
* Die Autonomie ist frei
* Du kannst später " skalieren, weil du angefangen hast.

Diese Rahmung ist rückwärts.

Mikroservices sind vor allem über Code-Struktur **wer kann was ändern, ohne mit wem zu sprechen und wie oft**.

Wenn Sie nicht haben

* Mehrere Teams versenden unabhängig
* Widersprüchliche Prioritäten
* Koordinierungsengpässe
* Behauptung über den Einsatz
* Grenzen des tatsächlichen Eigentums

Sie sind nicht ein organisatorisches Problem zu lösen , . , Sie kaufen ein .

Architektur ist letztlich über das Ermöglichen von Personen , , , nicht bewegen Boxen um ,. .

## Das Diagramm, das ein Warnschild sein sollte

Sie haben das Diagramm auf LinkedIn gesehen Werbung für einen Microservices-Kurs mit all jenen, die '.v.4'. API-Gateway...,. eine Assemblage von zufälligen Endpunkten usw.

> Hinweis: Ich hatte das tatsächliche Bild davon, aber es war für mich zu verwenden, dass so es entfernte '

Dies ist nicht eine Beispielarchitektur zum Kopieren von ".Es ist ein Warnschild.

Kurse lehren oft Mikroservices als Diagramme, weil Diagramme einfacher sind als die Vermittlung von betrieblicher Verantwortung.

Das wichtige Reframing ist, dass das Diagramm nicht ein Zielzustand ist. **Kostenfläche**.

Jede Box ist eine Verpflichtung.

* Eine Laufzeit zum Betrieb
* Ein Einsatz für die Verwaltung
* Ein Vertrag mit der Version
* Ein Fehler-Modus, den Sie jetzt besitzen
* Eine Geschichte, die du ignorieren kannst

Die Pfeile sehen beeindruckend aus... sie verstecken auch die Realität.

Denn jeder Pfeil ist

* Latenz
* Teilweises Versagen
* Wiederholungen
* Timeouts
* Trace-Kontextvermehrung
* Arbeitet in der Inszenierung

Wenn eine Architektur dies am ersten Tag erfordert, bauen Sie kein Produkt.

## Das versteckte Kostenmodell von Microservices

Wie alle architektonischen Entscheidungen werden auch die Microservices mit einem **Komplexitätssteuer** Siehe auch: [Spielen mit Code-:-Komplexität Steuer](/blog/playing-with-code-efficient-agile)Der Unterschied ist, dass diese Steuerverbindungen über jede Service-Grenze hinweg... jeden Einsatz... und jeden Ausfallmodus...

Die Kosten sind selten explizit, sie sind gewöhnlich als Best Practice verkleidet.

### Betriebsüberkopf

Jeder Dienst wünscht sich

* Eigene Bauleitung
* Die eigene Bereitstellungskonfiguration
* Seine eigene Überwachung und Alarmierung
* Seine eigenen logging-,-Dashboards - Runbooks
* Seine eigene Sicherheits-Haltung (-Geheimnisse,-auth.,-ingress

Wenn ein Team dieses bequem tun kann, dann hat es Microservices. **ein verteilter Monolith mit zusätzlichen Schritten**.

### Multiplikation von Latenz und Ausfall

In einem Monolithen ist ein Anruf ein Funktionsaufruf.

In Microservices ist ein ""Call" ein ausgehandelter Waffenstillstand zwischen

* Netze
* Lastausgleicher
* TLS
* Auth Middleware
* Serialisierung
* Timeouts
* Wiederholungen
* Rückdruck

Ausfall-Modi multiplizieren

* Ein stromabwärts ist langsam -→ flussaufwärts stapeln nach oben
* Retries amplify load →-Sie DDoS selbst höflich
* Eine einzelne Abhängigkeitsklappe Drei Dienste degradieren "zufällig"

Du hast mehr Debug-Fehler gemacht als .. Du debuggst **Systemzustände**.

### Die Serialisierungssteuer, über die niemand spricht

Hier ist ein Preis, der fast nie in Microservices Advocacy diskutiert wird. **Serialisierung und Deserialisierung**.

Jede Dienstgrenze bedeutet:

```csharp
// Monolith: direct object reference
var user = _userService.GetUser(userId);  // < 1μs
var tier = user.Tier;                      // Memory access

// Microservices: serialize → network → deserialize
var json = JsonSerializer.Serialize(user);        // ~50μs for a complex object
var bytes = Encoding.UTF8.GetBytes(json);         // ~10μs
// ... send over network ...
var responseJson = await response.Content.ReadAsStringAsync();  // ~20μs
var user = JsonSerializer.Deserialize<User>(responseJson);      // ~70μs
var tier = user.Tier;                                           // Finally
```

**Pro call-, , dass -' , , ~150 , μs der reinen CPU Overhead bevor das Netzwerk sogar beteiligt wird**

Jetzt multiplizieren, dass über eine Call-Kette

* Bestellen Sie Service deserialisiert Anfrage
* Bestellen Service serialisiert Benutzer-Service-Anfragen
* Benutzer-Service deserialisiert Anfrage
* Benutzer-Service serialisiert Antwort
* Order service deserializes Benutzer-Antwort
* Bestellservice serialisiert Bestandsanforderung
* Und so weiter

**In einer Service-Kette, die Sie auf SerDe ausgibt** - und dass ' optimistische JSON Serialisierung Wenn Sie 're mit XML verwenden, , Protokoll Puffer mit Reflexion , oder ineffizienten Serialisierern, multiplizieren Sie, dass durch 2-10.x..

Ja, das können Sie mit Techniken wie reduzieren [JSON-Quellengenerierung im .-NET](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation):

```csharp
[JsonSerializable(typeof(User))]
internal partial class UserJsonContext : JsonSerializerContext { }

// ~30-40% faster than reflection-based serialization
var json = JsonSerializer.Serialize(user, UserJsonContext.Default.User);
```

Aber du machst immer noch Serialisierung... du hast gerade die Steuer etwas billiger gemacht... in einem Monolithen.

#### Ein echtes Beispiel für die SerDe-Katastrophe

Ich profilierte einmal ein Adress-Suchsystem mit dieser Architektur.

```
ASP.NET API → Go Service (fan-out) → ASP.NET Search Service → Elasticsearch
```

Der Go-Service behandelte Fan---out zu mehreren Datenquellen und aggregierten Ergebnissen.Jede Anfrage bedeutete mehrere Serialisierungshops über Containergrenzen hinweg.

**Die Pannen für eine typische Adresssuche**

* ASP..-NET API.:. Serialisierung der Suchanfrage.MSC2. JSON.MSSK3.μs.
* Netzwerk ,: , ASP-. ,NET , → , Go , ( , Variablen durch Clusterlast , ) ,
* Gehe zu Service, um die Anfrage deserialisieren zu können.
* Gehe zu Service-Diensten : , Fan out ,- , Serialisieren Sie Anfragen an mehrere Backends , (60 , μs .× , N backends, ) ,
* Netzwerk ,: , gehen Sie , → , ASP , . ,NET Suche , ( , varies ,) ,
* Suchdienst - Anfrage deserialisieren (90μs)
* Suchdienst - : Build Elasticsearch-Abfrage -, , Serialisieren , (120 , μs ,) ,
* Netzwerk - Suche nach → - Elastische Suche - ( -Variablen
* Elastische Suche:-Deserialize-Abfrage,-Execute-,-Serialisieren Sie die Ergebnisse (-Resultate Aktuelle Suche ~5-Ms,- SerDe-MSC6-μs-)-
* Netzwerk ,: , Elasticsearch , → , Suche , ( , Varietés , ) ,
* Such-Service: : , Deserialize ES Antwort ,(300 , μs , ), , Karte zu Domänenmodell , , , Serialisierung , .(180 ,μs, MSC5 ,
* Netzwerk ,: , Suchen , → , Gehen , ( , Varietés , ) ,
* Gehen Sie Service, um Antworten von allen Backends Deserialisieren , (150μs ,× , N, ), Aggregat , , , Serialisierung , (80, μs, MSC6 ,
* Netzwerk ,: , gehen Sie , → , ASP , . , , ( , varies ,) ,
* ASP..-NET API.:. Deserialisieren Sie die endgültige Antwort.

**Für einen ,3-' Backend-Fan , -'out-:"**

* Gesamte SerDe Overhead-SerDe :, bevor Elasticsearch sogar gestartet wurde
* Netzüberkopf zwischen Containern
* Tatsächliche Suche Geschäftslogik

**Wir verbrachten fast so viel Zeit auf SerDe, wie wir auf der tatsächlichen Suche waren.**

Die Kosten für den Go-Service selbst machten die Kosten der **Dienstleistungsgrenzen**Jede Container-Grenze bedeutet Serialisierung des Netzwerks von →, Deserialisieren deserialize.

In einem Monolithen, der den gleichen Fan macht

* Gleiche elastische Suchanfragen
* Gleiche Aggregationslogik
* Null inter--Service SerDe Anrufe der Methode (
* Abzüglich der gesamten Latenz

Dies kostete ,:

* Skalen mit Objektkomplexität (-Nestierte Objekte ,-Sammlungen ,-Polymorphismus )-
* Verbindungen mit Ruftiefe
* Brennt CPU auf jeder Anfrage .( .can , ' .t Cache es weg .
* Erhöht den GC-Druck von String-/Byte Arrays
* **Fügt sich schnell, wenn du Hunderte von Anfragen pro Sekunde machst**

In einem Monolithen ist diese Kosten null... Das Objekt befindet sich bereits im Speicher.

### Der Performance-Mythos des :-Durchsatzes gegen die Skalierbarkeit von .

Hier ist ein gewöhnlicher Verkaufsabstand von :.Microservices verbessern die Leistung

**Dies ist rückwärts.**

Mikrodienstleistungen sind **langsamer** für die gleichen Compute-Ressourcen - .- Let-'-s seien Sie präzise über das, was wir meinen

**Durchsatz** Anfragen pro Sekunde pro CPU-Core

- **Monolith**0 0 0-SerDe-, - Null Netzwerk Hops - Direkte Methode Anrufe
- **Mikrodienste**Untere Länge des Container-Orchestrierungssystems

**Skalierbarkeit** Fähigkeit, mehr Gesamtanfragen durch Hinzufügen von Ressourcen zu bearbeiten

- **Monolith**Begrenzt durch vertikale Skalierung
- **Mikrodienste**Mehr Instanzen von Engpass-Diensten hinzufügen

Microservices lassen Sie **unabhängig skalieren**Wenn dein Inventardienst Ressourcen benötigt, aber dein Benutzerdienst nicht benötigt, kannst du sie separat skalieren. **wenn Sie es brauchen**.

Aber es ist nicht eine Performance-Optimierung. **Skalierungsstrategie**Und es kommt mit einer Steuer...

#### Moderne Monolithen können auch skalieren

Das Argument "microservices skalieren besser "MSC1" machte mehr Sinn in "MSSK2" wenn Server hatten.

Moderne Server haben Kerne der . Eine einzelne Maschine kann Tausende von gleichzeitigen Operationen effizient ausführen.

Wenn Ihr Monolith mit modernen gleichzeitigen Ausführungsmustern gebaut wird, kann es massiven Durchsatz auf einem einzigen Einsatz bewältigen. [ephemere Ausführungskoordinatoren](/blog/ephemeral-execution-library)Sie können :

```csharp
// Process thousands of concurrent operations in a monolith
services.AddEphemeralWorkCoordinator<TranslationRequest>(
    async (request, ct) => await TranslateAsync(request, ct),
    new EphemeralOptions { MaxConcurrency = Environment.ProcessorCount * 4 });

// Bounded, observable, efficient concurrent processing
// No network overhead, no SerDe, no container orchestration
// Can handle 10k+ req/sec on a single machine
```

Dies gibt Ihnen ,: ,

- **Parallelität**Die Arbeit läuft gleichzeitig über alle Kerne
- **Beobachtungsfähigkeit**:-Track ausstehender /-aktiver /-Failed-Betrieb
- **Rückdruck**Begrenzte Warteschlangen verhindern Erschöpfung des Gedächtnisses
- **Null Overhead**Keine Serialisierung, kein Netzwerk, keine verteilte Nachverfolgung

Wenn Sie **tun** Notwendigkeit, über eine Maschine hinaus zu skalieren

1. Führen Sie mehrere Instanzen hinter einem Load Balancer aus.
2. Verwenden Sie ein Outbox-Muster für die async Arbeitsverteilung
3. Teilung nach Schlüsseln der Kunden-ID: , Region:, usw.

Du führst immer noch einen Monolithen aus ,. , You , ' , den du gerade mehrmals eingesetzt hast .. ,

**Der Punkt**Nicht in Mikroservices aufgeteilt, wenn **unabhängige Skalierung bestimmter Komponenten** rechtfertigt den Betriebsaufwand

### Kognitive Belastung

Mikroservices reduzieren die Komplexität nicht... sie verteilen es neu.

Der Simple-Service von " benötigt immer noch einen Kontext.

* Wer nennt es?
* Was bedeutet ?
* Was passiert, wenn es sich nach unten bewegt?
* Was ist der Rollback-Plan?
* Was ist das Abhängigkeitsdiagramm?

Die Leute unterschätzen dies, weil Diagramme es verstecken

### Versionierung und Vertragsdrift

Jede Grenze wird zu einem Kontrakt.  
Jeder Vertrag wird zu .:

* Regeln für die Versionierung
* Kompatibilitätsgarantien
* Sachzwänge in der Schemaentwicklung
* Coordination Overhead, den du vorgabst, du hättest es getan

Du kannst dies für eine Weile ausweichen, mit dem Befehl " einfach alles zusammen bereitstellen.

Dass-' die Pointeline, wenn du alles zusammen entwickelst, hast du einen Monolithen gebaut.

### Werkzeug vor Wert

Die frühen Ausgaben sind immer die gleichen

* Entdeckung des Dienstes
* Sekretariatsgeschäfte
* Verteilte Rückverfolgung
* Zentralisierte Protokollierung
* Metrik und Alarmierung
* CIP-/-CD-Vorlagen
* Lokale Dev-Geschichte, die schmerzhaft ist
* Abhängigkeitsmanagement
* Ein Weg, alles ohne zu weinen laufen

Keines dieser Schiffe Warenwert

Und die meisten Teams tun es, bevor sie sich bewährt haben, dass das Produkt die Komplexität verdient

Dies ist der zentrale Fehler. **Sie zahlen die Zeremonie Steuer, bevor Sie verdienten den Wert**Wie: [tägliche Standups, die Zeit verschwenden ohne Ausrichtung](/blog/agile-standups-ceremony-tax)Microservices können zu ritueller Architektur werden.: Beeindruckend, um sich anzusehen, , Beeinträchtigt teuer zu pflegen und vom eigentlichen Problem zu trennen, das Sie lösen.

Zusammengenommen genommen, diese Kosten don-''t verschwinden, sie verbinden, .' Und sie vermischen, ob die Organisation brauchte Microservices in erster Linie

## Was Menschen vergessen, Menschen und Teams

Architektur existiert, um Gruppen von Menschen zu helfen, Software sicher zu ändern.

Nicht um andere Ingenieure zu beeindrucken  
Nicht, um ein Diagramm zu befriedigen  
Nicht ein Plattform-Team zu rechtfertigen, das du nicht hast.

Teamgröße und Einsatzkadenz sind wichtiger als der Musterkatalog

* Wenn ein Team die gesamte Roadmap besitzt, ist ein Monolith in der Regel schneller und sicherer.
* Wenn Sie immer noch verstehen, das System end--.to.-.end-,. microservices wird diese Klarheit reduzieren
* Wenn du nicht über stabile Eigentumsgrenzen verfügst, werden Microservices die Koordination durch APIs erzwingen. Das ist der langsamste Koordinierungsmechanismus, den es gibt.

**Conway, ', ist das Gesetz des ', optional, ., es ist die Physik von ',**

Ihre Architektur spiegelt Ihre Kommunikationsstruktur, ob Sie es mögen oder nicht.

Mikroservices don-'-t erzeugen Autonomie... Sie benötigen es.

## In der Verteidigung des modularen Monolithen

Die meisten Systeme sollten als Monolith beginnen.

A **Modularer Monolith** Ist-:-

* Eine Einsatzeinheit
* Eine Laufzeit
* Ein Ort zum Debuggen
* Eine konsistente Sicht des Zustands
* Aber mit echten inneren Grenzen

Es bedeutet:

* Domänenmodule mit expliziten Abhängigkeiten
* Freier Besitz im Code
* Keine Hinweise auf alles
* In der Codebasis durchgesetzte Verträge

Der Punkt ist, monolithisch für immer zu bleiben. **Grenzen verdienen, bevor Sie sie entfernt machen**.

Ein modularer Monolith zwingt Sie, die Fähigkeiten zu lernen Microservices vorgeben, um zu lösen

* Domänenmodellierung _ _reale Grenzen_,_ nicht Ordnergrenzen_MSC2_
* Trennung der Bedenken -(-not -"-we machte einen Service-MSC2-
* Prüfbarkeit
* Disziplin ändern
* Wissen, was Ihr System tatsächlich tut

**Wenn du einen sauberen modularen Monolithen bauen kannst, dann werden die Microservices von ' nicht sparen.**

### Gute Monolith-Design-Muster, die später skalieren

Das richtige Monolith-Design lässt Sie **Verzögern der Entscheidung über Mikrodienstleistungen** ohne sich einzusperren

#### Das Outbox-Muster – :-Async ohne Verteilung

Eines der besten Beispiele ist die **outbox-Muster** Ein Weg, um eventuelle Konsistenz und Async-Verarbeitung zu erreichen *innen* ein Monolithen-,Ã mit einem sauberen Pfad zur Verteilung spÃ¤ter.

Anstelle von„:"

```csharp
// Tightly coupled synchronous code
public async Task PlaceOrder(Order order)
{
    await _orderRepo.Save(order);
    await _emailService.SendConfirmation(order);  // Blocks on external service
    await _inventoryService.Reserve(order.Items); // Blocks on another service
}
```

Du schreibst

```csharp
// Outbox pattern: write events to a table
public async Task PlaceOrder(Order order)
{
    await using var transaction = await _db.Database.BeginTransactionAsync();
    
    // Save order
    await _orderRepo.Save(order);
    
    // Write events to outbox table (same transaction)
    _db.OutboxMessages.Add(new OutboxMessage
    {
        EventType = "OrderPlaced",
        Payload = JsonSerializer.Serialize(order),
        CreatedAt = DateTime.UtcNow
    });
    
    await _db.SaveChangesAsync();
    await transaction.CommitAsync();
    
    // Background worker picks up outbox events and publishes them
}
```

**Was dies Ihnen gibt**

* **Kohärenz der Transaktionen**Veranstaltungen und Daten, die gemeinsam übertragen werden oder gar nicht
* **Entkopplung**E-Mail-Adresse: /.Inventorylogik läuft async.,. doesns.'.t Blockauftragserstellung
* **Zuverlässigkeit**Die Ereignisse dauern an, auch wenn die nachgeschalteten Systeme heruntergefahren sind.
* **Sauberer Extraktionspfad**Später: , tauscht den Outbox-Arbeiter gegen Kafka, /, RabbitMQ aus, ohne die Ordnungslogik zu ändern

Das [SegmentCommerce Beispielprojekt](/blog/zero-pii-customer-intelligence-part2) zeigt dieses Muster in der Produktion

```csharp
// Mostlylucid.SegmentCommerce/Services/Queue/PostgresOutbox.cs
public class PostgresOutbox
{
    public async Task PublishAsync<T>(string eventType, T payload)
    {
        var message = new OutboxMessage
        {
            EventType = eventType,
            Payload = JsonSerializer.Serialize(payload),
            CreatedAt = DateTime.UtcNow
        };
        
        _db.OutboxMessages.Add(message);
        // Caller commits transaction
    }
}

// Background service
public class OutboxProcessor : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var pending = await _db.OutboxMessages
                .Where(m => !m.Processed)
                .OrderBy(m => m.CreatedAt)
                .Take(100)
                .ToListAsync();
                
            foreach (var message in pending)
            {
                await ProcessMessage(message);
                message.Processed = true;
            }
            
            await _db.SaveChangesAsync();
            await Task.Delay(1000, stoppingToken);
        }
    }
}
```

Dies läuft heute in einer einzigen App, wenn Sie skalieren müssen.

1. Ersetzen Sie den Hintergrundarbeiter durch eine Nachricht Bus-Verbraucher
2. Veröffentlichen Sie Outbox-Ereignisse in Kafka-/-RabbitMQ statt lokal zu verarbeiten
3. **Auftragsplatzierungscode ändert sich nicht**

Sie bauten Microservices, ohne die Vertriebssteuer zu bezahlen.

#### Andere Muster lohnen sich, früh zu tun

* **CQRS-Licht**Getrennte Lese- und Schreibmodelle, auch wenn sie eine DB teilen
* **Event-Sourcing-Veranstaltung**Ausschließlich für die Prüfung kritischer Unternehmen
* **Feature-Flags**Entkoppelung aus der Freigabe
* **Hintergrundarbeiten**Prozess-Async

Keiner von ihnen erfordert Verteilung.... alle machen die Distribution später einfacher....

## Wenn Microservices wirklich Sinn machen

Microservices machen Sinn, wenn die Einschränkungen real sind .

Die kritische Frage ist, dass wir Microservices verwenden sollten. **tun die Vorteile überwiegen die Betriebssteuer**

Wie die Wahl zwischen [kleine lokale Modelle und grenzübergreifende LLMs](/blog/small-models-not-budget-option)Hier geht es um das Verständnis, wo Komplexität hingehört und welche Ausfallmodi du dir leisten kannst.

### Gute Auslöser

* **Teamzwang ist messbar**Teams blockieren sich wöchentlich
* **Unabhängige Einsätze sind notwendig**Die Release-Kadenz unterscheidet sich pro Domain
* **Die Skala ist ungleichmäßig**Ein Teilsystem benötigt Ressourcen und Isolation
* **Ausfall von Isolationsfragen**Eine Komponente darf den Rest nicht herunternehmen
* **Regulatorische Isolierung der Daten ist obligatorisch**Die Grenzen sind nicht verhandelbar
* **Org-Struktur ist bereits multi--Team**Die Eigentümerschaft existiert und ist stabil

### Schlechte Trigger

* Wir könnten skalieren.
* Netflix tut es.
* Bewährte Verfahren
* ," , es sieht gut aus
* Unser Monolith ist unordentlich.

**Wenn Ihr Grund die Worte enthält *könnte*, *Schließlich*mit einem Quadratmetergewicht von mehr als 1 kg *zukunftssicher*Es ist wahrscheinlich kein Grund.**

## Die technische Realität – das, was Mikroservices eigentlich kosten

Lassen Sie 's erhalten Beton-.. Hier , was ändert sich, wenn Sie einen Monolithen in Dienstleistungen teilen , , . .

### Anrufketten und Latenz

**Monolithen-:**

```csharp
public async Task<Order> PlaceOrder(OrderRequest request)
{
    var user = await _userService.GetUser(request.UserId);
    var inventory = await _inventoryService.CheckStock(request.Items);
    var price = _pricingService.Calculate(request.Items, user.Tier);
    
    var order = new Order { /* ... */ };
    await _orderRepository.Save(order);
    await _emailService.SendConfirmation(order);
    
    return order;
}
```

Gesamte Latenz-Latenz-:---~50--ms--M(-in--Prozess-Aufrufe-MS K4-- 2-DB-Abfragen-MSC6-

**Mikrodienstleistungen**

```csharp
public async Task<Order> PlaceOrder(OrderRequest request)
{
    // HTTP call to User Service (network + TLS + serialization)
    var user = await _httpClient.GetAsync<User>($"http://user-service/users/{request.UserId}");
    
    // HTTP call to Inventory Service
    var inventory = await _httpClient.PostAsync<StockResult>(
        "http://inventory-service/check", request.Items);
    
    // HTTP call to Pricing Service
    var price = await _httpClient.PostAsync<PriceResult>(
        "http://pricing-service/calculate", 
        new { items = request.Items, tier = user.Tier });
    
    // HTTP call to Order Service
    var order = await _httpClient.PostAsync<Order>(
        "http://order-service/orders", request);
    
    // Event published to message bus
    await _messageBus.Publish(new OrderPlaced { OrderId = order.Id });
    
    return order;
}
```

Gesamte Latenzzeit: :- > ~400- >(- > sogar optimistische HTTP-Anrufe in realen Umgebungen: +- > Nachrichtenbus veröffentlichen ~20- > Ms K6- >

**Was du gewonnen hast**

* Jeder Dienst kann unabhängig sein
* Inventar und Preise können getrennt von Aufträgen skaliert werden
* Fehler in E-Mail doesn's'.t Blockauftragserstellung

**Was du bezahlt hast**

* Erhöhung der Latenzwerte
* Neue Ausfallpunkte ( ist ein Dienst, der down sein kann/ slow
* Netzwerk: DNS, ,, TLS Overhead auf jedem Anruf
* **Serialisierung®/-Deserialisierung** Siehe früherer Abschnitt
* Notwendigkeit für retry-Logik-Leistungsschalter
* Verteilte Nachverfolgung auf Debug-Ausfälle

### Fehler beim Umgang mit Explosionen

**Monolithische Fehlerbehandlung**

```csharp
try
{
    var order = await PlaceOrder(request);
    return Ok(order);
}
catch (InsufficientStockException)
{
    return BadRequest(new { error = "Out of stock" });
}
catch (Exception ex)
{
    _logger.LogError(ex, "Order placement failed");
    return StatusCode(500);
}
```

**Fehlerbehandlung bei Microservices-Diensten**

```csharp
try
{
    // Call User Service
    var user = await _httpClient.GetAsync<User>($"http://user-service/users/{request.UserId}");
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
    return NotFound(new { error = "User not found" });
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.ServiceUnavailable)
{
    // Retry with exponential backoff?
    // Circuit breaker opened?
    // Fail fast or degrade gracefully?
    _logger.LogWarning("User service unavailable, retrying...");
    await Task.Delay(TimeSpan.FromMilliseconds(100));
    // ... retry logic ...
}
catch (TaskCanceledException ex)
{
    // Timeout - was the request processed? Do we retry?
    _logger.LogError("User service timeout");
    return StatusCode(503, new { error = "Service temporarily unavailable" });
}

try
{
    var inventory = await _httpClient.PostAsync<StockResult>(
        "http://inventory-service/check", request.Items);
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.BadRequest)
{
    // Business error from remote service
    var errorDetails = await ex.Content.ReadAsAsync<ErrorResponse>();
    return BadRequest(new { error = errorDetails.Message });
}
catch (HttpRequestException ex)
{
    // Which service failed? Network issue? Service down?
    // Do we have a fallback? Cached data? Fail fast?
    _logger.LogError(ex, "Inventory service failed");
    // Maybe try a backup instance?
    // ... more retry logic ...
}

// And repeat for every service call...
```

Jeder Netzwerk-Anruf stellt vor

* Timeout-Szenarien
* Netzwerkausfälle
* Nichtverfügbarkeit des Dienstes
* Teilausfälle (-Anfrage gesendet,-Antwort nicht erhalten)-Antrag
* Verstärkung der Wiederholungsverstärktheit (-your retry könnte ihre Wiederholung auslösen
* Verteilte Transaktion Alpträume

### Koordinierung des Einsatzes

**Einsatz von Monolithen – :**

```bash
# Build
dotnet publish -c Release

# Run migrations
dotnet ef database update

# Deploy
docker push myapp:v1.2.3
kubectl set image deployment/myapp myapp=myapp:v1.2.3

# Rollback if needed
kubectl rollout undo deployment/myapp
```

**Bereitstellung von Microservices**

Sie ändern die Ordnungsstruktur. `Order` schließt ein `UserTier` direkt für die Leistung denormalisiert

```bash
# 1. Deploy Pricing Service v2 (understands both old and new Order format)
kubectl set image deployment/pricing-service pricing-service=pricing:v2.0.0

# 2. Wait for rollout and monitor
kubectl rollout status deployment/pricing-service
# Check metrics - is v2 working with old order format?

# 3. Deploy Order Service v2 (starts sending new format)
kubectl set image deployment/order-service order-service=order:v2.0.0

# 4. Monitor for errors
# If Pricing v2 has a bug, you can't just rollback Order service
# You have to rollback both in reverse order

# 5. Deploy User Service v2 (stops including tier in response)
# But wait - old Order Service instances might still be running!
# Need zero-downtime rollout or maintain backward compat

# 6. Eventually clean up old code paths in Pricing Service v3
# (6 months later because you're scared to remove backward compat)
```

Mit Microservices ,, , jede Änderung kreuzt mehrere Dienste , . , Contract evolution requires -: ,

* Rückwärtskompatibilitätsfenster
* Feature-Flags über Dienstleistungen hinweg
* Koordinierte Rollouts
* Extended testing matrices Service A v.1. Dienst B v. 2,. Dienst A v."2. Dienst Β v. 1,. usw.

Nichts davon ist unmöglich, aber es erfordert Disziplin, Werkzeug und Erfahrung, die die meisten Teams nur nach Jahren des Schmerzes verdienen.

### Die Debugging-Erfahrung

**Monolithischer Fehlerbericht (MSK)** Bestellplatzierung fehlschlägt für Premium-Benutzer

```csharp
// Set breakpoint in PlaceOrder
// Step through each call
// User tier is null - ah, there's the bug
// Fix, test, deploy
```

**Fehlerbericht von Microservices** Bestellplatzierung fehlschlägt für Premium-Benutzer

```bash
# 1. Check logs - which service failed?
kubectl logs -l app=order-service --tail=100

# 2. Oh, it's calling Pricing service. Check those logs
kubectl logs -l app=pricing-service --tail=100

# 3. Grep for correlation ID across all services
stern -l app=order-service,app=pricing-service,app=user-service \
  | grep "correlation-id-xyz"

# 4. Reconstruct the call chain from distributed traces
# Open Jaeger/Zipkin, find the trace
# User service returned 200 OK
# Pricing service returned 400 Bad Request
# Error: "user.tier is required"

# 5. Check User service - did it send tier?
# Look at schema version - ah, User v1.2 stopped sending tier
# When did that deploy? Was Pricing service updated?

# 6. Check API contracts
# Pricing expects tier, User stopped sending it
# Who approved this change?

# 7. Fix requires coordinating two teams
# Can't just deploy a fix - need contract negotiation
```

Dies ist die Realität. **Bugs, die waren 5--Minute-Fixes werden multi --Teamuntersuchungen**.

Wenn das extrem klingt, sind die Microservices extreme engineering

## Wie man sich sicher entwickelt, :-Monolith-Mikroservices

Microservices sind eine Ein---Wege-Tür, behandelt sie wie ein -.

Der sichere Weg sieht langweilig aus.

### Beweisen Sie zuerst Grenzen

Wenn du die Grenze im Monolithen mit durchsetzbaren Abhängigkeiten ziehen kannst, kannst du sie sicher extrahieren.

Holen Sie sich die Nähte direkt vor Ort zuerst

### Extrakt liest vor dem Schreiben

Lesen ist einfacher.

* Weniger Invarianten
* Weniger Konsistenzanforderungen
* Weniger rollback Alpträume

Verschieben Sie die Lesemodelle zuerst heraus, wenn Sie Trennung benötigen

### Vor dem Synchronisieren Async bevorzugen

Synchrone Service-Aufrufe erzeugen Abhängigkeitsketten

Async Messaging erstellt

* Leiden
* Resilienz
* Entkoppelung kann wirklich überleben

Beginnen Sie mit der Trennung von Ereignissen und Fakten.

### WÄHREND , ENTWICKLUNG

Keine großen bang-.  
Keine "-We-'-ll umschreiben es richtig

Von der Grenze abschneiden - ,- messen Sie es -,- besitzen Sie es ,,- und halten Sie weiter , .-

**Wenn Sie erklären können, warum ein Dienst unabhängig existiert, sollte er überhaupt existieren.**

## Die Takeaway-Mikroservices zahlen nur, wenn Sie den Trade verstehen.

Microservices sind kein Ausgangspunkt, sondern ein Ergebnis.

**Komplexität sollte verdient werden** Verteilte Systeme sind kein Abzeichen, sondern ein Schuldinstrument.

Die Trade-Gleichung ist einfach.

```
Microservices Value = (Team Autonomy + Independent Scaling + Failure Isolation)
                     - (Latency Tax + SerDe Tax + Operational Overhead + Coordination Cost)
```

Für die meisten Teams Vor allem früh vor der - stadium oder einzelne single-- team-Produkte Vor der rechten Seite dominiert - Sie zahlen enorme Kosten für Vorteile, die Sie noch nicht benötigen

Aber wenn Sie haben

* Teams, die auf einander treten
* Einsatz Warteschlangen, die in Tagen gemessen werden
* Subsysteme mit stark unterschiedlichen Skalierungsanforderungen
* Regulierungsanforderungen für die Datenisolierung

Die Steuer wird gerechtfertigt, die linke Seite beginnt zu gewinnen

### Ein Entscheidungsrahmen

Stellen Sie diese Fragen in der Reihenfolge

1. **Kann ein Team noch dieses Ende besitzen?**  
   →-Ja-:-Bleiben Monolith-.-Nein-:-In Erwägung ziehen, teilen

2. **Sind Teams von einander blockiert ,' s Release-Zyklen , ? .**  
   → - Ja, : - Mikroservices könnten helfen, . - Nein, : - Koordination funktioniert - . -

3. **Haben wir den operativen Muskel, um verteilte Systeme laufen zu lassen?**  
   →-Nein:-Bauen Sie es zuerst .-Ja-:-Vorgehen sorgfältig

4. **Können wir verfolgen ,, , debug , , , und setzen Sie mehrere Dienste ohne Heldentaten ,**  
   → - Nein MS K1 - du bist nicht bereit . - Ja MS-K4 - du könntest es sein

5. **Haben wir die Grenzen im Code zuerst bewiesen?**  
   Befestigen Sie Ihre monolithische Struktur.... Ja, die Extraktion von : ist sicherer.

Wenn Sie nicht hinter Frage erhalten können 3... mit Vertrauen ,... Sie sind nicht bereit für Microservices. **Boring Architektur ist ein Wettbewerbsvorteil**

Die meisten erfolgreichen Produkte wurden als Monolithen zuerst gebaut .: .GitHub ?, .Shopify . , .Stack Overflow ., .Basecamp . . . Sie entwickelten sich in verteilte Systeme nur, wenn die organisatorischen Schmerzen verlangt es .

Ihre Aufgabe ist es, die beeindruckendste Architektur zu bauen, um Wert zu liefern und gleichzeitig zufällige Komplexität zu minimieren.

Und kein Kunde hat jemals extra bezahlt, weil Ihr System verwendet Kafka-.

Manchmal bedeutet das Mikroservices, ., normalerweise bedeutet es einen gut strukturierten Monolith und die Disziplin, um ihn so zu halten.