Baza pytań rekrutacyjnych i wiedzy. Filtruj, szukaj i sprawdzaj swoją wiedzę.
Monolit to jedna wdrażalna aplikacja ze wspólnym runtime i zwykle jedną bazą danych — łatwiejsza w budowie i debugowaniu, ale trudniejsza do niezależnego skalowania fragmentów. Mikroserwisy dzielą system na niezależnie wdrażalne usługi, które mogą skalować się i rozwijać osobno, ale dodają złożoność systemów rozproszonych i narzut operacyjny.
Korzyści to niezależne wdrażanie i skalowanie usług, autonomia zespołów i elastyczność technologiczna. Kompromisy to złożoność systemów rozproszonych, opóźnienia sieciowe, trudniejsze debugowanie/observability oraz wyzwania spójności ostatecznej.
Mikroserwisy komunikują się synchronicznie przez REST/gRPC, gdzie wywołujący czeka na odpowiedź, albo asynchronicznie przez messaging/eventy. Synchroniczna komunikacja jest prostsza, ale mocniej wiąże usługi i przenosi awarie; asynchroniczna zwiększa odporność kosztem spójności ostatecznej i większej złożoności.
Service discovery to mechanizm dynamicznego odnajdywania instancji usług (np. przez rejestr Eureka/Consul lub DNS w Kubernetes). Jest potrzebny, bo instancje skalują się i zmieniają adresy, więc klienci muszą znajdować zdrowe endpointy w runtime.
Spójność w mikroserwisach jest zwykle ostateczna. Sagi koordynują serię lokalnych transakcji z akcjami kompensacyjnymi przy błędzie. Wzorzec outbox zapisuje eventy w tej samej transakcji DB co zmiana stanu, a potem niezawodnie publikuje je do brokera.
Mikroserwis to mały, niezależnie wdrażalny serwis, który posiada fragment funkcji biznesowej i swoje dane. Celem jest niezależna zmiana i skalowanie, ale trade-off to złożoność systemu rozproszonego.
To jedno wejście przed serwisami: routing, auth, rate limiting, TLS termination i agregacja requestów. Upraszcza klientów, ale może stać się wąskim gardłem, jeśli jest przeciążone.
W środowiskach dynamicznych (autoscaling) instancje przychodzą i odchodzą. Service discovery pozwala klientom znajdować zdrowe instancje (registry/DNS) bez hardcodowania IP.
Synchroniczne wywołania (HTTP/gRPC) są prostsze i dają natychmiastową odpowiedź, ale zwiększają coupling i mogą powodować kaskadowe awarie. Asynchroniczne messaging poprawia decoupling i odporność, ale dokłada eventual consistency i złożoność operacyjną (kolejki, retry, kolejność).
Na jakiś czas przestaje wywoływać padającą zależność (stan open) i „failuje szybko”, chroniąc serwis i dając zależności czas na powrót. Zmniejsza kaskadowe awarie i poprawia stabilność.
Trace reprezentuje jedno żądanie przechodzące przez serwisy, a span to zmierzona operacja w ramach trace. Correlation/trace ID pozwala spiąć logi, metryki i spany między serwisami, co mocno przyspiesza debugowanie.
Zapisuje event/wiadomość do tabeli „outbox” w tej samej transakcji co zmiana biznesowa, a potem publikuje asynchronicznie. Dzięki temu nie gubisz eventów, gdy commit w DB się uda, ale publikacja zawiedzie.
Bo wiadomości mogą przyjść więcej niż raz (retry, redelivery). Idempotentny konsument bezpiecznie obsługuje duplikaty (np. dedup key lub upsert), żeby nie robić podwójnych efektów ubocznych.
Preferuj zmiany kompatybilne wstecz (dodawaj opcjonalne pola, nie usuwaj/nie zmieniaj nazw), a gdy trzeba — wersjonuj. Kontrakty weryfikuj testami consumer-driven i wdrażaj w kolejności, która utrzyma kompatybilność w trakcie rollout.
Używaj timeoutów + circuit breakerów oraz ograniczaj retry (backoff + jitter). Dodatkowo stosuj bulkheady (limity współbieżności na zależność), żeby jedna awaria nie wyczerpała wszystkich wątków/połączeń.
Bez timeoutów requesty mogą wisieć i zużywać wątki/połączenia, co prowadzi do kaskadowych awarii. Timeout pozwala szybko failować, odzyskać zasoby i bezpiecznie zastosować retry lub fallback.
Backpressure to mechanizm sygnalizacji „zwolnij”, gdy producent generuje szybciej niż konsument przetwarza. Pojawia się w strumieniach, systemach kolejkowych i API — bez niego rosną kolejki, zużycie pamięci i timeouty.
Schema registry przechowuje i wersjonuje schematy eventów (Avro/Protobuf/JSON schema) oraz wymusza reguły kompatybilności. Pomaga producentom i konsumentom bezpiecznie ewoluować bez wzajemnego psucia się.
Bulkhead izoluje zasoby, żeby jedna padająca zależność nie wyczerpała wszystkiego. W praktyce: osobne pule wątków, pule połączeń albo limity współbieżności per zależność, dzięki czemu reszta systemu nadal działa.
Distributed lock jest potrzebny, gdy wiele instancji musi zagwarantować, że tylko jedna wykona sekcję krytyczną (np. jeden job schedulera). Ryzyka: wycieki locków, split-brain, problemy zegara/sieci i dodatkowe opóźnienie; jeśli się da, preferuj idempotencję i constrainty w DB.
To sprzęga serwisy przez wspólny schemat i transakcje: jedna zmiana może zepsuć inne, wdrożenia trzeba koordynować, a własność danych jest niejasna. Trudniej też o skalowanie i granice bezpieczeństwa.
Przez API (request/response) albo eventy (publish/subscribe). Serwis jest właścicielem swoich danych i wystawia je przez stabilny kontrakt; inne serwisy mogą budować read modele lub cache na podstawie eventów, jeśli potrzebują lokalnych odczytów.
Retry storm to sytuacja, gdy wiele klientów robi retry jednocześnie, zwiększając obciążenie padającej zależności i utrudniając jej powrót. Zapobiegasz przez exponential backoff + jitter, limity retry, circuit breakery i rate limiting.
Zakładaj duplikaty i zrób handler idempotentny. Typowe wzorce: zapisz ID wiadomości jako przetworzone z unique constraint, użyj upsertów i trzymaj zmianę + dedup w jednej transakcji (tabela inbox/dedup).
Orkiestracja ma centralnego koordynatora, który mówi serwisom co robić dalej. Choreografia jest zdecentralizowana: serwisy reagują na eventy i uruchamiają kolejny krok. Orkiestracja jest łatwiejsza do ogarnięcia, a choreografia zmniejsza centralne sprzężenie, ale bywa trudniejsza do śledzenia.
W consumer-driven contract testing konsument definiuje oczekiwania wobec API (kształt request/response), a provider weryfikuje, że nadal je spełnia. To wcześnie wykrywa breaking changes i pomaga zespołom wdrażać się niezależnie z większą pewnością.
mTLS szyfruje ruch i uwierzytelnia obie strony (tożsamość serwisu), co pomaga przed podszywaniem i podsłuchem. Samo mTLS NIE rozwiązuje autoryzacji (co serwis może robić) i nie zastępuje walidacji wejścia ani reguł bezpieczeństwa na poziomie biznesowym.
Akcja kompensująca to operacja biznesowa, która “odwraca” poprzedni krok (np. anuluj rezerwację, gdy płatność się nie powiedzie). To trudne, bo to nie jest prawdziwy rollback: może się nie udać, nie zawsze idealnie przywróci stan, i musi być idempotentne oraz dobrze obserwowalne.
Przy wielu instancjach licznik w pamięci limituje tylko jedną instancję, więc sumaryczny ruch może przekroczyć limit. Zwykle potrzebujesz współdzielonego storage (np. Redis) albo limitów na gatewayu. Trudne elementy: poprawność przy współbieżności, okna czasowe, drift zegara i unikanie “hot keys”.
Korzyści: większa dostępność i mniejsza latencja dla globalnych użytkowników. Problemy: replikacja danych, spójność/rozwiązywanie konfliktów, większa złożoność operacyjna oraz latencja/koszt między regionami. Wiele zespołów zaczyna od active-passive (failover) zanim przejdzie do active-active.
BFF to backend dopasowany do jednego frontu (np. web, mobile). Pomaga, gdy różne klienty potrzebują innego „kształtu” danych, gdy chcesz ograniczyć „chatty” wywołania z UI, albo gdy potrzebujesz miejsca do złożenia wielu wywołań serwisów w jedno API dla tego klienta.
REST (JSON po HTTP) jest łatwe do debugowania i bardzo kompatybilne. gRPC używa HTTP/2 + Protobuf: daje silny kontrakt, dobrą wydajność i streaming, ale trudniej je „podejrzeć” bez narzędzi i jest mniej przyjazne przeglądarce. Wybór zależy od kompatybilności, potrzeb wydajności i dojrzałości zespołu/narzędzi.
Zwiększa latencję (czekasz na wiele calli), zwiększa ryzyko awarii (jeden zależny serwis psuje cały request) i potrafi mnożyć obciążenie. Ograniczaj to przez agregację w BFF/API Gateway, cache, podejście async/event-driven oraz time-outy + bulkheady, żeby jeden wolny serwis nie blokował reszty.
Kafka gwarantuje kolejność tylko w obrębie jednej partycji. Żeby zdarzenia dla danej encji były po kolei, publikuj je z tym samym kluczem partycjonowania (np. `orderId`), żeby trafiły do tej samej partycji. Nie ma globalnej kolejności między partycjami, a konsument i tak powinien obsłużyć duplikaty/retry.
`traceparent` to nagłówek W3C Trace Context, który niesie trace ID i informację o rodzicu (span). Gdy każdy serwis przekazuje go dalej w wywołaniach downstream, możesz połączyć logi/span’y w jeden end-to-end trace i łatwiej debugować opóźnienia/awarie między serwisami.