Turbine Dashboard Is not Loading for Aggregation in Spring Cloud Microservice - spring-cloud

I am trying to develop a spring cloud microservice using spring MVC and spring boot framework. And Eureka server , Zuul , Ribbon , hystrix and Turbine using for spring cloud. I already developed a microservice and implemented only hystrix dashboard. I am able to take hystrix dashboard. Now I am implementing more services. So I choosed turbine for aggregation of monitoring. But it not getting the dashboard.I implemented turbine in separate spring boot project.
My pom.xml containing,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine</artifactId>
</dependency>
And My main class containing,
#SpringBootApplication
#EnableHystrixDashboard
#EnableCircuitBreaker
#EnableTurbine
public class ZTurbineClientApplication {
public static void main(String[] args) {
SpringApplication.run(ZTurbineClientApplication.class, args);
}
}
And my Turbine project application.properties file containing,
server.port=8085
spring.application.name=espace-Turbine
eureka.client.serviceUrl.defaultZone=http://localhost:8071/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
turbine:
aggregator:
clusterConfig: APPCLUSTER
app-config: espaceService1,espaceService2
instanceUrlSuffix.APPCLUSTER: /hystrix.stream
And My previous first services's application.properties file like
eureka.client.serviceUrl.defaultZone=http://localhost:8071/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
spring.application.name=espaceService1
server.port=8080
eureka:
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 3
leaseExpirationDurationInSeconds: 3
metadata-map:
cluster: APPCLUSTER
And second service's application property file contains,
eureka.client.serviceUrl.defaultZone=http://localhost:8071/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
spring.application.name=espaceService2
server.port=8081
eureka:
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 3
leaseExpirationDurationInSeconds: 3
metadata-map:
cluster: APPCLUSTER
these are my implementation details.
After I took URL "http://localhost:8085/hystrix.dashboard". And pasted "http://localhost:8085/turbine.stream?cluster=APPCLUSTER". But getting error like "Unable to connect to Command Metric Stream". Adding screenshots below.

You need to remove space from comma separated service names
turbine.aggregator.cluster-config=espace-Second_Microservice,espaceFirst_Microservice
You cannot aggregate streams from different cluster names, either use one cluster name in both espace-Second_Microservice and espace-First_Microservice or don't use cluster at all.
To define one cluster name use below config
eureka:
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 3
leaseExpirationDurationInSeconds: 3
metadata-map:
cluster: APPCLUSTER
Use below mentioned config for turbine
turbine:
aggregator:
clusterConfig: APPCLUSTER
app-config: espace-Second_Microservice,espace-First_Microservice
instanceUrlSuffix.APPCLUSTER: /hystrix.stream
Use http://{turbine host}:{turbine Port}/turbine.stream?cluster=APPCLUSTER in Hystrix Dashboard

Related

Difference in load balancer behavior

