Microservices
Microservices:
--------------
What is Monolithic Application:
-------------------------------
* All type of components included in the single project, That is called Monolithic application.
Eg.
College Project (Including all below modules in the single project):
->Student
->Faculty
->Examination
->Result
->Address
What is Microservice:
--------------------
* Micro -> small
* Creating multiple small services
* So here we will create all the component as a seperate application (micro services).
* So here creating multiple spring boot projects.
Eg: (Below all creating as seperate application):
->Student
->Faculty
->Examination
->Result
->Address
Advantages:
* Testing -> If you change any one microservice you can test that alone and you can deploy that alone. So nothing else get down
* Scalable -> Any specific applicaiton we can scalable. Eg. at the time of result , we can scale up the result micorserive up and others down.
* Loosely Coupling -> Using REST API we are achiving this
Spring Cloud:
---------------
* To maintain 100 or 1000 of micro services Spring Cloud will help you for this with below concepts.
Spring Cloud Projects:
* Spring Cloud Open Feign -> To make a REST API
* Spring Cloud Netflix Eureka -> To Maintain all the projects based on Name not a URL (Service Discovery & Registry)
* Spring Cloud Load Balancer -> Load Balancing Machanism to handle the request
* Spring Cloud API Gateway -> It is the entry point of the microservices (Authentication, Request or Response handling in common way)
* Fault Tolerance -> If any of your microservice is down. It should not impact others.
* Sleuth and Zipkin -> Sleuth to trace the application flow. (Zipkin is the UI tool to see the trace).
* Config Server -> To maintain a properties in common place. Like database credentials etc., (GIT will involve here)
Creating Micro Service Application:
------------------------------------
* Create Spring Boot Project
* Add starter , mysql, Spring Data JPA, Spring Web dependencies
* In properties spring.application.name = <application-name>
* server.port = <port-number>
* Controller should annotate with @RestController , @RequestMapping, @PostMapping etc.,
Spring Cloud Open Feign:
-------------------------
* Open Feign is the Rest Client. It is helpful to make Rest Calls to other services.
* It is similar like WebClient. But Open Feign is providing in declarative way.
* Feign clients is always a interface
Implementation:
* Add the dependency
* Enabling the package using @EnableFeignClients annotation
* @FeignClient (url="<other application url>" value = "<any meaning full name>", path="<api-path>")
Eg:
@FeignClient(url = "${address.service.url}", value = "address-feign-client",
path = "/api/address")
public interface AddressFeignClient {
@GetMapping("/getById/{id}")
public AddressResponse getById(@PathVariable long id);
}
Service class implementation as like below:
@Autowired AddressFeignClient addressFeignClient;
addressFeignClient.getById(student.getAddressId()) // It will call another application based on our FeignClient Configuration.
Spring Cloud Netflix Eureka (Service Discovery & Registry):
-----------------------------------------------------------
Service Discovery & Registry:
* Have a Microservice with 100s of application. 20 application is using a application called address service. So If I change address service url. I want to update that 20 application. It is very difficult.
To handle this, what will do instead of reffering the url other 20 applications will refer the service name instead of url. So if you are making any change in the url nothing need to worry.
So these all registry will be done in the Eureka Server. So Eureka Server will take care of keeping the url mapping with service name.
Creating Eureka Server:
* Create spring boot application.
* Add Spring cloud Eureka Server dependency
* In application.properties set port -> server.port = <port-number>
* spring.application.name = <application-name-server>
* eureka.client.register-with-eureka=false // we dont want to register server applicaiton with eureka server. this is meaning less.right.
* eureka.client.fetch-registry=false
* annote @EnableEurekaServer to inform spring boot application as this is Eureka Server.
So (In Our microservice applications we need to add below configuration),
* In Other Microservice application we need to add Eureka Client.
* annotate application with @EnableEurekaClient
* In properties eureka.client.service.url.defaultZone = <eureka-server-url>
Now we can remove FeignClient url and we can use name in the value part as we registered with eureka server
Eg.
@FeignClient(value = "address-service",
path = "/api/address")
public interface AddressFeignClient {
@GetMapping("/getById/{id}")
public AddressResponse getById(@PathVariable long id);
}
Spring Cloud Load Balancer:
--------------------------
* In Case we are running our application in 2 instances. So in that case, if our application receive 1000 request 500 has to go one instance and another 500 has to go another instance. All 1000 should not go one instance. This is called Load Balancing.
* It will use Round Robin Method to split the requests between multiple instances.
* Add dependency in pom.xml
* Create new class with annotate @LoadBalancerClient and providing the value as application name.
* Need to create Bean for Feign Builder.
* This Bean will be annotate with @LoadBalanced. This will take care of the application load balancing.
Eg:
@LoadBalancerClient(value = "address-service")
public class AdrSerLoadBalConfig {
@LoadBalanced
@Bean
public Feign.Builder feignBuilder () {
return Feign.builder();
}
}
Spring Cloud API Gateway:
-------------------------
* For example, you have a 100s of microservices. You want to authenticate the 100s of application for consumers. Will you add authentication for 100s of application seperately.? No.
In this case, API Gateway coming into Picture, It will take care of the authentication and its responsibility to route the request to specific microservices.
So here we will not share our microservice url to consumer. we will give Gateway application url to consumer
* API Gateway have the option as Prefilter & post filter
Create API Gateway:
* Create Spring Boot application
* Add Gateway Dependency
* Add Eureka Client dependency. So that we can communicate with Eureka Server.
* @EnableEurekaClient
* IN properties eureka.client.service-url.defaultZone=<eureka-server-url>
Configure Spring Cloud:
* In Properties for routing purpose,
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
Pre filter:
* Create New Class
* Once consumer request the request to microservice first pre filter will execute then pre filter take care of sending the request to particular microservice
Eg.
@Configuration
public class CustomFilter implements GlobalFilter {
Logger logger = LoggerFactory.getLogger(CustomFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
logger.info("Authoriation = " + request.getHeaders().getFirst("Authoriation"));
return chain.filter(exchange);
}
}
Post Filter:
* Before Gateway sending response to the consumer, it will get execute.
Eg:
@Configuration
public class CustomFilter implements GlobalFilter {
Logger logger = LoggerFactory.getLogger(CustomFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (request.getURI().toString().contains("/api/student/")) {
}
logger.info("Authorization = " + request.getHeaders().getFirst("Authorization"));
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
logger.info("Post Filter = " + response.getStatusCode());
}));
}
}
Feign Client with API Gateway:
* Internal address microservice to call student microservice also need to include this api-gateway.
* So need to configure our Feign client value as api-gateway
Eg.
@FeignClient(value = "api-gateway")
public interface AddressFeignClient {
@GetMapping("/address-service/api/address/getById/{id}")
public AddressResponse getById(@PathVariable long id);
}
Load Balancing with API Gateway:
* If we are using API Gateway we no need to worry about load balancing. API gateway will take care of that internally.
Fault Tolerance & Circuit Breaker with Resilience4j:
Possible Failures:
* Have the scenario, when one of our microservice is down or any other failures ?
Circuit Breaker:
* Switch Close/Open
States:
* Closed
* Open
* Half-Open
Properties:
* slidingWindowSize -> eg.100. So last 100 calls it will consider and it will react
* failureRateThreshold -> eg. 50% value. Based on failure of above mentioned 100 calls. 50 % of the calls is failed then switch will be open.
* waitDurationInOpenState -> eg. 30s . 30s it will be open
* Then based on property configuration It will go to off-open state
* permittedNumberOfCallsInHalfOpenState -> eg.5 . Only 5 calls will allow then
* failureRateThreshold -> failure >=failureRateThreshold -> It will go to open state
* failure <failureRateThreshold -> It will go to closed state
Dependency:
* resilient4j dependency
* spring AOP dependency
* spring boot actuator
Resilient Properties:
resilient4j circuitbreaker properties
* resilient4j.circuitbreaker.instances.addressService.sliding-window-size = 10
* resilient4j.circuitbreaker.instances.addressService.failure-rate-threshold = 50
* resilient4j.circuitbreaker.instances.addressService.wait-duration-in-open-state = 30000
* resilient4j.circuitbreaker.instances.addressService.automatic-transition-from-open-to-half-open-enabled=true
* resilient4j.circuitbreaker.instances.addressService.permitted-number-of-calls-in-half-open-state=5
resilient4j with actuator properties
* resilient4j.circuitbreaker.instances.addressService.allow-health-indicator-to-fail=true
* resilient4j.circuitbreaker.instances.addressService.register-health-indicator=true
actuator properties
* management.health.circuitbreaker.enabled=true
* management.endpoints.web.exposure.include=health
* management.endpoints.health.show-details=always
In Specific method,
Eg.
@CircuitBreaker(name = "addressService")
public AddressResponse getAddressById (long addressId) {
AddressResponse addressResponse = addressFeignClient.getById(addressId);
return addressResponse;
}
FallBack Method with Resilience4j:
@CircuitBreaker(name = "addressService", fallbackMethod = "fallbackGetAddressById")
public AddressResponse getAddressById (long addressId) {
AddressResponse addressResponse = addressFeignClient.getById(addressId);
return addressResponse;
}
public AddressResponse fallbackGetAddressById (long addressId, Throwable th) { // Throwable th -> This is optional
return new AddressResponse();
}
As per Spring AOP above will not work if you are calling the getAddressById in the same Class, So need to create seperate class for that,
@Service
public class CommonService {
Logger logger = LoggerFactory.getLogger(CommonService.class);
long count = 1;
@Autowired AddressFeignClient addressFeignClient;
@CircuitBreaker(name = "addressService", fallbackMethod = "fallbackGetAddressById")
public AddressResponse getAddressById (long addressId) {
logger.info("count = " + count);
count++;
AddressResponse addressResponse = addressFeignClient.getById(addressId);
return addressResponse;
}
public AddressResponse fallbackGetAddressById (long addressId, Throwable th) {
logger.error("Error = " + th);
return new AddressResponse();
}
Distributed with Sleuth and Zipkin:
* It is used for Distributed Tracing
* Trace Id will be unique for all services which is generated by Sleuth.
* Span Id will be unique for every services which is generted by Span.
* Zipkin is providing the UI for above tracing.
Config Sleuth:
* Add Sleuth dependency in microservice apps and api-gateway application
In API Gateway propeties,
* spring.sleuth.reactor.instrumentation-type=decorate-on-each
Config Zipkin:
* Add dependency in microservices and api-gateway
* In properties,
* spring.zipkin.base-url = <zipkin-url>
Spring Cloud Config Server:
----------------------------
* To maintain common properties.
* Using git we can manage that.
* To connect git we will use config server application. So that in future instead of git if we are using any other repository, we can easily config that.
Create Config Server:
* Create spring boot application
* Add config server dependency
* Add eureka client dependency
* Add @EnableConfigServer annotation
* Add @EnableEurekaClient
* spring.cloud.config.server.git.uri=<add-git-url>
* Add eureka server url
Comments
Post a Comment