How to create several instances of a Microservice: SpringBoot and Spring Cloud - java

I am new to the Microservices, I came across several concepts like Service Registry and Load Balancing. I have following questions-
How multiple instances of a particular microservice are created?
How Service Registry using Eureka Server helps in distributing the load on the several instances of Microservice?
In my scenario, I created 3 different microservices and registered them on my service registry-
Service Registry Configuration-
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #this will ensure that this service
#is not itself registered as a client
fetch-registry: false
Client Configuration-
eureka:
instance:
prefer-ip-address: true
client:
fetch-registry: true #true by default
register-with-eureka: true #true by default
service-url:
defaultZone: http://localhost:8761/eureka
When I stop my services I still see the services as Up and Running on Eureka and get a warning as-
Can somebody please help me find the reason for this problem?

1. To communicate with another instance, you can use Eureka to find the address of the service you want to talk to. Eureka will give you a list of all the available instances of that service, and you can choose which one you want to communicate with.
2. The Eureka server is a microservice that keeps track of the locations of other microservices within the same system. These other microservices register themselves with the Eureka server so that they can be found and contacted by other microservices when needed. The Eureka server acts as a directory for the microservices, allowing them to find and communicate with each other. (not sure if that's what you asked).
3. In order to remove the warning:
You can set a renewal threshold limit in the Eureka server's properties file.
eureka.renewalPercentThreshold=0.85

1. To scale your microservice locally, you can run multiple instances of your Spring Boot application each on a different port.
First update the port on the microservice you wish to scale in the application.yml file to:
server:
port: 0
This will start the application on a random port each time you run it.
If you run 2 applications now, you will see 1 instance of your microservice on your Eureka dashboard. This is because they both have the same Eureka instance id. To fix this you need to generate a new instance id so add the below in the same application.yml:
spring:
application:
name: "hotel-service"
eureka:
instance:
instance-id: "${spring.application.name}:${random.value}"
Finally, just run the same application more than once. You can do this on InteliJ by right clicking on the main class and selecting run and then doing that again. Some extra setup may be required to run multiple instance of the same application on IntelliJ, please see link: How do I run the same application twice in IntelliJ?
If you are using Eclipse/STS, right click on project > Run as > Spring Boot App (do this twice or more).
Alternatively if you have maven installed. Open a terminal and run mvn spring-boot:run and then open a new terminal and run the command again.
Now you should see multiple instances of your application on the Eureka dashboard.
Note: In production scaling up a microservice is done on the by the Devops team, for example a container orchestration platform such as Kubernetes can be used to increase the instances of a microservices.
2. Generally an API gateway is used to route incoming network requests to microservices and do the load balancing while service discovery allows microservices to find and communicate with each other.
With Eureka service discovery, the microservices will register on the discovery server. An API gateway will also register on the Eureka server and will do load balancing.
One method of load balancing is the round-robin strategy, where the load balancer will rotate through the available instances in a sequential order. This helps to distribute the load evenly across the instances. There are also other load balancing methods, like Least Connection, Resource Based (Adaptive) etc.
3. The error your getting is due to the self preservation mode which comes with the Eureka server. The Eureka server expects a heartbeat from microservices every 30 seconds by default, if it doesn't receive a heartbeat within 90 seconds it will de-register a microservice from it. In a case where Eureka doesn't receive heartbeat signals from many services, it will de-register each microservice up to a certain limit. Then after it will enter self preservation mode and will not de-register any more microservices and will try to re-establish a connection, this is because a network issue could result in eureka server from not receiving heartbeats.
Since you are developing locally and you stopped running your microservices, you are seeing the expected behaviour of the Eureka server entering self preservation mode, which you can ignore.

You already register the microservices in eureka server.
Just run same service [hotel-service, rating service] on different port. Eureka server check name while registering microservice if It found same name It registered microservice with different {ip-address:port} format, you can also use same approch for load balancing

Related

Why do we use port number localhost: 8080? Why don't we use a port number when using www.example.com?

When I use a Spring Boot app in local it uses, localhost:8080. When it is pushed to Pivotal Cloud Foundry, it has some route https://my-app.xyz-domain.com and we can access the URL without a port, what is happening behind the scene?
Please help me understand.
There is a default port number for each protocol which is used by the browser if none is specified. For https it is 443, for http 80 and for telnet 23.
On Unix and similar systems like Linux, those are often not available to a developer so other ports are used but then they have to be specified. 8080 is often available and looks like 80.
On CloudFoundry, your application is actually still running on localhost:8080. The reason that you can access your application through https://my-app.xyz-domain.com is that the platform handles routing the traffic from that URL to your application.
The way this works is as follows:
You deploy your application. It's run by the foundation in a container. The container is assigned a port, which it provides to the application through the $PORT env variable (this can technically change, but it's been 8080 for a long time). Your application then listens on localhost:$PORT or effectively localhost:8080.
The platform also runs Envoy in your container. It's configured to listen for incoming HTTP and HTTPS requests, and it will proxy that traffic to your application on localhost:$PORT.
Using the cf cli, you map a route to your application. This is a logical rule that tells the platform what external traffic should go to your application. A route can consist of a hostname, domain, and/or path. For example, my-cool-app.example.com or my-cool-app.example.com/foo. For a route to work, the domain must have its DNS directed to the platform.
When an end-user accesses the route that you mapped, the DNS resolves to the platform and the traffic is directed to the external load balancers (sometimes TCP/layer4, sometimes HTTPS/layer7) that sit in front of the platform. These proxies do not have knowledge of CF, they just proxy incoming traffic.
Traffic from the external load balancers is spread across the set of the platform Gorouters. The Gorouter is a second layer of proxies, but these proxies have knowledge of the platform, specifically, all of the routes that have been mapped on the platform and where those applications actually live.
When a request comes to Gorouter, it will recognize the route like my-cool-app.example.com and look up the location of the container where that app is running. Traffic from Gorouter is then proxied to the Envoy which is running in the app container. This ties into step two as the Envoy will route that traffic to your application.
All in total, incoming requests are routed like this:
Client/Browser -> External LBs -> Gorouters -> Envoy -> Application
First, you should change the port to 80 or 443, because HTTP corresponds to 80, and HTTPS corresponds to 443. Then, you should set the domain name to resolve to the current host, so that you can access the current application through the domain name. In addition, if you want to set the local domain name, then The hosts file should be modified.

