Architecture

Architektura mikroserwisów: praktyczny przewodnik

cyberwolf.studio
Architecture/14 min read/January 22, 2025
Danylo Kabanov
Danylo Kabanov
Chief Technology Officer

#Architektura mikroserwisów: praktyczny przewodnik

Mikroserwisy to nie srebrna kula — to narzędzie architektoniczne, które ma sens w odpowiednim kontekście. Po latach budowania systemów rozproszonych dla naszych klientów, wypracowaliśmy zestaw zasad, które pomagają uniknąć najczęstszych błędów.

##Kiedy mikroserwisy mają sens

Zanim rozbijemy monolit, warto odpowiedzieć na kilka pytań:

  • Czy zespół jest wystarczająco duży (>8 deweloperów)?
  • Czy różne części systemu mają różne wymagania skalowania?
  • Czy potrzebujemy niezależnych cykli wdrożeniowych?
  • Czy jesteśmy gotowi na złożoność operacyjną?
"

"Jeśli nie potrafisz zbudować dobrze zorganizowanego monolitu, mikroserwisy tylko pomnożą Twoje problemy."

##Podział na domeny

Stosujemy Domain-Driven Design (DDD) jako podstawę do wydzielania granic serwisów. Każdy mikroserwis odpowiada za jedną, dobrze zdefiniowaną domenę biznesową.

typescript
1// Przykład: granice kontekstów w systemie e-commerce
2const boundedContexts = {
3 catalog: {
4 entities: ["Product", "Category", "PriceRule"],
5 commands: ["CreateProduct", "UpdatePrice", "SetDiscount"],
6 events: ["ProductCreated", "PriceChanged"],
7 },
8 orders: {
9 entities: ["Order", "OrderItem", "Shipment"],
10 commands: ["PlaceOrder", "CancelOrder", "UpdateShipment"],
11 events: ["OrderPlaced", "OrderShipped", "OrderDelivered"],
12 },
13 payments: {
14 entities: ["Payment", "Refund", "Invoice"],
15 commands: ["ProcessPayment", "IssueRefund"],
16 events: ["PaymentCompleted", "RefundIssued"],
17 },
18 users: {
19 entities: ["User", "Address", "Preferences"],
20 commands: ["RegisterUser", "UpdateProfile"],
21 events: ["UserRegistered", "ProfileUpdated"],
22 },
23}

##Komunikacja między serwisami

Wybór odpowiedniego wzorca komunikacji jest kluczowy:

WzorzecZastosowanieZaletyWady
REST/HTTPZapytania synchroniczneProstota, szeroka adopcjaCoupling, kaskadowe błędy
gRPCKomunikacja wewnętrznaWydajność, typowanieZłożoność debugowania
Event-driven (Kafka)Asynchroniczne procesyLuźne powiązanie, skalowalnośćEventual consistency
CQRSOddzielenie odczytu/zapisuOptymalizacja per-use-caseZłożoność implementacji

###Event-driven w praktyce

W większości naszych projektów stosujemy podejście event-driven jako fundament komunikacji:

typescript
1// Definicja zdarzeń domenowych
2interface DomainEvent {
3 id: string
4 type: string
5 aggregateId: string
6 timestamp: Date
7 payload: Record<string, unknown>
8 metadata: {
9 correlationId: string
10 causationId: string
11 version: number
12 }
13}
14
15// Publikacja zdarzenia po złożeniu zamówienia
16async function placeOrder(command: PlaceOrderCommand): Promise<void> {
17 const order = Order.create(command)
18 await orderRepository.save(order)
19
20 await eventBus.publish({
21 id: crypto.randomUUID(),
22 type: "order.placed",
23 aggregateId: order.id,
24 timestamp: new Date(),
25 payload: {
26 customerId: command.customerId,
27 items: command.items,
28 totalAmount: order.calculateTotal(),
29 },
30 metadata: {
31 correlationId: command.correlationId,
32 causationId: command.id,
33 version: 1,
34 },
35 })
36}

##Infrastruktura i orkiestracja

Każdy serwis jest konteneryzowany i zarządzany przez Kubernetes:

yaml
1# Przykład konfiguracji deployment w Kubernetes
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: orders-service
6 labels:
7 app: orders
8 team: backend
9spec:
10 replicas: 3
11 strategy:
12 type: RollingUpdate
13 rollingUpdate:
14 maxSurge: 1
15 maxUnavailable: 0
16 selector:
17 matchLabels:
18 app: orders
19 template:
20 spec:
21 containers:
22 - name: orders
23 image: registry.cyberwolf.studio/orders:v2.1.0
24 resources:
25 requests:
26 memory: "256Mi"
27 cpu: "250m"
28 limits:
29 memory: "512Mi"
30 cpu: "500m"
31 livenessProbe:
32 httpGet:
33 path: /health
34 port: 8080
35 initialDelaySeconds: 10
36 periodSeconds: 15
37 readinessProbe:
38 httpGet:
39 path: /ready
40 port: 8080
41 initialDelaySeconds: 5
42 periodSeconds: 10

##Obserwabilność

W systemie rozproszonym obserwabilność to nie luksus — to konieczność. Stosujemy trzy filary:

  • Logi — strukturalne logowanie JSON, centralna agregacja (ELK/Loki)
  • Metryki — Prometheus + Grafana, RED metrics per serwis
  • Trace'y — OpenTelemetry z distributed tracing przez cały pipeline

###Kluczowe dashboardy

  1. Service Health — latencja, error rate, throughput per serwis
  2. Business Metrics — zamówienia/min, konwersja, wartość koszyka
  3. Infrastructure — CPU, pamięć, sieć, pod autoscaling
  4. Dependencies — health check zewnętrznych integracji

##Podsumowanie

Mikroserwisy dają ogromną elastyczność, ale wymagają dojrzałości operacyjnej. Zacznij od dobrze zaprojektowanego monolitu, identyfikuj naturalne granice domen i wydzielaj serwisy tam, gdzie przynoszą realną wartość.

***

Potrzebujesz pomocy z architekturą systemu? Porozmawiajmy o Twoim projekcie.

MikroserwisyDockerKubernetesSystem Design