Ghid Arhitectură Microservicii Java Spring Cloud pe VPS
Acest ghid descrie configurarea unei arhitecturi moderne de microservicii Java pe VPS-ul Ubuntu (63.250.40.142). Ghidul utilizează stack-ul standard de la Spring Cloud: Eureka Server (Service Discovery), Spring Cloud Gateway (Routing & Edge Server) și Resilience4j (Circuit Breaker & Fault Tolerance).
# Diagrama Arhitecturală pe VPS
1. Componenta 1: Eureka Server (Registru de Servicii Centralizat)
Eureka Server acționează ca un registru dinamic în care toate microserviciile își înregistrează adresa IP și portul la pornire.
A. Fișierul pom.xml (Eureka Server)
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
B. Clasa Principală Java
package com.bytebook.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
C. Fișierul application.yml
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
wait-time-in-ms-when-sync-empty: 0
2. Componenta 2: Microserviciul de Business (ex: user-service)
Fiecare microserviciu își va asuma un nume unic și se va înregistra automat în Eureka.
A. Fișierul pom.xml (user-service)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
B. Fișierul application.yml (user-service)
server:
port: 8081
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
C. Controller REST Java
package com.bytebook.userservice.controller;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public Map<String, Object> getUserById(@PathVariable String id) {
return Map.of(
"userId", id,
"name", "Alin Popescu",
"email", "alin@bytebook.xyz",
"serverPort", 8081
);
}
}
3. Componenta 3: Spring Cloud Gateway & Resilience4j
Gateway-ul primește cererile din exterior, le rutează inteligent prin Eureka către microservicii și oferă reziliență prin Circuit Breaker.
A. Fișierul pom.xml (Gateway)
<dependencies>
<!-- Gateway Reactive WebFlux -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Eureka Client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Resilience4j Circuit Breaker -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
</dependencies>
B. Fișierul application.yml (Gateway Config)
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: user-service-route
uri: lb://USER-SERVICE
predicates:
- Path=/api/v1/users/**
filters:
- RewritePath=/api/v1/(?<segment>.*), /${segment}
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/fallback/users
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
C. Controller de Fallback (Resilience4j)
package com.bytebook.gateway.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.util.Map;
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@GetMapping("/users")
public Mono<Map<String, String>> userServiceFallback() {
return Mono.just(Map.of(
"status", "503 Service Unavailable",
"message", "Serviciul de Utilizatori este indisponibil temporar. Incercati mai tarziu!",
"circuitBreaker", "OPEN"
));
}
}
4. Integrarea cu Caddy Reverse Proxy pe VPS
Caddy va fi singurul punct de intrare public SSL (https://api.bytebook.xyz), redirecționând tot traficul către Spring Cloud Gateway pe portul 8080.
- Deschide fișierul
Caddyfile:nano /etc/caddy/Caddyfile - Adaugă configurația pentru subdomeniul de API Gateway și Eureka Dashboard:
# Dashboard-ul grafic Eureka (Opțional) eureka.bytebook.xyz { reverse_proxy localhost:8761 } # API Gateway Unificat api.bytebook.xyz { reverse_proxy localhost:8080 } - Reîncarcă Caddy:
systemctl reload caddy
5. Rularea Microserviciilor ca Servicii systemd 24/7
Pentru ca serviciile să pornească automat în ordinea corectă (întâi Eureka Server, apoi Gateway-ul și Microserviciile):
A. Serviciu Systemd Eureka (/etc/systemd/system/eureka-server.service)
[Unit]
Description=Spring Cloud Eureka Server
After=network.target
[Service]
User=root
WorkingDirectory=/root/projects/microservices/eureka-server
ExecStart=/usr/bin/java -jar target/eureka-server-1.0.0.jar
Restart=always
[Install]
WantedBy=multi-user.target
B. Serviciu Systemd API Gateway (/etc/systemd/system/api-gateway.service)
[Unit]
Description=Spring Cloud API Gateway
After=eureka-server.service
Requires=eureka-server.service
[Service]
User=root
WorkingDirectory=/root/projects/microservices/api-gateway
ExecStart=/usr/bin/java -jar target/api-gateway-1.0.0.jar
Restart=always
[Install]
WantedBy=multi-user.target
C. Activează și pornește serviciile
systemctl daemon-reload
systemctl enable --now eureka-server api-gateway
6. Testarea Arhitecturii
- Accesează https://eureka.bytebook.xyz în browser pentru a vedea interfața grafică Eureka și lista de servicii înregistrate (
USER-SERVICE,API-GATEWAY). - Trimite o cerere către API Gateway:
curl https://api.bytebook.xyz/api/v1/users/100 - Testare Circuit Breaker: Oprește
user-service(systemctl stop user-service) și repetă cerereacurl. Vei primi instant răspunsul JSON de Fallback din Resilience4j, fără ca aplicația să returneze eroarea 500!