Spring Eureka Client Failover - spring

I'm trying to get the failover behavior of the Eureka Client working and am receiving the below exception. Eureka server1 is shutdown and I want it to failover to Eureka server2. The application realizes server 1 is down and tries to use the failover, but gets to this place in the code and throws an exception because the backup registry isn't defined.
2016-07-08T14:25:41.369Z WARN 0 [main] com.netflix.discovery.DiscoveryClient: Using default backup registry implementation which does not do anything.
2016-07-08T14:25:41.370Z WARN 0 [main] com.netflix.discovery.DiscoveryClient: Cannot fetch applications from apps although backup registry was specified
java.lang.UnsupportedOperationException: Backup registry not implemented.
at com.netflix.discovery.NotImplementedRegistryImpl.fetchRegistry(NotImplementedRegistryImpl.java:15)
at com.netflix.discovery.DiscoveryClient.fetchRegistryFromBackup(DiscoveryClient.java:1811)
My bootstrap.yml
eureka:
client:
fetchRegistry: true
service-url:
defaultZone: https://server1/eureka/,https://server2/eureka/
This the line in the Eureka Client the failure is occurring.
private void fetchRegistryFromBackup() {
try {
#SuppressWarnings("deprecation")
BackupRegistry backupRegistryInstance = newBackupRegistryInstance();
if (null == backupRegistryInstance) { // backward compatibility with the old protected method, in case it is being used.
backupRegistryInstance = backupRegistryProvider.get();
}
if (null != backupRegistryInstance) {

You may try the following configuration:
eureka:
client:
register-with-eureka: true
fetch-registry: true
availability-zones:
us-east-1: us-east-1a,us-east-1b
region: us-east-1
service-url:
us-east-1a: http://<server1>/eureka/
us-east-1b: http://<server2>/eureka/

Related

management endpoints throwing GroovyCastException when served on different port

I have the following health management endpoints in my application.yml file
management:
endpoints:
health:
sensitive: false
web:
base-path: /
and I have an interceptor with the following code
class TestInterceptor {
TestInterceptor() {
matchAll()
}
boolean before() {
if (request.forwardURI?.endsWith('.json')) {
// ... some code
return false
}
true
}
}
this is working great. The application is working on 8080.
But as soon as I change the port of management endpoints (so that health check is served on a different port), the following code
management:
server:
port: 8989
endpoints:
health:
sensitive: false
web:
base-path: /
Ref# https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/html/production-ready-monitoring.html
then the application is throwing a cast exception when accessing the request object in the interceptor
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot
cast object 'Request(GET
//localhost:8989/testApp/health)#68117e64' with class
'org.springframework.web.context.request.ServletRequestAttributes' to
class 'org.grails.web.servlet.mvc.GrailsWebRequest'
any suggestion to fix the issue.
(Grails 4.0.12, Groovy 2.5.14 and Java 11)
Upgrade to Grails 5. The above functionality working fine with that.

Spring Cloud Consul health check and status configuration on GCP

We are trying to register a spring-cloud-consul application with consul on GCP compute engine, where it is able to register the application with the consul, but there are two problems we are facing with the application. Below is bootstrap.yaml and server.yaml for the application,
application.yaml
server:
port: 10003
spring:
application:
name: hello-service
cloud:
consul:
enabled: true
inetutils:
useOnlySiteLocalInterfaces: true
endpoints:
actuator:
sensitive: false
bootstrap.yaml
spring:
cloud:
consul:
enabled: true
host: 10.160.0.18
port: 8500
discovery:
prefer-ip-address: true
Consul is not able to call health-check on compute engine, possibly because it's registered on the internal domain name of the instance.
service with consul: NewService{id='hello-service-10003',
name='hello-service', tags=[secure=false],
address='consul-app-test.c.name-of-project.internal', meta=null,
port=10003, enableTagOverride=null, check=Check{script='null',
interval='10s', ttl='null',
http='http://consul-app-test.c.name-of-project.internal:10003/actuator/health',
method='null', header={}, tcp='null', timeout='null',
deregisterCriticalServiceAfter='null', tlsSkipVerify=null,
status='null'}, checks=null}
Application, not de-registering from the consul. We have stopped the application still it shows on consul UI.
I made a few changes in the application.yaml and bootstrap.yaml which worked for me.
application.yaml
spring:
application:
name: hello-service
cloud:
consul:
discovery:
instanceId: ${spring.application.name}:${random.value}
health-check-critical-timeout: 3m
prefer-ip-address: true # disable if we want to use google cloud internal DNS
bootstrap.yaml
spring:
cloud:
consul:
enabled: true
host: 10.160.0.18
port: 8500
if you use version 2.1.2 like me: org.springframework.cloud:spring-cloud-starter-consul-discovery:2.1.2.RELEASE
you can set:
spring:
cloud:
consul:
host: localhost # consul的地址
port: 8500 # consul 的端口
discovery:
prefer-ip-address: true # // This must be matched
tags: version=1.0
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}
healthCheckPath: /actuator/health # 服务做健康检查的端口
healthCheckInterval: 15s # 服务健康检查的周期
healthCheckTimeout: 60s # 服务检查是的timeout时长
healthCheckCriticalTimeout: 5m # 服务健康检查失败5分钟后,删除服务
and you can look the source code in ConsulDiscoveryProperties:
#ConfigurationProperties("spring.cloud.consul.discovery")
public class ConsulDiscoveryProperties {
……
/** Is service discovery enabled? */
private boolean enabled = true;
/** Alternate server path to invoke for health checking. */
private String healthCheckPath = "/actuator/health";
/** Custom health check url to override default. */
private String healthCheckUrl;
/** How often to perform the health check (e.g. 10s), defaults to 10s. */
private String healthCheckInterval = "10s";
/** Timeout for health check (e.g. 10s). */
private String healthCheckTimeout;
/**
* Timeout to deregister services critical for longer than timeout (e.g. 30m).
* Requires consul version 7.x or higher.
*/
private String healthCheckCriticalTimeout;
……

Eureka Server and Spring Boot Admin in one Application

I try to run Eureka Server and Spring Boot Admin Server in one Application (SBA Docu says this is possible). Eureka is working as intended but the Admin App still shows zero Applications.
Spring Boot Version 2.0.3,
Spring Boot Admin Version 2.0.1
Eureka and SBA Server
#SpringBootApplication
#EnableEurekaServer
#EnableDiscoveryClient
#EnableAdminServer
class KotlintestApplication
fun main(args: Array<String>) {
SpringApplication.run(KotlintestApplication::class.java, *args)
}
Server bootstrap.yml
spring:
application:
name: server
Server application.yml
spring:
boot:
admin:
context-path: /admin
eureka:
instance:
leaseRenewalIntervalInSeconds: 10
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:8080/eureka
Client
#EnableDiscoveryClient
#SpringBootApplication
class KotlintestApplication
fun main(args: Array<String>) {
SpringApplication.run(KotlintestApplication::class.java, *args)
}
#Configuration
class SecurityPermitAllConfig : WebSecurityConfigurerAdapter() {
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.authorizeRequests().anyRequest().permitAll()
.and().csrf().disable()
}
}
Client bootstrap.yml
spring:
application:
name: client
server:
port: 0
Client application.yml
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
eureka:
instance:
hostname: localhost
health-check-url-path: /actuator/health
status-page-url-path: /actuator/info
client:
serviceUrl:
defaultZone: http://127.0.0.1:8080/eureka/
Found the answer myself
Remove the fetchRegistry: false from the server application.yaml.
The Server has to fetch the registry to see the clients ...
Btw: You should set an instanceId if you want to run multiple instances with a random port on the same host. Otherwise SBA can't differ between the instances.
eureka:
instance:
instanceId : client-${random.uuid}

Spring Cloud : Zuul throwing "Load balancer does not have available server for client"

I am trying to get a simple microservice to register to the Eureka Server and then have Zuul proxy to the microservice. I got the microservice to register to the Eureka Server. However, whenever I bring the Zuul service up I see that it is not registering to the Eureka Server. Whenever I try to route to the microservice I get the below exception:
Load balancer does not have available server for client: microservice
I am not able to figure out where the issue is. Any help would be greatly appreciated
Below are my Spring Boot classes for each of these components.
Microservice Components
MicroserviceApplication.java
#SpringBootApplication(scanBasePackages = { "some.package.controller", "some.package.service" })
#EnableEurekaClient
#EnableJpaRepositories("some.package.repository")
#EntityScan("some.package.entity")
public class MicroserviceApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceApplication.class, args);
}
}
bootstrap.yml
server:
port: 8090
info:
component: Core Services
spring:
application:
name: microservice
application.yml
eureka:
instance:
leaseRenewalIntervalInSeconds: 1
leaseExpirationDurationInSeconds: 2
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
healthcheck:
enabled: true
lease:
duration: 5
#some other logging and jpa properties below
Eureka Server Components
EurekaServerApplication.java
#SpringBootApplication
#EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
bootstrap.yml
spring:
application:
name: discovery-server
application.yml
server:
port: 8761
info:
component: Discovery Server
eureka:
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
instance:
hostname: localhost
server:
waitTimeInMsWhenSyncEmpty: 0
API Gateway Components
ZuulGatewayApplication.java
#SpringBootApplication
#EnableZuulProxy
public class ZuulGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulGatewayApplication.class, args);
}
#Bean
public ZuulGatewayPreFilter gatewayPreFilter() {
return new ZuulGatewayPreFilter();
}
}
bootstrap.yml
spring:
application:
name: api-gateway
application.yml
server:
port: 8888
info:
component: API Gateway
eureka:
instance:
leaseRenewalIntervalInSeconds: 1
leaseExpirationDurationInSeconds: 2
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
microservice:
path: /microservice/**
serviceId: microservice
Adding #EnableEurekaClient solved this issue. The Zuul application is now discoverable in the Eureka server and is able to route requests.
I had the correct annotation on my Zuul application #EnableZuulClient but still got that error.
The problem was that I started all the applications (Eureka, Zuul and the third application) at the same time instead of doing this one by one. So they all needed time to register. After some time, the error was gone and I could reach my service through Zuul client.
Wrong spring.application.name might be the reason for this error other than
adding #EnableEurekaClient to the Zuul application class.

spring cloud side car hystrix timeout not fire

I have a simple spring cloud application with side car here is the code:
#SpringBootApplication
#EnableSidecar
public class SidecarApp {
public static void main(String[] args) {
SpringApplication.run(SidecarApp.class, args);
}
}
The side car call to another service via zuul and I am trying to configure the hystrix timeout without success! here is my configurations:
server:
port: 9085
spring:
application:
name: cue
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 100
hystrix.command.default.execution.isolation.thread.interruptOnTimeout: true
hystrix.command.default.execution.timeout.enabled: true
sidecar:
port: 8085
health-uri: http://localhost:8085/health.json
in these configurations I expect that if the call to the other service will take more than 100 miliseconds the hystrix will return immediately, but this is not happened(the service hystrix call take 10 seconds)
Am I misconfiguring something?
Note:
The call to the other service is: http://localhost:9085/cma/myinfo1 so the call arrives to the sidecar and cma is the Eureka name of the remote service and it calls the function myinfo1 in the service cma...
First, I think your yaml file is incorrect,you should use standard format.
You can disable hystrix's timeout check:
hystrix:
command:
default:
execution:
timeout:
enabled: false
Or change Zuul's Hystrix isolation strategy to THREAD:
hystrix:
command:
default:
execution:
isolation:
strategy: THREAD
thread:
timeoutInMilliseconds: 10000

Resources