Cloud computing

Introduction

Architecture de Spring Cloud

Eureka Config Serve Zuul Consul Hystrix Resilience4J

Spring Boot (BackEnd) TPs

Creation,Dépendance,Configuration Exemple Video RestController

Produit Rest API

Entity et repository Ajouter Afficher Liste Produit Détails,Supprimer,Vider Modifier

Angular (FrontEnd)

Angular Rappel CLient CRUD

Spring Security

User Auth

CRUD

Vente CRUD

To be Continued...

Middlewares Orientés Messages

Communication Synchrone vs. Asynchrone API JMS : Java Message Service JMS avec ActiveMQ et HornetQ KAFKA

Spring Batch

Spring Batch

Stream Processing

Kafka Streams

Architectures Serverless

Architectures Serverless Résumé



Spring Cloud Consul

  • Spring Cloud Consul integrates Consul with Spring Boot applications, facilitating service discovery, configuration management, and distributed system coordination.
  • Leverages the open-source Consul platform for managing complex microservice architectures, enhancing service resilience and ease of scaling.
graph TD A[Spring Cloud Consul] --> B[Service Discovery] A --> C[Configuration Management] A --> D[Health Checking] A --> E[Load Balancing] B --> F[Service Registration] B --> G[Service Discovery API] C --> H[Centralized Config Storage] C --> I[Dynamic Config Updates] D --> J[Health Check Monitors] D --> K[Service Status Tracking] E --> L[Traffic Distribution] E --> M[Failover Handling] style A fill:#2b6cb0,stroke:#ffffff,stroke-width:2px style B fill:#4caf50,stroke:#ffffff,stroke-width:1px style C fill:#ff9800,stroke:#ffffff,stroke-width:1px style D fill:#2196f3,stroke:#ffffff,stroke-width:1px style E fill:#9c27b0,stroke:#ffffff,stroke-width:1px

Install and Start Consul

  • Download Consul: https://developer.hashicorp.com/consul/install
  • Unzip the downloaded file.
  • add the location to your PATH for Windows).
  • consul agent -dev
  • it will run on localhost:8500.
  • Access the Consul UI: http://localhost:8500 to access the Consul UI.

Tp1: Service Discovery

1. Client-A Application

Step 2.1: Create a Spring Boot Project for Client-A
Dependencies:
  • Spring Web
  • Spring Cloud Starter Consul Discovery
  • Spring Boot DevTools (optional for easier development)
pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

Step 2.2: Configure application.yml for Client-A

Create a file named application.yml in the src/main/resources:

spring:
  application:
    name: client-a
  cloud:
    consul:
      host: localhost
      port: 8500
	  

Step 2.3: Create a REST Controller for Client-A

Create a REST controller that exposes an endpoint:

package com.example.clienta;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClientAController {
    
    @GetMapping("/greet")
    public String greet() {
        return "Hello from Client A!";
    }
}

Step 2.4: Create the Main Application Class


package com.example.clienta;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ClientAApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientAApplication.class, args);
    }
}

Run Client A

2. Client-B Application Setup

Create a Spring Boot Project for Client-B

Similar to Client-A, create another Spring Boot project for Client-B with the same dependencies.

pom.xml


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

application.yml for Client-B

Create a file named application.yml in the src/main/resources directory with the following content:

spring:
  application:
    name: client-b
  cloud:
    consul:
      host: localhost
      port: 8500
	  

Create a REST Controller for Client-B

Create a REST controller that calls Client-A:

package com.example.clientb;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class ClientBController {

    @Autowired
    private DiscoveryClient discoveryClient;

    private final RestTemplate restTemplate = new RestTemplate();

    @GetMapping("/call-a")
    public String callClientA() {
        List<ServiceInstance> instances = discoveryClient.getInstances("client-a");
        if (instances != null && !instances.isEmpty()) {
            String clientAUrl = instances.get(0).getUri().toString() + "/greet";
            return restTemplate.getForObject(clientAUrl, String.class);
        }
        return "Client A not available";
    }
}
 
  • DiscoveryClient: Used for service discovery. It provides information about registered services (such as their URLs) and allows applications to locate other services by name.
  • RestTemplate: Used for making HTTP requests. After obtaining the service URL from DiscoveryClient, RestTemplate uses this URL to make RESTful calls to the discovered service.
  • Client-B uses DiscoveryClient to retrieve the URL of Client-A from the Consul Server.
  • DiscoveryClientcontacts Consul Server to fetch the URL of Client-A.
  • RestTemplate then uses the retrieved URL to make HTTP requests to Client-A.
graph TD ClientB["Client-B Application"] -->|Uses| DiscoveryClient["DiscoveryClient"] DiscoveryClient -->|Finds service instance URL for 'client-a'| ClientAURL["client-a URL"] ClientB -->|Uses| RestTemplate["RestTemplate"] RestTemplate -->|Makes HTTP request to| ClientAURL ClientB --> ConsulServer["Consul Server"] DiscoveryClient -->|Fetches service information from| ConsulServer ClientAURL -->|Registered with| ConsulServer

Create the Main Application Class for Client-B


package com.example.clientb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ClientBApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientBApplication.class, args);
    }
}
 

Run

  • Run Consul
  • Run Client-A:
  • Run Client-B:
Go to http://localhost:8500 to see both Client-A and Client-B registered.
Test the API: Use a tool like Postman or cURL to test the endpoints.

