Koreografi ve Orkestrasyon: Mikro Hizmetlerde Dağıtılmış İş Akışlarının Tasarlanması
Monolitik bir mimaride, bir e-ticaret siparişini yerine getirmek gibi karmaşık bir ticari işlemin yürütülmesi basittir. Tüm veriler tek bir ilişkisel veritabanında bulunur ve geliştiricilerin tek bir ACID işleminde envanter, ödemeler ve nakliye genelinde birden fazla veritabanı yazma işlemini tamamlamasına olanak tanır. Herhangi bir noktada bir hata meydana gelirse, SQL ROLLBACK sistem tutarlılığını anında geri yükler.
Bununla birlikte, modern bulutta yerel sistemler, her hizmetin kendi verilerine sahip olduğu ve farklı API sınırlarını ortaya çıkardığı Mikro Hizmet Mimarisini benimser. Bu dağıtılmış paradigmada, tek bir uçtan uca iş operasyonu birden fazla bağımsız mikro hizmeti ve veritabanı motorunu kapsar.
Bulut ağlarında iki aşamalı taahhüt (2PC) protokolleri yavaş, engelleyici ve kırılgan olduğundan, dağıtılmış sistemlerin nihai tutarlılığı korurken iş akışlarını eşzamansız olarak koordine etmesi gerekir.
Bu, yazılım mimarlarını temel bir tasarım kararına getirir: Dağıtılmış mikro hizmet iş akışlarını yönetmek için Koreografiyi mi yoksa Orkestrasyonu mu kullanmalısınız?
Bu kapsamlı kılavuzda, her iki mimari modeli de parçalara ayıracağız, gerçek dünya analojilerini keşfedeceğiz, mimari değiş tokuşları analiz edeceğiz, Go ve Java‘daki üretim kodu uygulamalarını ayrıntılandıracağız ve altyapınız için doğru modeli seçmenize yönelik bir çerçeve oluşturacağız.
Gerçek Dünya Analojisi: Flash Mob ve Senfoni Orkestrası
Her iki model için de sezgisel bir zihinsel model oluşturmak amacıyla, performans sergileyen insan gruplarının eylemlerini nasıl koordine ettiğini düşünün:
Koreografi Analojisi: Bir Flash Mob Dansçıları Ağı
Bir grup profesyonel sokak dansçısının flaş mob rutini sergilediğini hayal edin. Sahnede durup dansçılara bir sonraki hamlelerini emretmeleri için işaret eden bir eğitmen yok. Bunun yerine her dansçı ana müzik parçasını dinler ve yanındaki dansçının hareketlerine dinamik olarak tepki verir.
- Dansçı A takla atmayı tamamladığında, Dansçı B bu görsel işareti tanır ve dönmeye başlar.
- Dansçı B dönmeyi bitirdiğinde, Dansçı C öne çıkar.
- Temel Özellik: Merkezi olmayan, reaktif ve özerk. Her katılımcı, merkezi yönlendirme olmadan kendi sorumluluğunun bilincindedir.
Orkestrasyon Analojisi: Bir Senfoni Orkestrası
Şimdi 70 kişilik bir klasik senfoni orkestrası hayal edin. Kemancılar, perküsyoncular ve çellistler sahne boyunca birbirlerinin ellerini izleyerek ipucu almazlar. Bunun yerine herkes doğrudan İletken’e bakar.
- Şef, kemanlara yumuşak tellerin ne zaman çalınacağını işaret eder.
- Şef, perküsyon vuruşunun sinyalini vermek için davulları işaret eder.
- Bir müzisyen tempoyu kaçırırsa, Şef tempo ayarlamasını koordine eder veya bir duraklama sinyali verir.
- Temel Özellik: Merkezi, açık ve komuta dayalı. Tek bir lider tüm katılımcıları yönlendirir.
1. Koreografi Mimarisi: Merkezi Olmayan ve Olay Odaklı
Koreografi‘de dağıtılmış mikro hizmetler, merkezi bir ana koordinatör olmadan tepkisel olarak iletişim kurar. Hizmetler, dahili durumları değiştiğinde etki alanı olaylarını eşzamansız bir mesaj aracısına (Apache Kafka, RabbitMQ veya AWS EventBridge gibi) yayınlar. Aşağı yöndeki mikro hizmetler, ilgili etkinlik konularına abone olur ve bir sonraki adımda hangi eylemin gerçekleştirileceğine bağımsız olarak karar verir.
Koreografi Altında E-Ticaret Akışı
Koreografiyi kullanarak bir e-ticaret ödeme sürecini düşünün:
- Sipariş Hizmeti: Bir HTTP POST ödeme isteği alır, bekleyen siparişi veritabanına yazar ve Kafka olay veri yoluna bir
OrderCreatedetki alanı olayı gönderir. - Ödeme Hizmeti:
OrderCreatedkonusuna abone olur. Etkinliği aldıktan sonra müşterinin kredi kartından çekim yapar ve birPaymentProcessedolayı düzenler. - Envanter Hizmeti:
PaymentProcessedkonusuna abone olur. Depo öğelerini ayırır ve birInventoryReservedolayı yayınlar. - Gönderim Hizmeti:
InventoryReservedkonusuna abone olur. Bir gönderi etiketi oluşturur ve birOrderShippedolayı yayar. - Bildirim Hizmeti:
OrderShipped‘ye abone olur ve müşteriye bir takip e-postası gönderir.
Koreografinin Avantajları
- Yüksek Özerklik ve Gevşek Bağlantı: Hizmetler, aşağı yönlü işleyicilerin varlığından haberdar değildir. Sipariş Hizmeti yalnızca bir siparişin oluşturulduğunu bilir; bu bilgiyi kimin tükettiği umrunda değil.
- Bağımsız Ölçeklenebilirlik ve Hız: Ekipler mikro hizmetleri bağımsız olarak oluşturabilir, dağıtabilir ve ölçeklendirebilir. Yeni bir özellik eklemek (ör. satışları takip eden bir Analytics Hizmeti), yukarı akış kodunu değiştirmeden mevcut etkinliklere abone olmayı gerektirir.
- Tek Arıza Noktası Yok (SPOF): Merkezi bir iş akışı koordinatörü olmadığından ilgisiz bir hizmetin arızalanması tüm yürütme motorunu çökertmez.
- Yüksek Performans ve Verim: Olay odaklı pub/sub akışı, büyük olay hacmini eşzamanlı HTTP/gRPC engelleme gecikmesi olmadan eşzamansız olarak işler.
Koreografinin Dezavantajları
- Örtülü İş Akışı Mantığı: Uçtan uca iş sürecini tanımlayan tek bir kod konumu yoktur. İş akışının tamamını anlamak, birden fazla kod tabanındaki olay işleyicilerinin bir araya getirilmesini gerektirir.
- Döngüsel Bağımlılık Riski: Mikro hizmetler, dikkatli konu tasarımı olmadan çakışan konuları yayınlar ve bunlara abone olursa, sonsuz olay döngüleri sistem mesaj kuyruklarını çökertebilir.
- Karmaşık Gözlemlenebilirlik ve Dağıtılmış İzleme: 10 etkinlik konusu genelinde tek bir sipariş işleminin izlenmesi, güçlü dağıtılmış izleme altyapısı gerektirir (ör. OpenTelemetry, Jaeger, W3C Trace Context).
- Zor Hata İşleme ve Tazminatlar: Ödeme başarılı olduktan sonra Envanter Hizmeti başarısız olursa, Envanter Hizmetinin bir
InventoryFailedolayı yayınlaması gerekir. Ödeme Hizmetinin bu olayı dinlemesi ve geri ödeme tazminatını manuel olarak tetiklemesi gerekir.
2. Düzenleme Mimarisi: Merkezi ve Komuta Odaklı
Orkestrasyon‘da, özel bir koordinatör hizmeti (Saga Orkestratörü) yürütme sırasını açıkça yönlendirir. Orkestratör, iş akışı durumu makinesini tutar, komut isteklerini (gRPC, HTTP REST veya özel komut kuyrukları aracılığıyla) çalışan mikro hizmetlerine gönderir, yanıtları bekler ve bir sonraki yürütme adımını belirler.
Düzenleme Altında E-Ticaret Akışı
- Sipariş Hizmeti / Saga Orchestrator: Ödeme isteğini alır ve
ORDER_PENDINGdurumunda birOrderSagaCoordinatoriş akışı örneğini başlatır. - Adım 1 (Ödeme Komutu): Orkestratör
PaymentService.ExecutePayment()öğesini çağırır. Ödeme Hizmeti ödemeyi işler veSUCCESSdeğerini döndürür. - 2. Adım (Envanter Komutu): Orkestratör
SUCCESSalır veInventoryService.ReserveStock()‘yi çağırır. Envanter Hizmeti stok ayırır veSUCCESSdeğerini döndürür. - 3. Adım (Gönderim Komutu): Orkestratör
ShippingService.CreateShipment()öğesini çağırır. Nakliye Hizmeti takip ayrıntılarını döndürür. - 4. Adım (Tamamlanma): Orkestratör, durum deposundaki sipariş durumunu
ORDER_COMPLETEDolarak günceller.
InventoryService.ReserveStock() Adım 2 sırasında başarısız olursa, Orkestratör geri alma komutlarını sırayla yürütür:
-
- Adımı geri almak için
PaymentService.RefundPayment()öğesini çağırır.
- Adımı geri almak için
- Saga durumunu
ORDER_CANCELLEDolarak günceller.
Düzenlemenin Avantajları
- Açık ve Merkezi İş Akışı Görünürlüğü: Tüm iş süreci, tek durumlu makine tanımında veya iş akışı DSL’sinde (ör. Geçici iş akışı tanımı) açıkça görülebilir.
- Basitleştirilmiş Arıza Yönetimi: Bir adım başarısız olursa Orkestratör, dolaylı olay zincirlerine dayanmadan önceden tamamlanmış tüm adımlar için doğrudan telafi edici işlemleri başlatır.
- Döngüsel Bağımlılıkları Önler: Çalışan hizmetleri, birbirlerini doğrudan aramak yerine Orkestratör ile ileri geri iletişim kurar.
- Daha Kolay Test ve Denetim: Birim testlerinde hizmet yanıtlarını taklit ederek iş akışı durumu geçişlerini belirleyici bir şekilde test edebilirsiniz.
Düzenlemenin Dezavantajları
- Aşırı Merkezileştirme Riski (“Tanrı Hizmeti”): Geliştiriciler, etki alanı iş mantığını Orkestratöre aktarırsa, çalışan mikro hizmetler, yekpare bir çekirdeği yeniden oluşturarak “aptal CRUD hizmetlerine” dönüşme riskiyle karşı karşıya kalır.
- Daha Sıkı API Bağlantısı: Orkestratör, tüm katılımcı mikro hizmetlerin API sözleşmelerinden ve uç noktalarından açıkça haberdar olmalıdır.
- Potansiyel Ölçeklenebilirlik Darboğazı: Merkezi Orkestratör, her etkin işlem için durum kalıcılığını yönetir. Yüksek verimli sistemler, yatay olarak ölçeklenebilir durum motoru arka uçları gerektirir.
3. Kapsamlı Mimari Karşılaştırma
Koreografi ve Orkestrasyon’u yan yana değerlendirmek için temel operasyonel özelliklerini göz önünde bulundurun:
| Boyut | Koreografi (Etkinlik Odaklı) | Düzenleme (Komut Odaklı) |
|---|---|---|
| İletişim Tarzı | Eşzamansız Pub/Sub (Event yayını) |
Noktadan Noktaya / RPC (Command + Yanıt) |
| Servis Bağlantısı | Çok Düşük (Hizmetler yalnızca etki alanı olaylarını bilir) | Orta (Orkestratör, çalışan API’lerini bilir) |
| Devlet Yönetimi | Hizmet veritabanlarına dağıtılmıştır | Orkestratör durumu motorunun içinde merkezileştirilmiş |
| İş Akışı Görünürlüğü | Örtülü (İşleyiciler arasında yayılmış) | Açık (Merkezi durum makine kodu) |
| Arıza Kurtarma | Karmaşık (Telafi edici olaylar dizisi) | Basit (Orkestratör geri alma işlemlerini yönetir) |
| Dağıtılmış İzleme | Tüm konularda korelasyon kimlikleri gerektirir | Orkestratör günlükleri aracılığıyla basitleştirilmiş izleme |
| İdeal Takım Boyutu | Özerk ekiplere sahip büyük mühendislik kuruluşları | Karmaşık kurumsal akışları yöneten Orta/Büyük ekipler |
| En Uygun Olanlar | Yüksek verimli, basit doğrusal iş akışları | Ağır iş kurallarına sahip karmaşık, çok şubeli iş akışları |
4. Hibrit Yaklaşım: Makro Koreografi + Mikro Düzenleme
Modern kurumsal mimari nadiren ya hep ya hiç seçeneğini zorlar. Bunun yerine, önde gelen mühendislik ekipleri Hibrit Mimari kullanıyor:
- Makro Düzey (Koreografi): Yüksek düzeyde sınırlı bağlamlar (ör. Satışla Sınırlı Bağlam, Tedarik Zinciriyle Sınırlı Bağlam, Müşteri Desteği), Kafka veya NATS aracılığıyla Olay Odaklı Koreografi kullanarak iletişim kurar.
- Mikro Düzey (Düzenleme): Belirli bir sınırlı bağlam içinde (örneğin, çoklu ağ geçidi yeniden denemelerini, dolandırıcılık doğrulamasını ve defter girişlerini yöneten Ödeme sınırlı bağlamı içinde), yerel bir Orkestratör ayrıntılı hizmet yürütmeyi koordine eder.
[EVENT BROKER: KAFKA]
/ | \
(OrderCreated) (PaymentSuccess) (StockReserved)
/ | \
[Order Domain] [Payment Domain] [Inventory Domain]
| | |
(Local Saga (Local Saga (Local Saga
Orchestrator) Orchestrator) Orchestrator)
Bu hibrit model, Koreografinin etki alanı sınırları boyunca gevşek bir şekilde bağlanmasını sağlarken, bireysel hizmet ekipleri içinde Orkestrasyonun durum görünürlüğünü korur.
5. Üretim Kodu Örnekleri
Go ve Java (Spring Boot) kullanarak her iki modeli de üretim ortamlarında nasıl uygulayacağımıza bakalım.
Go Uygulaması: Koreografi Etkinliği Tüketicisi ve Saga Orkestratörü
1. Go’da Koreografi (Kafka Etkinlik Tüketicisi)
Koreografide Envanter Hizmeti, Kafka’dan PaymentProcessedEvent öğesini tepkisel olarak dinler:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/segmentio/kafka-go"
)
type PaymentProcessedEvent struct {
OrderID string `json:"order_id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
}
type InventoryReservedEvent struct {
OrderID string `json:"order_id"`
Status string `json:"status"`
}
func main() {
reader := kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{"localhost:9092"},
Topic: "payment-events",
GroupID: "inventory-service-group",
})
defer reader.Close()
writer := kafka.NewWriter(kafka.WriterConfig{
Brokers: []string{"localhost:9092"},
Topic: "inventory-events",
})
defer writer.Close()
fmt.Println("Inventory Service listening for payment events...")
for {
msg, err := reader.ReadMessage(context.Background())
if err != nil {
log.Fatalf("Error reading message: %v", err)
}
var event PaymentProcessedEvent
if err := json.Unmarshal(msg.Value, &event); err != nil {
log.Printf("Invalid message payload: %v", err)
continue
}
if event.Status == "SUCCESS" {
log.Printf("[Choreography] Reserved stock for Order: %s", event.OrderID)
// Publish downstream domain event reactively
resEvent := InventoryReservedEvent{
OrderID: event.OrderID,
Status: "RESERVED",
}
payload, _ := json.Marshal(resEvent)
err = writer.WriteMessages(context.Background(), kafka.Message{
Key: []byte(event.OrderID),
Value: payload,
})
if err != nil {
log.Printf("Failed to publish inventory event: %v", err)
}
}
}
}
2. Go’da Düzenleme (Merkezi Durum Makine Koordinatörü)
Düzenlemede, açık durumlu bir makine adımları yürütür ve telafileri yönetir:
package main
import (
"context"
"errors"
"fmt"
"log"
)
type OrderSagaOrchestrator struct {
paymentClient *PaymentClient
stockClient *StockClient
}
func NewOrderSagaOrchestrator(p *PaymentClient, s *StockClient) *OrderSagaOrchestrator {
return &OrderSagaOrchestrator{paymentClient: p, stockClient: s}
}
func (o *OrderSagaOrchestrator) ExecuteSaga(ctx context.Context, orderID string, amount float64) error {
log.Printf("[Orchestrator] Starting Saga execution for Order ID: %s", orderID)
// Step 1: Charge Payment
if err := o.paymentClient.Charge(ctx, orderID, amount); err != nil {
log.Printf("[Orchestrator] Payment failed for Order %s: %v", orderID, err)
return err
}
log.Printf("[Orchestrator] Step 1 Complete: Payment Charged")
// Step 2: Reserve Inventory
if err := o.stockClient.Reserve(ctx, orderID); err != nil {
log.Printf("[Orchestrator] Inventory reservation failed: %v. Initiating Compensation...", err)
// Compensation Step: Refund Payment
if refundErr := o.paymentClient.Refund(ctx, orderID, amount); refundErr != nil {
log.Printf("[CRITICAL] Compensation failed! Manual intervention required for Order %s", orderID)
}
return errors.New("saga aborted: inventory unavailable")
}
log.Printf("[Orchestrator] Saga Completed Successfully for Order ID: %s", orderID)
return nil
}
type PaymentClient struct{}
func (p *PaymentClient) Charge(ctx context.Context, id string, amt float64) error { return nil }
func (p *PaymentClient) Refund(ctx context.Context, id string, amt float64) error { return nil }
type StockClient struct{}
func (s *StockClient) Reserve(ctx context.Context, id string) error { return errors.New("out of stock") }
func main() {
saga := NewOrderSagaOrchestrator(&PaymentClient{}, &StockClient{})
_ = saga.ExecuteSaga(context.Background(), "ORD-9982", 149.99)
}
Java (Spring Boot) Uygulaması
1. Java’da Koreografi (Spring Cloud Stream / Kafka Dinleyicisi)
package com.ghaznix.microservices.choreography;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.function.Function;
public record PaymentProcessedEvent(String orderId, String status, double amount) {}
public record InventoryReservedEvent(String orderId, String status) {}
@Configuration
public class InventoryChoreographyProcessor {
@Bean
public Function<PaymentProcessedEvent, InventoryReservedEvent> processPaymentEvent() {
return paymentEvent -> {
System.out.println("[Choreography Java] Processing payment event for order: " + paymentEvent.orderId());
if ("SUCCESS".equals(paymentEvent.status())) {
// Reserve stock in database...
System.out.println("[Choreography Java] Reserved inventory for: " + paymentEvent.orderId());
return new InventoryReservedEvent(paymentEvent.orderId(), "SUCCESS");
} else {
return new InventoryReservedEvent(paymentEvent.orderId(), "FAILED");
}
};
}
}
2. Java’da Düzenleme (Bildirimsel Durum Koordinatörü)
package com.ghaznix.microservices.orchestration;
import org.springframework.stereotype.Service;
@Service
public class OrderSagaOrchestratorService {
private final PaymentServiceClient paymentClient;
private final InventoryServiceClient inventoryClient;
private final ShippingServiceClient shippingClient;
public OrderSagaOrchestratorService(PaymentServiceClient p, InventoryServiceClient i, ShippingServiceClient s) {
this.paymentClient = p;
this.inventoryClient = i;
this.shippingClient = s;
}
public boolean processCheckoutSaga(String orderId, double totalAmount) {
System.out.println("[Orchestrator Java] Initiating Saga Workflow for Order: " + orderId);
// Step 1: Execute Payment
boolean paymentSuccess = paymentClient.processPayment(orderId, totalAmount);
if (!paymentSuccess) {
System.err.println("[Orchestrator Java] Step 1 Failed: Aborting Saga.");
return false;
}
// Step 2: Reserve Inventory
boolean inventorySuccess = inventoryClient.reserveStock(orderId);
if (!inventorySuccess) {
System.err.println("[Orchestrator Java] Step 2 Failed: Triggering Compensation.");
paymentClient.refundPayment(orderId, totalAmount);
return false;
}
// Step 3: Trigger Shipping
boolean shippingSuccess = shippingClient.createShipment(orderId);
if (!shippingSuccess) {
System.err.println("[Orchestrator Java] Step 3 Failed: Compensating Step 2 & Step 1.");
inventoryClient.releaseStock(orderId);
paymentClient.refundPayment(orderId, totalAmount);
return false;
}
System.out.println("[Orchestrator Java] Saga Executed Successfully.");
return true;
}
}
6. Popüler Endüstri Takım İşleme Ortamı
Açık kaynak ve bulut ekosistemi, hangi mimari yönü seçtiğinize bağlı olarak özel altyapı motorları sunar:
Koreografi Ekosistemi
- Mesaj Akışı: Apache Kafka, Apache Pulsar, RabbitMQ, NATS JetStream.
- Bulut Olay Yönlendiricileri: AWS EventBridge, Azure Event Grid, Google Cloud Eventarc.
- Şema Kayıtları: Birleşik Şema Kayıt Defteri (Avro/Protobuf yönetimi için).
Düzenleme Ekosistemi
- İş Akışı Kod Motorları: Temporal.io (Go/Java/TypeScript dayanıklı yürütme motoru), Cadence.
- Bulut Tarafından Yönetilen Koordinatörler: AWS Step Functions, Azure Logic Apps, GCP İş Akışları.
- BPMN ve Enterprise Engines: Camunda 8 (Zeebe), Netflix Şefi.
7. Karar Matrisi: Nasıl Seçilir?
Mikro hizmet platformunuz için Koreografi ve Orkestrasyon arasında karar verirken bu karar kuralı matrisini kullanın:
[Start: System Architecture Assessment]
|
Is the workflow complex with >4 steps
or strict business auditing rules?
/ \
(YES) (NO)
/ \
[Choose: Saga Orchestration] Does the system require
(e.g., Temporal / Camunda) ultra-high event streaming velocity?
/ \
(YES) (NO)
/ \
[Choose: Event Choreography] [Choose: Simple Choreography]
(e.g., Apache Kafka / NATS) (e.g., RabbitMQ Pub/Sub)
Aşağıdaki durumlarda Koreografiyi seçin:
- İş akışınız 2-4 basit, doğrusal adımdan oluşur.
- Yüksek olay akışı verimi ve milisaniyenin altındaki teslimat gecikmesi en önemli önceliklerdir.
- Mühendislik ekibiniz, hizmetleri bağımsız olarak oluşturan ve dağıtan özerk etki alanı ekipleri halinde organize edilmiştir.
- Zaten güçlü dağıtılmış izleme ve APM araçlarına (OpenTelemetry, Datadog) sahipsiniz.
Aşağıdaki durumlarda Düzenleme’yi seçin:
- İş süreçleriniz karmaşık durum geçişleri, çok dallı koşullu mantık veya zamansal gecikmeler içeriyor (ör. “Müşteri onayı için 3 gün bekleyin”).
- Uyumluluk ve denetim gereksinimleriniz, her işlemin tam durumunun merkezi bir günlüğe kaydedilmesini gerektirir.
- Özel olay zincirleme mantığı yazmadan, başarısız adımlar için sağlam, otomatik telafi geri alma işlemlerine ihtiyacınız var.
- Kurumsal finansal işlemleri (örn. bankacılık, sigorta talepleri işleme) yönetiyorsunuz.
Çözüm
Ne Koreografi ne de Orkestrasyon evrensel olarak üstün değildir. Koreografi, örtülü iş akışı görünürlüğü ve karmaşık dağıtılmış izleme pahasına gevşek bağlantıyı, olay verimini ve hizmet özerkliğini en üst düzeye çıkarır. Orkestrasyon, daha sıkı API birleştirme ve orkestratör altyapı yönetimi pahasına açık durum yönetimi, merkezi denetlenebilirlik ve belirleyici hata kurtarma sağlar.
Her iki modelin de güçlü yanlarını anlayarak ve uygun olduğunda Mikro Düzenleme ile Hibrit Makro Koreografiden yararlanarak, bulut ortamları genelinde dağıtılmış işlemleri zarif bir şekilde yöneten esnek, ölçeklenebilir mikro hizmet mimarileri oluşturabilirsiniz.
Tags
Empower Your Digital Presence & Workflows
Explore top-tier tools built by Ghaznix to streamline your links, surveys, and brand growth.