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. Performance Considerations

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

10.2 Tools và Frameworks

  • Spring Cloud
  • Kubernetes
  • Istio
  • Prometheus/Grafana
  • ELK Stack
  • Jaeger
  • Kong/Ambassador