How to setup eureka clients behind reverse proxy with different port?

I am currently trying to setup service discovery with eureka, but the clients register with the wrong port. Every Eureka client is on a different server behind its own nginx reverse proxy and it is reachable from outside via https on port 443, but the java eureka clients are configured on different port. I also tried configuring them on the same port as nginx exposes, but than the nginx server has infinited redirects and stops after some attempts with error "invalid redirect". Being on different port the eureka clients register at the server with the port configure in spring boot yaml server port config. If then a client tries to reach another client it uses the port configured in the spring boot application. I need to be able to register the eureka client on a different port than I am running the client. Is that possible? What am I missing here? Would be using Zuul as a gateway make a difference here?
Setup (every system is deployed on a different VServer behind NGINX reverse proxy):
Eureka Server
Multiple Eureka Clients (API, UI, etc)
Identity Management Keycloak SSO server not registered with eureka server
A port can only be used by one service at a time. Hence, you cannot configure nignx and spring boot to listen on the same port and receive the error message.
Spring boot does not know about the proxy setup and hence the eureka client registers the instance (with the spring.port) at the eureka server. You can configure the eurka instance with the EurekaInstanceConfig. In this case you want to change eureka.instance.port=443 to the one exposed by nginx.

connect to rabbitmq server through proxy

how to connect to rabbitmq server with web proxy. I have rabbit credentials in application.yml spring.rabbitmq.host, spring.rabbitmq.port, spring.rabbitmq.username, spring.rabbitmq.password
I am not pretty sure what do you need but pls read below basic info:
The RabbitMQ is divided into 2 parts:
The Queue Service itself
The Management UI
You can install 1 without 2 or both.
The service works on port 5672 (and it is not HTTP) whereas Management UI on port 15672 (and it is HTTP).
Be aware that to connect to Management UI (via the browser) you need to have management plugin installed or use docker image with "management" postfix.
To sum up:
Your spring-boot application connects over port 5672 with the service directly.
If you have performed the steps mentioned before you should be able to connect to the management plugin using http://localhost:15672.

Monitoring replicas with Spring Boot Admin on Kubernetes

I setted up a Spring Boot Admin Client on Kubernetes and scaled up to 3 replicas, but when I try to check the instances the Admin Server show just one
In order for SBA (Spring Boot Admin) to understand that the three instances of your services are distinct, you need to make sure each is registered in SBA using its "internal IP address".
Doing so will let SBA query the health of each instance independently, and will result with spring creating unique instance-id for each pod.
Note that using the k8s service name for the registration will result with SBA's health queries being load-balanced across the service's pods.
To do this, add to your application.yml the following:
spring:
boot.admin.client:
url: http://<k8s-service-name-and-port>
instance:
name: <service-name>
service-base-url: http://${K8S_POD_IP}:8080
management-base-url: http://${K8S_POD_IP}:8081
auto-deregistration: true
Having:
K8S_POD_IP is an environment-variable with the pod's IP address that must be accessible from SBA - this is the address that will be used by SBA to query for your service instance's health
spring.boot.admin.client.url is the URL that will be used by SBA's UI when you click on an instance of your service - this URL should point to k8s's service
spring.boot.admin.client.management-base-url - this is used by SBA to monitor every service's health, should be unique for every instance and should be accessible from SBA
If you don't set auto-deregistration to true whenever you roll out an update or scale down your service, you'll get notification of unhealthy instances - with this setting, instances will derigister from SBA when shutdown.
you need set parameter in yml file:
eureka.instance.instance-id: ${spring.cloud.client.ip-address}:${server.port}

Port Binding - 12 Factor App

Whenever I deploy a spring boot app , it had embedded tomcat container. It relys on container being available. Does it mean that these are not 12 factor app compliant as depends on runtime injection of webserver?
What does TCP routing mean for non-http services?
Port Binding
Export services via port binding. The 12-factor app is
completely self-contained and does not rely on runtime injection of a
web server into the execution environment to create web-facing
service.
For Pivotal Cloud Foundry, non-HTTP services require TCP routing in
order to be replatformed.
When you run locally, a spring boot app, it runs with a default profile. So, Spring will leverage your port and other settings at runtime.
When you push to cloud, a spring boot app runs with a cloud profile. In a cloud profile, port settings are dictated by the cloud and settings you provide are ignored.
In PCF, a Diego cell hosts all app instances. A Diego cell has its own CIDR block for apps its hosting. So your app instance will get an IP from that range. And you cannot access the app by its ip.
The Diego cell vm though, has the IP from the CIDR range of the network its running. Diego cell also uses NAT-ing to map you app ip to a port on the Diego cell vm. That is how the traffic is routed to your app.
As you can see, the Diego cell, in PCF, cannot rely that the port you provided. Instead it will run the app where it can, and NAT to an available port.
Take a look at Diego Reference Architecture.
As to your second question, Go-Routers in Cloud Foundry route requests to app instances. By default only http/https traffic is enabled on Go-Routers. You can enable TCP Routing on Go-Routers. This was added, I believe, in PCF 1.9.
Here's the documentation.

Categories