Gyakori komponensek
Eureka, OpenFeign, Gateway, Spring Cloud Stream
Gyakori komponensek
A Spring Cloud komponensek akkor hasznosak igazán, ha érted, melyik mire való, és nem ugyanazzal a kalapáccsal próbálsz minden integrációs problémát megoldani.
1. Definíció / Definition
Mi ez? / What is it?
A Spring Cloud gyakori komponensei azok az építőelemek, amelyekkel a microservice kommunikáció, routing és event-alapú integráció mindennapi problémáit oldod meg. Ebben a témában a négy legismertebb szereplőt nézzük: Eureka, OpenFeign, Spring Cloud Gateway és Spring Cloud Stream.
Miért létezik? / Why does it exist?
Mert a distributed rendszerben nem elég annyi, hogy „van egy REST controller”. Kell valami, ami megtalálja a service-eket, kell kényelmes HTTP kliens, kell egy bejárati kapu a külső forgalomnak, és kell üzenet-alapú kommunikáció is, ha nem akarsz mindent synchronous hívásokkal összedrótozni.
Hol helyezkedik el? / Where does it fit?
Ezek a komponensek a service-ek közötti és a service-ek körüli infrastruktúra részei. Az Eureka a registry, a Feign a deklaratív kliens, a Gateway az edge layer, a Stream pedig a message broker fölötti absztrakció.
2. Alapfogalmak / Core Concepts
2.1 Eureka Server és Client
Az Eureka Server service registry. A kliensek beregisztrálnak, rendszeresen heartbeatet küldenek, és deregistration vagy lease expiry után eltűnnek a registryből.
| Fogalom | Mit jelent? | Miért fontos? |
|---|---|---|
| Registration | Service instance felkerül a registrybe | Felfedezhetővé válik |
| Heartbeat | Periodikus renewal | Az instance élőnek számít |
| Deregistration | Leálláskor kivonja magát | Tisztább routing |
| Self-preservation mode | Védelem tömeges eviction ellen | Hálózati hiba idején stabilabb |
A self-preservation fontos, mert ha hirtelen sok heartbeat marad el, a registry inkább óvatos. Ez néha zavaró, mert „halott” instance-okat is láthatsz rövid ideig, de cserébe nem törlöd ki a fél clustered egy network glitch miatt.
2.2 OpenFeign
Az OpenFeign deklaratív HTTP kliens. Nem neked kell RestTemplate vagy WebClient hívásokat kézzel összerakni minden service-hez; elég egy interface és annotációk.
Tipikus OpenFeign hívási út:
- Definiálsz egy Java interface-t
@FeignClientannotációval. - A Spring legenerál egy Feign proxy implementációt.
- A proxy elvégzi a kimenő HTTP hívást a downstream service felé.
Kulcselemek:
@FeignClient(name = "inventory-service")- Spring MVC-szerű mapping annotációk az interface metódusokon
- request interceptorok auth headerhez vagy correlation ID-hoz
- fallback vagy fallback factory, ha van circuit breaker integráció
2.3 Spring Cloud Gateway
A Gateway a reactive edge service. Tipikusan ez ül az internet és a belső service-ek között.
Tipikus gateway útvonal:
- A client elküldi a kérést.
- A Gateway route-ot választ és filtereket futtat.
- A kérés a megfelelő downstream service-hez kerül.
Fő building blockok:
- predicates: eldöntik, melyik route illeszkedik;
- filters: módosítják a requestet/response-t;
- rate limiting: túl nagy forgalom szabályozása;
- circuit breaker integration: hibás downstream védelme;
- rewrite, auth, logging: tipikus cross-cutting feladatok.
2.4 Gateway vs Zuul
A Zuul a Netflix stack régebbi proxy megoldása volt, ma a Spring Cloud Gateway a preferált út. A Gateway reaktív modellre épül, modernebb és jobban illeszkedik a mai Spring stackhez. Legacy rendszerekben még találkozhatsz Zuullal, de új fejlesztéshez általában nem ez az ajánlott választás.
2.5 Spring Cloud Stream
A Spring Cloud Stream egy absztrakció message brokerök fölött. Binder alapú modellje van, így a fejlesztő jellemzően nem a nyers Kafka vagy RabbitMQ API-ra épít, hanem bindingokra és funkcionális beanekre.
| Fogalom | Jelentés |
|---|---|
| Binder | Adapter a broker felé |
| Binding | Logikai kapcsolat input/output csatorna és broker destination között |
| Functional model | Supplier, Function, Consumer beanek |
| Producer/consumer pattern | Üzenet publikálás és feldolgozás laza csatolással |
2.6 Feign vs WebClient vs RestTemplate
| Eszköz | Mikor jó? | Fő trade-off |
|---|---|---|
| OpenFeign | Egyszerű service-to-service REST kliens | Kényelmes, de kevésbé finomhangolt |
| WebClient | Reactive vagy nagy kontrollt igénylő kliens | Rugalmasabb, de verbose-abb |
| RestTemplate | Legacy szinkron kliens | Egyszerű, de új fejlesztéshez háttérbe szorult |
Feign akkor erős, ha a downstream API stabil és szeretnél olvasható klienskódot. WebClient jobb, ha streaming, reactive flow vagy komplex hibakezelés kell. RestTemplate sok projektben még él, de újonnan jellemzően nem ez az első választás.
3. Gyakorlati használat / Practical Usage
Egy tipikus webshop platformon a külső mobilapp és web frontend a Gatewayen keresztül jön be. A Gateway végzi a JWT ellenőrzést, request loggingot, route-olást, rate limitinget és adott esetben circuit breaker fallbacket. Így az edge policy egy helyen marad, nem minden service-ben külön-külön.
A belső service-ek Feignt használnak egymás hívására, például a checkout-service meghívja az inventory-service és pricing-service API-ját. Ez a kódot sokkal beszédesebbé teszi, mint a stringekből összerakott HTTP hívások.
Eurekát olyan környezetben látod sokat, ahol a service példányok skálázódnak, újraindulnak, vagy több hoston futnak. Ha a checkout service név alapján tudja a pricing service-et hívni, akkor nem kell minden új deploymentnél endpoint listákat manuálisan karbantartani.
A Spring Cloud Stream pedig akkor szép megoldás, amikor eseményekkel akarod leválasztani a rendszert. Például OrderCreated eseményt publikálsz, amit több consumer dolgoz fel: email, analytics, fraud detection. A functional programming model miatt a producer és consumer kód gyakran egyszerűbb és kevésbé broker-specifikus.
4. Kód példák / Code Examples
4.1 Eureka kliens konfiguráció
@SpringBootApplication
@EnableDiscoveryClient
public class CheckoutApplication {
public static void main(String[] args) {
SpringApplication.run(CheckoutApplication.class, args);
}
}
spring:
application:
name: checkout-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
4.2 OpenFeign kliens interceptorral
@FeignClient(name = "inventory-service", path = "/api/inventory")
public interface InventoryClient {
@GetMapping("/{sku}")
InventoryResponse getInventory(@PathVariable String sku);
}
@Configuration
class FeignConfig {
@Bean
RequestInterceptor correlationIdInterceptor() {
return template -> template.header("X-Correlation-Id", UUID.randomUUID().toString());
}
}
record InventoryResponse(String sku, int available) {}
4.3 Spring Cloud Gateway route-ok
@Configuration
class GatewayRoutes {
@Bean
RouteLocator customRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("inventory-route", r -> r
.path("/api/inventory/**")
.filters(f -> f
.stripPrefix(1)
.requestRateLimiter(c -> {})
.circuitBreaker(c -> c.setName("inventoryCb")))
.uri("lb://inventory-service"))
.build();
}
}
4.4 Spring Cloud Stream functional consumer
@Configuration
class OrderEventsConfig {
@Bean
Consumer<OrderCreatedEvent> notifyAccounting() {
return event -> System.out.println("Accounting notified for order " + event.orderId());
}
@Bean
Function<OrderCreatedEvent, InvoiceRequestedEvent> createInvoiceRequest() {
return event -> new InvoiceRequestedEvent(event.orderId(), event.customerId());
}
}
record OrderCreatedEvent(String orderId, String customerId) {}
record InvoiceRequestedEvent(String orderId, String customerId) {}
spring:
cloud:
function:
definition: notifyAccounting;createInvoiceRequest
stream:
bindings:
notifyAccounting-in-0:
destination: orders.created
createInvoiceRequest-in-0:
destination: orders.created
createInvoiceRequest-out-0:
destination: invoices.requested
5. Trade-offok / Trade-offs
Előnyök
- Eureka lazítja a fizikai endpoint-függőséget;
- Feign olvashatóbbá teszi a service klienskódot;
- Gateway központosítja az edge policy-kat;
- Stream csökkenti a broker-specifikus kódot és támogatja az event-driven mintákat.
Hátrányok
- több absztrakció, emiatt néha nehezebb debugolni;
- Feign túl kényelmes, ezért sokan RPC mental modelt építenek microservice környezetben;
- Gateway könnyen bottleneckké válik, ha minden logika oda kerül;
- Stream elrejti a broker részleteit, ami egyszerre előny és veszély.
Mikor használd? Ha több service-ed van, standardizálni akarod a kommunikációt, és értéket ad a központi routing vagy az event-driven integráció.
Mikor ne? Ha egyetlen appod van, vagy a csapat még a synchronous és asynchronous kommunikáció alap trade-offjait sem tisztázta.
6. Gyakori hibák / Common Mistakes
6.1 Feign fallback félreértése
Fallback nem arra való, hogy minden hibát elrejts. Ha egy fizetés vagy készletlekérés hibás, a vakon adott default válasz üzleti adatvesztést okozhat. Fallback csak átgondolt, domain-kompatibilis esetben jó.
6.2 Gateway-ben üzleti logika
A Gateway legyen routing és cross-cutting policy réteg, ne mini monolit. Ha üzleti döntéseket teszel bele, gyorsan elszáll a karbantarthatóság.
6.3 Stream binder részletek ignorálása
Hiába absztrakció a Stream, attól még számít a Kafka partitioning, consumer group, ordering vagy a Rabbit queue semantics. Az absztrakció nem törli el a broker viselkedését.
6.4 Eureka self-preservation félreolvasása
Sokan incidens közben azt hiszik, hogy a registry „rosszul működik”, mert nem dob ki azonnal minden problémás instance-ot. Valójában a self-preservation sokszor szándékos védelmi mechanizmus.
6.5 Feign vs WebClient rossz választása
Ha reactive pipeline-ba szinkron Feign kliens kerül, vagy fordítva, könnyen teljesítmény- és komplexitásproblémád lesz. A kliensválasztást az execution modelhez igazítsd.
7. Senior szintű meglátások / Senior-level Insights
Senior nézőpontból ezek a komponensek nem egyenként érdekesek, hanem együtt mint kommunikációs stratégia. A rendszerednek kell egy világos szabályrendszer: mi megy Gatewayen át, mi mehet közvetlen service-to-service hívással, mi lesz event, és milyen esetben engedélyezett a fallback.
Feign nagyon jó fejlesztői élményt ad, de könnyen elrejti, hogy valójában hálózati hívást csinálsz. Egy interface nem szabad, hogy úgy nézzen ki, mintha lokális Java metódus lenne minden operációs következmény nélkül. Timeout, retry, idempotencia és observability itt is kötelező gondolkodási pont.
Gatewaynél a legjobb gyakorlat az, hogy az edge concernöket központosítod, de az üzleti ownershipet bent hagyod a domain service-ekben. Auth, routing, rate limiting, request enrichment még ide való; pricing szabály vagy kosárszámítás már nem.
Streamnél pedig mindig döntsd el, hogy absztrakciót vagy broker-specifikus erőt akarsz. Ha a csapatnak szüksége van Kafka-specifikus finomhangolásra és stream processing mintákra, lehet, hogy közvetlenebb API kell. Ha viszont hordozhatóbb, tisztább producer/consumer modell kell, a Stream sokat segít.
8. Szószedet / Glossary
- Eureka Server: service registry, ahol a service-ek beregisztrálnak.
- Eureka Client: alkalmazás, amely regisztrál és discoveryt használ.
- OpenFeign: deklaratív HTTP kliens Spring integrációval.
- Gateway predicate: route match feltétel.
- Gateway filter: request/response feldolgozó elem.
- Binder: Spring Cloud Stream adapter a brokerhez.
- Binding: logikai összekapcsolás alkalmazáscsatorna és broker destination között.
- Fallback: alternatív viselkedés hiba esetén.
9. Gyorsreferencia / Cheatsheet
| Komponens | Fő szerep | Mikor jó? | Fő veszély |
|---|---|---|---|
| Eureka | Discovery | Dinamikus service példányoknál | Registry félreértelmezése |
| OpenFeign | Deklaratív HTTP kliens | Egyszerű REST service hívásokhoz | Rejtett RPC szemlélet |
| Gateway | Edge routing és policy | Auth, rate limiting, route-olás | Túl sok logika a gatewayben |
| Stream | Event-driven absztrakció | Producer/consumer workflow-khoz | Broker részletek ignorálása |
| WebClient | Rugalmas HTTP kliens | Reactive és finomhangolt hívásokhoz | Verbose kód |
| RestTemplate | Legacy kliens | Régi kódbázisban | Új fejlesztéshez ritkán ideális |
🎮 Játékok
8 kérdés