I noticed that load balancer has different behavior pattern in certain scenario.
When using discovery with load balancer and one of the services is restarted on different port - then if services are running on Spring Boot 2.3.8-RELEASE, other service can find and communicate with restarted service, but if services are running on Spring Boot 2.7.8 it will only work if below setting is set to "true":
spring.cloud.loadbalancer.health-check.refetch-instances=true
I tried to create 3x brand new projects in first test using Spring Boot 2.3.8-RELEASE and in second test Spring Boot 2.7.8 to eliminate any specific setting or configuration or my actual project. I was thinking that maybe there is something specific in my actual project causing difference in behavior, but it turns out that vanilla plain setup has exactly this same problem.
In general my expectation was that setup using Spring Boot 2.3.8-RELEASE will have exactly this same behavior in case of restarting a service on different port as Spring Boot 2.7.8 - but that doesn't seems to be a case.
I noticed that load balancer has different behavior pattern in certain scenario.
When using discovery with load balancer and one of the services is restarted on different port - then if services are running on Spring Boot 2.3.8-RELEASE, other service can find and communicate with restarted service, but if services are running on Spring Boot 2.7.8 it will only work if below setting is set to "true":
spring.cloud.loadbalancer.health-check.refetch-instances=true
I tried to create 3x brand new projects in first test using Spring Boot 2.3.8-RELEASE and in second test Spring Boot 2.7.8 to eliminate any specific setting or configuration or my actual project. I was thinking that maybe there is something specific in my actual project causing difference in behavior, but it turns out that vanilla plain setup has exactly this same problem.
In general my expectation was that setup using Spring Boot 2.3.8-RELEASE will have exactly this same behavior in case of restarting a service on different port as Spring Boot 2.7.8 - but that doesn't seems to be a case.
Here are details of my tests.
My setup is 3x spring boot applications - all in this same version (first test with 2.3.8-RELEASE and second with 2.7.8):
Discovery service - Eureka Server
Test service 1 - "caller" - Eureka Client
Test service 2 - "receiver" - also Eureka Client
The difference in behavior can be reproduce following scenario:
Start Discovery service
Start "caller" application - wait for it to register in Discovery
Start "receiver" application - also wait for it to register in Discovery and also wait for "caller" application to fetch latest record from Discovery
Call GET endpoint in "caller" application which in turn calls GET endpoint in "receiver" application
At this stage everything works fine, "caller" can find and call "receiver"
Change server port in "receiver" application to different value and restart "receiver" application
Again, wait for "receiver" application to register in Discovery and "caller" application to fetch latest record from Discovery
At this stage there is a difference in the way how Spring Boot 2.3.8-RELEASE application stack behaves and 2.7.8
What happens is 2.3.8-RELEASE will work fine after changing port in "receiver" application but 2.7.8 will ONLY be able to communicate with "receiver" if below setting is set to "true":
spring.cloud.loadbalancer.health-check.refetch-instances=true
if it's not (and that is the default setting) the 2.7.8 will not be able to ever communicate with "receiver" unless "receiver" port will be reverted to original value and both applications restarted.
Here are some more significant elements of my configuration for Spring Boot 2.3.8-RELEASE:
Discovery service
Main class:
#SpringBootApplication
#EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
application.yml:
spring:
application:
name: eureka
eureka:
client:
registerWithEureka: false
fetchRegistry: false
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abednarski79</groupId>
<artifactId>eureka-old</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>Eureka service</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Caller service
Rest template configuration:
#Configuration
public class RestTemplateConfig {
#Bean
#LoadBalanced
#Qualifier("loadBalanced Rest Template")
RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}
#Bean
#Qualifier("rest Template")
RestTemplate restTemplate() {
return new RestTemplate();
}
}
Controller:
#RestController
public class CallerController
{
private Rest Template restTemplate;
public CallerController (#Qualifier("loadBalancedRestTemplate") RestTemplate restTemplate)
{
this.restTemplate= restTemplate;
}
#GetMapping(value = "/call")
public String call()
{
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<String> (headers);
restTemplate.exchange("http://receiver/receive", HttpMethod. GET, entity, String.class);
System.out.println("Called.");
return "success";
}
}
pom.xml - only difference vs discovery service is load balancer is added:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
application.yml:
spring:
application:
name: caller
cloud:
loadbalancer:
ribbon:
enabled: false
eureka:
instance:
prefer-ip-address: true
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:8001/eureka/
Receiver application
Controller:
#RestController
public class ReceiverController
{
#GetMapping(value = "/receive")
public String receive()
{
System.out.println("Received.");
return "success";
}
}
application.yml:
spring:
application:
name: receiver
eureka:
instance:
prefer-ip-address: true
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:8001/eureka/
And here are some more significant elements of my configuration for Spring Boot 2.7.8: Discovery service
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abednarski79</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>Eureka service</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Caller service
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abednarski79</groupId>
<artifactId>caller</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>caller</name>
<description>Caller service</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Rest template configuration:
#Configuration
#LoadBalancerClient(value = "receiver", configuration = LoadBalancerConfig.class)
public class RestTemplateConfig {
#Bean
#LoadBalanced
#Qualifier("loadBalanced RestTemplate")
RestTemplate loadBalanced RestTemplate() {
return new RestTemplate();
}
#Bean
#Qualifier("rest Template")
Rest Template restTemplate() {
return new RestTemplate();
}
and load balancer configuration:
public class LoadBalancerConfig
{
#Bean
ServiceInstanceListSupplier serviceInstanceListSupplier(ConfigurableApplicationContext context, #Qualifier ("restTemplate") RestTemplate restTemplate) {
return ServiceInstanceListSupplier
.builder()
.withBlockingDiscoveryClient()
.withBlockingHealthChecks(restTemplate)
.build(context);
}
}
application.yml:
spring:
application:
name: caller
cloud:
loadbalancer:
health-check:
refetch-instances: false
eureka:
instance:
prefer-ip-address: true
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:9001/eureka/

Getting Error when trying to connect AWS Aurora Postgre cluster from spring boot app

I am trying to connect to AWS Aurora (Postgre) cluster from spring boot app using following properties
spring.datasource.driver.class.name = org.postgre.jdbc.Driver
spring.datasource.url=jdbc:postgresql://a2-xxxxx.cluster-xxxxxxxxxx.us-east-1.rds.amazonaws.com:5432
spring.datasource.username=username
spring.datasource.password=password
but I am getting following error -
*Caused by: java.lang.RuntimeException: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:postgresql://a2-xxxxx.cluster-xxxxxxxxxx.us-east-1.rds.amazonaws.com:5432
at com.zaxxer.hikari.util.DriverDataSource.<init>(DriverDataSource.java:110) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.PoolBase.initializeDataSource(PoolBase.java:331) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.PoolBase.<init>(PoolBase.java:114) ~[HikariCP-4.0.3.jar:na]*
Following are my maven pom.xml contents -
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
You should read the jdbc documentation.
If the host is specified, the url needs a / at the end. If the database you are connecting to has a different name than the user, you also have to put the name of the database after the /. Even if they are the same, it's a good idea to include the db name because that default behavior is a bit confusing.

Spring Cloud Config Server not registering as client to Spring Boot Admin

I have Spring Cloud config server and trying to register it to Spring Boot admin. In my pom.xml file I have
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-client</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.3.Release</version>
</dependency>
I have several other services registering, so I know I have all my URL and settings correct. But I am not seeing is the registering log in the config server logs.
Found the answer after running the config server in debug mode.
SpringBootAdminClientAutoConfiguration:
Did not match:
- Spring Boot Client is disabled, because 'spring.boot.admin.client.url' is empty. (SpringBootAdminClientEnabledCondition)
Matched:
- #ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
SpringBootAdminClientCloudFoundryAutoConfiguration:
Did not match:
- Spring Boot Client is disabled, because 'spring.boot.admin.client.url' is empty. (SpringBootAdminClientEnabledCondition)
Matched:
- #ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
Since the config server doesn't read from the config server git repo the client URL was not set.
Adding --spring.boot.admin.client.url=<url> to the startup fixed it.

Spring Cloud Connector and MongoDB Replica Set

I have developed a micro service in Spring boot and it is deployed in Cloud Foundry. MongoDB is a service created in PCF and it is a replica set type service. The mongodb service is bound to the micro service in PCF. I am using Spring cloud connector to automatically fetch the connection string for the mongodb service when deployed in cloud using the following code.
#Configuration
#Profile("cloud")
public class CloudFoundryDatabaseConfig extends AbstractCloudConfig{
#Bean
public Cloud cloud() {
return new CloudFactory().getCloud();
}
#Bean
public MongoDbFactory mongoFactory() {
return connectionFactory().mongoDbFactory();
}
}
This code is working perfectly fine when the mongoDB service is a standalone type. However if it is a replica set, i get a unknown host exception. Since the mongodb URI contains comma separated host names, it seems to be unresolved.
An example of MongoDB URI below.
"mongodb://username:password#101.23.65.41:28000,101.23.65.43:28000,101.23.65.45:28000/default?authSource=admin"
Error:
com.mongodb.MongoSocketException: mongod-node-0-310d0fd1.mongodb.internal: Name or service not known}, caused by {java.net.UnknownHostException
Pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-cloudfoundry-connector</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-spring-service-connector</artifactId>
</dependency>
Please help.

Spring Boot admin not showing any client applications in dashboard

I have been following this tutorial for Spring boot Admin, but when I run the admin application I can't see any spring boot client application for monitoring. I have checked that both the admin and client apps are running. Admin is running on port 8080 and client application is running on port 9010
This is what I have done in my Admin application
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>1.5.3</version>
</dependency>
Added these annotations
#Configuration
#SpringBootApplication
#EnableAdminServer
public class SpringBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminApplication.class, args);
}
}
This is what I have added in my client application
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>1.5.3</version>
</dependency>
and added this in my properties file (YAML)
spring:
boot:
admin:
url:
- http://localhost:8080
management:
security:
enabled: false
This is what my Dashboard looks like, as you can see there are no applications to monitor.