The gateway application is generated in a similar fashion to the monolithic application, except for configurations related to Zuul proxy, Eureka Client, and Hystrix:
@ComponentScan
@EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class, MetricsDropwizardAutoConfiguration.class})
@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class})
@EnableDiscoveryClient
@EnableZuulProxy
public class GatewayApp {
...
}
We have selected the JHipster registry for our registry service. This will be a standalone registry server which other microservice applications and gateways will register itself:
- @EnableDiscoveryClient is added to Spring Boot's main class, which will enable the Netflix Discovery Client. The microservice applications and gateways need to register themselves to the registry service. It uses Spring Cloud's discovery client abstraction to interrogate its own host and port, and then adds them to the registry server.
- Zuul, on the other hand, is the gatekeeper. This helps route the authorized requests to the respective endpoints, limits the requests per route, and relays the necessary tokens to the microservice application.
- @EnableZuulProxy helps the microservice gateway application route the requests to the applicable microservice application based on the configurations provided in the application.yml:
zuul: # those values must be configured depending on the application specific needs
host:
max-total-connections: 1000
max-per-route-connections: 100
semaphore:
max-semaphores: 500
In the gateway app, we have specified the aforementioned settings for Zuul configuration. The maximum number of total connections that a proxy can hold open is kept at 1000. The maximum number of route connections that a proxy can hold open is kept at 100. Semaphore is kept to a maximum of 500. (Semaphore is like a counter that is used for synchronization between threads and processes.)
Access to the backend microservice endpoint is controlled by AccessControlFilter, which will check whether the request is authorized, and is allowed to request the endpoint:
public class AccessControlFilter extends ZuulFilter {
...
public boolean shouldFilter() {
...
return !isAuthorizedRequests(serviceUrl, serviceName,
requestUri);
}
...
}
Zuul, as a gatekeeper, also acts as a rate limiter. A rate-limiting filter is added to the generated application, which limits the number of HTTP calls that are made per client. This is enabled conditionally with:
@ConditionalOnProperty("jhipster.gateway.rate-limiting.enabled")
public static class RateLimitingConfiguration {
...
}
SwaggerBasePathRewritingFilter is also used, which will help to rewrite the microservice Swagger URL base path:
@Component
public class SwaggerBasePathRewritingFilter extends SendResponseFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
if(!context.getResponseGzipped()) {
context.getResponse().setCharacterEncoding("UTF-8");
}
// rewrite the base path and send down the response
}
...
A TokenRelayFilter is added to remove the authorization from Zuul's ignore list. This will help to propagate the generated authorization token:
@Component
public class TokenRelayFilter extends ZuulFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
Set<String> headers = (Set<String>) ctx.get("ignoredHeaders");
// JWT tokens should be relayed to the resource servers
headers.remove("authorization");
return null;
}
...
Each application should have a Eureka client that helps load balance the requests among the services, as well as sending health information to the Eureka Server or registries. The Eureka client is configured in application-dev.yml as follows:
eureka:
client:
enabled: true
healthcheck:
enabled: true
fetch-registry: true
register-with-eureka: true
instance-info-replication-interval-seconds: 10
registry-fetch-interval-seconds: 10
instance:
appname: gateway
instanceId: gateway:${spring.application.instance-id:${random.value}}
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
status-page-url-path: ${management.context-path}/info
health-check-url-path: ${management.context-path}/health
metadata-map:
zone: primary # This is needed for the load balancer
profile: ${spring.profiles.active}
version: ${info.project.version}
We have chosen to enable health checks and have the interval to register and replicate be within 10 seconds, as well as instances where we define the lease renewal interval and expiration duration.
We will configure timeout in Hystrix, beyond which the server is considered to be closed:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
If the server does not respond within 10 seconds, then the server is considered dead and is registered in the registry service. This makes sure no subsequent requests are sent to that server until the server is made active.