Call Client-A: http://localhost:8080/greet
Call Client-B :that call A :http://localhost:8081/call-a
You should see:

The response from Client-A when hitting the /greet endpoint.
The response from Client-B calling Client-A through service discovery.

Configuration Management

  1. Consul: Acts as a centralized configuration storage where configurations (key-value pairs) for applications are stored.

  2. Spring Boot Application: The application loads configurations from Consul when it starts and injects them into the @ConfigurationProperties class (e.g., AppConfig).

  3. @RefreshScope: This annotation allows specific beans, such as AppConfig, to be refreshed with updated values when a configuration refresh is triggered.

  4. Actuator /refresh Endpoint: When a POST request is sent to /actuator/refresh, Spring Cloud reloads the configurations from Consul without restarting the application.

  5. User/Admin: Can update configuration values directly in Consul and then trigger the /refresh endpoint, making the updated configurations immediately available in the application.

graph TD Consul["Consul Server (Central Config Storage)"] -->|Stores config values| KeyValueStore["Key-Value Store"] ClientApp["Spring Boot Application"] -->|Loads config on startup| ConfigProperties["@ConfigurationProperties (AppConfig)"] ClientApp --> ActuatorRefresh["/actuator/refresh Endpoint"] KeyValueStore -->|Provides config values| ClientApp ConfigProperties -->|Holds config values| RefreshScope["@RefreshScope"] User["User/Admin"] -->|Updates config| KeyValueStore User -->|Triggers refresh| ActuatorRefresh ActuatorRefresh -->|Refreshes updated config| ConfigProperties

Create Configuration

Create Configuration in Consul Key-Value Store
  • Open the Consul UI at http://localhost:8500.
  • Navigate to Key/Value.
  • Create a key-value pair :config/application-name/data
  • config/client-a/messge/
  • use cmd :consul kv put config/client-a/message "client a message"

Create the Spring Boot Application

including the following dependencies:
  • Spring Web (to create REST endpoints)
  • Spring Cloud Starter Consul Config (for Consul integration)
  • Spring Boot Actuator (for monitoring and refreshing)

pom.xml

:

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-discovery</artifactId>
		</dependency>
		<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
		  <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

Configure application.yml for Consul

spring:
  application:
    name: clienta

  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        enabled: true
      config:
        enabled: true
        prefix: config

  config:
    import: "consul:"

management:
  endpoints:
    web:
      exposure:
        include: health,info,refresh

server:
  port: 8080


Use Consul Configuration in the Application


package com.example.clienta;

import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@RefreshScope
@Component

public class AppConfig {
	@Value("${message}")
	private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
To make the configuration update dynamically, we’ll use Spring Cloud’s @RefreshScope annotation and Spring Boot Actuator’s /refresh endpoint.

Create a REST Controller to Display the Configuration


package com.example.clienta;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConfigController {

    private final AppConfig appConfig;

    public ConfigController(AppConfig appConfig) {
        this.appConfig = appConfig;
    }

    @GetMapping("/message")
    public String getMessage() {
        return appConfig.getMessage();
    }
}

Run

Enable Actuator’s Refresh Endpoint In application.yml, enable the /actuator/refresh endpoint by adding the following configuration:

management:
  endpoints:
    web:
      exposure:
        include: refresh

Run

http://localhost:8080/message
You should see the value of message as set in Consul (Hello from Consul Config!).
Update the Configuration in Consul: Go to http://localhost:8500. Update the message key under config/client-a/data to a new value, like "Hello, updated from Consul!".
Refresh the Configuration: you can
  • 1.Restart the application
  • 2.send a POST request to the /actuator/refresh endpoint:
     POST http://localhost:8080/actuator/refresh
    http://localhost:8080/message

Load balancing

  • Load balancing is a technique for distributing network traffic across a server farm.
  • It optimizes network performance, reliability, and capacity.
  • Reduces latency by evenly distributing demand among multiple servers and resources.
  • Uses an appliance (physical or virtual) to identify the best server for client requests in real-time.
  • Prevents overwhelming a single server during heavy network traffic.
  • Provides failover; if one server fails, workloads are redirected to a backup server.
graph TD A[Client Request] --> B[Load Balancer] B --> C{Available Servers} C -->|Server A| D[Forward to Server A] C -->|Server B| E[Forward to Server B] C -->|Server C| F[Forward to Server C] D --> G[Process Request] E --> G F --> G G --> H[Return Response] subgraph Failover Handling H -->|Failure Detected| I[Load Balancer] I --> C C -->|Backup Server| J[Forward to Backup Server] J --> K[Process on Backup Server] K --> L[Return Response to Client] end
  1. Client Request:

    • The process starts with a client making a request.
  2. Load Balancer:

    • The load balancer receives the client request and determines which server is available to handle the request.
  3. Available Servers:

    • The load balancer evaluates the pool of available servers (e.g., Server A, Server B, Server C) and chooses one to forward the request.
  4. Forwarding Requests:

    • The load balancer forwards the request to the selected server, which processes the request and returns a response.
  5. Response:

    • The server processes the request and sends the response back to the client.
  6. Failover Handling:

    • If the load balancer detects a failure while processing the request (for example, if the selected server becomes unavailable):
      • The load balancer redirects the request to a backup server.
      • The backup server processes the request and returns the response to the client.