Cloud Native Architecture trong Java
1. Lý thuyết và Khái niệm Cơ bản
1.1 Cloud Native Principles
- Microservices Architecture
- Containerization
- DevOps Automation
- Continuous Delivery
- Scalability và Elasticity
- Resilience và Self-healing
- Observability
- Service Discovery
- Configuration Management
- API-First Design
1.2 Cloud Native Stack
- Spring Cloud
- Kubernetes
- Docker
- Service Mesh (Istio)
- Message Brokers (Kafka, RabbitMQ)
- Distributed Tracing (Jaeger)
- Monitoring (Prometheus)
- Logging (ELK Stack)
2. Best Practices và Design Patterns
2.1 Microservices Configuration
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class MicroserviceApplication {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(10)
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(10))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(3))
.build())
.build());
}
}
2.2 Service Discovery
@Configuration
public class ServiceDiscoveryConfig {
@Bean
public ServiceDiscoveryClient discoveryClient(
WebClient.Builder webClientBuilder) {
return new ServiceDiscoveryClient(webClientBuilder);
}
}
@Service
public class ServiceDiscoveryClient {
private final WebClient.Builder webClientBuilder;
public Mono<ServiceResponse> callService(String serviceId, String path) {
return webClientBuilder.build()
.get()
.uri("http://" + serviceId + path)
.retrieve()
.bodyToMono(ServiceResponse.class)
.transform(CircuitBreakerOperator.of(circuitBreaker));
}
}
3. Anti-patterns và Common Pitfalls
3.1 Distributed System Anti-patterns
- Distributed Monolith
- Synchronous Communication Chains
- Shared Database
- No Service Boundaries
- Lack of Resilience
- Poor Monitoring
3.2 Common Mistakes
// Bad Practice: Tight Coupling
@Service
public class OrderService {
private final PaymentService paymentService;
private final InventoryService inventoryService;
public Order createOrder(OrderRequest request) {
// Synchronous calls creating a chain of dependencies
Payment payment = paymentService.processPayment(request);
Inventory inventory = inventoryService.updateInventory(request);
return orderRepository.save(new Order(payment, inventory));
}
}
// Good Practice: Event-Driven
@Service
public class OrderService {
private final EventPublisher eventPublisher;
public Order createOrder(OrderRequest request) {
Order order = orderRepository.save(new Order(request));
eventPublisher.publish(new OrderCreatedEvent(order));
return order;
}
@EventListener
public void handlePaymentCompleted(PaymentCompletedEvent event) {
// Handle payment completion asynchronously
}
}
4. Ví dụ Code Thực tế
4.1 Config Server
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
// application.yml
spring:
cloud:
config:
server:
git:
uri: https://github.com/company/config-repo
searchPaths: '{application}'
default-label: main
4.2 API Gateway
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(
RouteLocatorBuilder builder) {
return builder.routes()
.route("order_service", r -> r
.path("/api/orders/**")
.filters(f -> f
.circuitBreaker(c -> c
.setName("orderCircuitBreaker")
.setFallbackUri("forward:/fallback"))
.rewritePath("/api/orders/(?<segment>.*)",
"/orders/${segment}"))
.uri("lb://order-service"))
.build();
}
}
5. Use Cases và Scenarios
5.1 Event-Driven Architecture
@Configuration
public class EventConfig {
@Bean
public NewTopic orderTopic() {
return TopicBuilder.name("orders")
.partitions(3)
.replicas(2)
.build();
}
}
@Service
public class OrderEventHandler {
@KafkaListener(topics = "orders")
public void handleOrderEvent(OrderEvent event) {
switch (event.getType()) {
case CREATED:
processNewOrder(event);
break;
case UPDATED:
updateOrderStatus(event);
break;
case CANCELLED:
handleCancellation(event);
break;
}
}
}
5.2 Circuit Breaker Pattern
@Service
public class ResilientService {
private final CircuitBreakerFactory circuitBreakerFactory;
public Mono<Response> callService(String serviceId) {
CircuitBreaker circuitBreaker =
circuitBreakerFactory.create("service-cb");
return WebClient.builder()
.build()
.get()
.uri("http://" + serviceId)
.retrieve()
.bodyToMono(Response.class)
.transform(CircuitBreakerOperator.of(circuitBreaker))
.onErrorResume(this::handleError);
}
private Mono<Response> handleError(Throwable error) {
return Mono.just(new Response("Fallback Response"));
}
}
6.1 Caching Strategy
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)))
.withCacheConfiguration("orders",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(5)))
.build();
return cacheManager;
}
}
6.2 Load Balancing
@Configuration
public class LoadBalancerConfig {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
@Bean
public ReactorLoadBalancerExchangeFilterFunction lbFunction(
LoadBalancerRegistry registry) {
return new ReactorLoadBalancerExchangeFilterFunction(registry);
}
}
7. Security Considerations
7.1 OAuth2 Configuration
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(
ServerHttpSecurity http) {
http
.oauth2ResourceServer()
.jwt(jwt -> jwt
.jwtAuthenticationConverter(grantedAuthoritiesExtractor()))
.and()
.authorizeExchange()
.pathMatchers("/api/public/**").permitAll()
.pathMatchers("/api/private/**").authenticated()
.anyExchange().authenticated();
return http.build();
}
}
7.2 Service-to-Service Authentication
@Configuration
public class ServiceAuthConfig {
@Bean
public WebClient.Builder secureWebClientBuilder(
ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("keycloak");
return WebClient.builder()
.filter(oauth);
}
}
8. Testing Strategies
8.1 Integration Testing
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureWebTestClient
public class MicroserviceIntegrationTest {
@Autowired
private WebTestClient webTestClient;
@Test
public void testServiceIntegration() {
webTestClient.get()
.uri("/api/orders")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.length()").isEqualTo(10)
.jsonPath("$[0].id").isNotEmpty();
}
}
8.2 Contract Testing
@SpringBootTest(webEnvironment = MOCK)
@AutoConfigureMessageVerifier
public class OrderServiceContractTest {
@Autowired
private OrderService orderService;
@Test
@PactTestFor(providerName = "order-service")
public void testOrderCreation() {
// given
OrderRequest request = new OrderRequest();
// when
Order result = orderService.createOrder(request);
// then
assertThat(result).isNotNull();
assertThat(result.getId()).isNotNull();
}
}
9. Monitoring và Troubleshooting
9.1 Distributed Tracing
@Configuration
public class TracingConfig {
@Bean
public Tracer jaegerTracer() {
SamplerConfiguration samplerConfig =
SamplerConfiguration.fromEnv()
.withType(ConstSampler.TYPE)
.withParam(1);
ReporterConfiguration reporterConfig =
ReporterConfiguration.fromEnv()
.withLogSpans(true);
Configuration config = new Configuration("service-name")
.withSampler(samplerConfig)
.withReporter(reporterConfig);
return config.getTracer();
}
}
9.2 Metrics Collection
@Configuration
public class MetricsConfig {
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config()
.commonTags("application", "cloud-native-app")
.meterFilter(MeterFilter.deny(id -> {
String uri = id.getTag("uri");
return uri != null && uri.startsWith("/actuator");
}));
}
}
10. References và Further Reading
10.1 Cloud Native Resources
- Cloud Native Java (Josh Long & Kenny Bastani)
- Spring Microservices in Action
- Building Microservices (Sam Newman)
- Cloud Native Patterns (Cornelia Davis)
- Kubernetes in Action
- Spring Cloud
- Kubernetes
- Istio
- Prometheus/Grafana
- ELK Stack
- Jaeger
- Kong/Ambassador