From 7aa355aa5e13ad63eececc3da03d4330f44a001e Mon Sep 17 00:00:00 2001 From: buildmaster Date: Wed, 22 May 2019 15:48:42 +0000 Subject: [PATCH] Sync docs from 1.4.x to gh-pages --- ...ulti__circuit_breaker_hystrix_clients.html | 4 +- .../multi__polyglot_support_with_sidecar.html | 12 +- .../multi/multi__router_and_filter_zuul.html | 110 +++--- ...lti__service_discovery_eureka_clients.html | 14 +- 1.4.x/multi/multi_netflix-metrics.html | 42 +-- .../multi/multi_netflix-rxjava-springmvc.html | 30 +- .../multi_spring-cloud-eureka-server.html | 4 +- 1.4.x/multi/multi_spring-cloud-feign.html | 76 ++--- 1.4.x/multi/multi_spring-cloud-ribbon.html | 24 +- 1.4.x/single/spring-cloud-netflix.html | 316 +++++++++--------- 10 files changed, 316 insertions(+), 316 deletions(-) diff --git a/1.4.x/multi/multi__circuit_breaker_hystrix_clients.html b/1.4.x/multi/multi__circuit_breaker_hystrix_clients.html index 029e2bb90..e12d69849 100644 --- a/1.4.x/multi/multi__circuit_breaker_hystrix_clients.html +++ b/1.4.x/multi/multi__circuit_breaker_hystrix_clients.html @@ -32,11 +32,11 @@ circuit, and what to do in case of a failure.

To configure the @HystrixProperty annotations. See here for more details. See the Hystrix wiki -for details on the properties available.

3.2 Propagating the Security Context or using Spring Scopes

If you want some thread local context to propagate into a @HystrixCommand the default declaration will not work because it executes the command in a thread pool (in case of timeouts). You can switch Hystrix to use the same thread as the caller using some configuration, or directly in the annotation, by asking it to use a different "Isolation Strategy". For example:

@HystrixCommand(fallbackMethod = "stubMyService",
+for details on the properties available.

3.2 Propagating the Security Context or using Spring Scopes

If you want some thread local context to propagate into a @HystrixCommand the default declaration will not work because it executes the command in a thread pool (in case of timeouts). You can switch Hystrix to use the same thread as the caller using some configuration, or directly in the annotation, by asking it to use a different "Isolation Strategy". For example:

@HystrixCommand(fallbackMethod = "stubMyService",
     commandProperties = {
       @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")
     }
-)
+)
 ...

The same thing applies if you are using @SessionScope or @RequestScope. You will know when you need to do this because of a runtime exception that says it can’t find the scoped context.

You also have the option to set the hystrix.shareSecurityContext property to true. Doing so will auto configure an Hystrix concurrency strategy plugin hook who will transfer the SecurityContext from your main thread to the one used by the Hystrix command. Hystrix does not allow multiple hystrix concurrency strategy to be registered so an extension mechanism is available by declaring your own HystrixConcurrencyStrategy as a Spring bean. Spring Cloud will lookup for your implementation within the Spring context and wrap it inside its own plugin.

3.3 Health Indicator

The state of the connected circuit breakers are also exposed in the /health endpoint of the calling application.

{
     "hystrix": {
diff --git a/1.4.x/multi/multi__polyglot_support_with_sidecar.html b/1.4.x/multi/multi__polyglot_support_with_sidecar.html
index 88e6a0ed4..f03e7de46 100644
--- a/1.4.x/multi/multi__polyglot_support_with_sidecar.html
+++ b/1.4.x/multi/multi__polyglot_support_with_sidecar.html
@@ -21,14 +21,14 @@ indicator.  It should return a json document like the following:

health }

Here is an example application.yml for a Sidecar application:

application.yml. 

server:
-  port: 5678
+  port: 5678
 spring:
   application:
     name: sidecar
 
 sidecar:
-  port: 8000
-  health-uri: http://localhost:8000/health.json

+ port: 8000 + health-uri: http://localhost:8000/health.json

The api for the DiscoveryClient.getInstances() method is /hosts/{serviceId}. Here is an example response for /hosts/customers that returns two instances on different hosts. This api is accessible to the non-jvm app (if the sidecar is @@ -36,14 +36,14 @@ on port 5678) at [ { "host": "myhost", - "port": 9000, + "port": 9000, "uri": "http://myhost:9000", "serviceId": "CUSTOMERS", "secure": false }, { "host": "myhost2", - "port": 9000, + "port": 9000, "uri": "http://myhost2:9000", "serviceId": "CUSTOMERS", "secure": false @@ -60,7 +60,7 @@ documents. For example, a call to eureka: client: serviceUrl: - defaultZone: http://localhost:8761/eureka/ + defaultZone: http://localhost:8761/eureka/ password: password info: description: Spring Cloud Samples diff --git a/1.4.x/multi/multi__router_and_filter_zuul.html b/1.4.x/multi/multi__router_and_filter_zuul.html index a7dc48531..564f1e9ca 100644 --- a/1.4.x/multi/multi__router_and_filter_zuul.html +++ b/1.4.x/multi/multi__router_and_filter_zuul.html @@ -70,10 +70,10 @@ To achieve this, you can specify a serviceId with a ribbon: NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList listOfServers: https://example1.com,http://example2.com - ConnectTimeout: 1000 - ReadTimeout: 3000 - MaxTotalHttpConnections: 500 - MaxConnectionsPerHost: 100

+ ConnectTimeout: 1000 + ReadTimeout: 3000 + MaxTotalHttpConnections: 500 + MaxConnectionsPerHost: 100

Another method is specifiying a service-route and configure a Ribbon client for the serviceId (this requires disabling Eureka support in Ribbon: see above for more information), e.g.

application.yml.  @@ -93,7 +93,7 @@ see @Bean +

@Bean
 public PatternServiceRouteMapper serviceRouteMapper() {
     return new PatternServiceRouteMapper(
         "(?<name>^.+)-(?<version>v.+$)",
@@ -238,7 +238,7 @@ but redirect some of the requests to new ones.

Example configuration:

< url: forward:/second third: path: /third/** - url: forward:/3rd + url: forward:/3rd legacy: path: /** url: https://legacy.example.com

@@ -261,10 +261,10 @@ path is externalized via zuul.servletPath. Extremel large files will also require elevated timeout settings if the proxy route takes you through a Ribbon load balancer, e.g.

application.yml.  -

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
+

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
 ribbon:
-  ConnectTimeout: 3000
-  ReadTimeout: 60000

+ ConnectTimeout: 3000 + ReadTimeout: 60000

Note that for streaming to work with large files, you need to use chunked encoding in the request (which some browsers do not do by default). E.g. on the command line:

$ curl -v -H "Transfer-Encoding: chunked" \
     -F "file=@mylarge.iso" localhost:9999/zuul/simple/file

9.9 Query String Encoding

When processing the incoming request, query params are decoded so they can be available for possible modifications in @@ -296,40 +296,40 @@ possible filters that are enabled. If you want to disable one, simply set by creating a bean of type ZuulFallbackProvider. Within this bean you need to specify the route ID the fallback is for and provide a ClientHttpResponse to return as a fallback. Here is a very simple ZuulFallbackProvider implementation.

class MyFallbackProvider implements ZuulFallbackProvider {
-    @Override
+    @Override
     public String getRoute() {
         return "customers";
     }
 
-    @Override
+    @Override
     public ClientHttpResponse fallbackResponse() {
         return new ClientHttpResponse() {
-            @Override
+            @Override
             public HttpStatus getStatusCode() throws IOException {
                 return HttpStatus.OK;
             }
 
-            @Override
+            @Override
             public int getRawStatusCode() throws IOException {
-                return 200;
+                return 200;
             }
 
-            @Override
+            @Override
             public String getStatusText() throws IOException {
                 return "OK";
             }
 
-            @Override
+            @Override
             public void close() {
 
             }
 
-            @Override
+            @Override
             public InputStream getBody() throws IOException {
                 return new ByteArrayInputStream("fallback".getBytes());
             }
 
-            @Override
+            @Override
             public HttpHeaders getHeaders() {
                 HttpHeaders headers = new HttpHeaders();
                 headers.setContentType(MediaType.APPLICATION_JSON);
@@ -341,40 +341,40 @@ as a fallback.  Here is a very simple ZuulFallbackProvider
   routes:
     customers: /customers/**

If you would like to provide a default fallback for all routes than you can create a bean of type ZuulFallbackProvider and have the getRoute method return * or null.

class MyFallbackProvider implements ZuulFallbackProvider {
-    @Override
+    @Override
     public String getRoute() {
         return "*";
     }
 
-    @Override
+    @Override
     public ClientHttpResponse fallbackResponse() {
         return new ClientHttpResponse() {
-            @Override
+            @Override
             public HttpStatus getStatusCode() throws IOException {
                 return HttpStatus.OK;
             }
 
-            @Override
+            @Override
             public int getRawStatusCode() throws IOException {
-                return 200;
+                return 200;
             }
 
-            @Override
+            @Override
             public String getStatusText() throws IOException {
                 return "OK";
             }
 
-            @Override
+            @Override
             public void close() {
 
             }
 
-            @Override
+            @Override
             public InputStream getBody() throws IOException {
                 return new ByteArrayInputStream("fallback".getBytes());
             }
 
-            @Override
+            @Override
             public HttpHeaders getHeaders() {
                 HttpHeaders headers = new HttpHeaders();
                 headers.setContentType(MediaType.APPLICATION_JSON);
@@ -384,12 +384,12 @@ type ZuulFallbackProvider and have the 

If you would like to choose the response based on the cause of the failure use FallbackProvider which will replace ZuulFallbackProvder in future versions.

class MyFallbackProvider implements FallbackProvider {
 
-    @Override
+    @Override
     public String getRoute() {
         return "*";
     }
 
-    @Override
+    @Override
     public ClientHttpResponse fallbackResponse(final Throwable cause) {
         if (cause instanceof HystrixTimeoutException) {
             return response(HttpStatus.GATEWAY_TIMEOUT);
@@ -398,38 +398,38 @@ type ZuulFallbackProvider and have the @Override
+    @Override
     public ClientHttpResponse fallbackResponse() {
         return response(HttpStatus.INTERNAL_SERVER_ERROR);
     }
 
     private ClientHttpResponse response(final HttpStatus status) {
         return new ClientHttpResponse() {
-            @Override
+            @Override
             public HttpStatus getStatusCode() throws IOException {
                 return status;
             }
 
-            @Override
+            @Override
             public int getRawStatusCode() throws IOException {
                 return status.value();
             }
 
-            @Override
+            @Override
             public String getStatusText() throws IOException {
                 return status.getReasonPhrase();
             }
 
-            @Override
+            @Override
             public void close() {
             }
 
-            @Override
+            @Override
             public InputStream getBody() throws IOException {
                 return new ByteArrayInputStream("fallback".getBytes());
             }
 
-            @Override
+            @Override
             public HttpHeaders getHeaders() {
                 HttpHeaders headers = new HttpHeaders();
                 headers.setContentType(MediaType.APPLICATION_JSON);
@@ -458,31 +458,31 @@ into account the Ribbon connect and read timeouts as well as any retries that ma
 A LocationRewriteFilter Zuul filter can  be configured to re-write the Location header to the Zuul’s url, it also adds back the stripped global and route specific prefixes. The filter can be added the following way via a Spring Configuration file:

import org.springframework.cloud.netflix.zuul.filters.post.LocationRewriteFilter;
 ...
 
-@Configuration
-@EnableZuulProxy
+@Configuration
+@EnableZuulProxy
 public class ZuulConfig {
-    @Bean
+    @Bean
     public LocationRewriteFilter locationRewriteFilter() {
         return new LocationRewriteFilter();
     }
 }
[Warning]Warning

Use this filter with caution though, the filter acts on the Location header of ALL 3XX response codes which may not be appropriate in all scenarios, say if the user is redirecting to an external URL.

9.15 Zuul Developer Guide

For a general overview of how Zuul works, please see the Zuul Wiki.

9.15.1 The Zuul Servlet

Zuul is implemented as a Servlet. For the general cases, Zuul is embedded into the Spring Dispatch mechanism. This allows Spring MVC to be in control of the routing. In this case, Zuul is configured to buffer requests. If there is a need to go through Zuul without buffering requests (e.g. for large file uploads), the Servlet is also installed outside of the Spring Dispatcher. By default, this is located at /zuul. This path can be changed with the zuul.servlet-path property.

9.15.2 Zuul RequestContext

To pass information between filters, Zuul uses a RequestContext. Its data is held in a ThreadLocal specific to each request. Information about where to route requests, errors and the actual HttpServletRequest and HttpServletResponse are stored there. The RequestContext extends ConcurrentHashMap, so anything can be stored in the context. FilterConstants contains the keys that are used by the filters installed by Spring Cloud Netflix (more on these later).

9.15.3 @EnableZuulProxy vs. @EnableZuulServer

Spring Cloud Netflix installs a number of filters based on which annotation was used to enable Zuul. @EnableZuulProxy is a superset of @EnableZuulServer. In other words, @EnableZuulProxy contains all filters installed by @EnableZuulServer. The additional filters in the "proxy" enable routing functionality. If you want a "blank" Zuul, you should use @EnableZuulServer.

9.15.4 @EnableZuulServer Filters

Creates a SimpleRouteLocator that loads route definitions from Spring Boot configuration files.

The following filters are installed (as normal Spring Beans):

Pre filters:

  • ServletDetectionFilter: Detects if the request is through the Spring Dispatcher. Sets boolean with key FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY.
  • FormBodyWrapperFilter: Parses form data and reencodes it for downstream requests.
  • DebugFilter: if the debug request parameter is set, this filter sets RequestContext.setDebugRouting() and RequestContext.setDebugRequest() to true.

Route filters:

  • SendForwardFilter: This filter forwards requests using the Servlet RequestDispatcher. The forwarding location is stored in the RequestContext attribute FilterConstants.FORWARD_TO_KEY. This is useful for forwarding to endpoints in the current application.

Post filters:

  • SendResponseFilter: Writes responses from proxied requests to the current response.

Error filters:

  • SendErrorFilter: Forwards to /error (by default) if RequestContext.getThrowable() is not null. The default forwarding path (/error) can be changed by setting the error.path property.

9.15.5 @EnableZuulProxy Filters

Creates a DiscoveryClientRouteLocator that loads route definitions from a DiscoveryClient (like Eureka), as well as from properties. A route is created for each serviceId from the DiscoveryClient. As new services are added, the routes will be refreshed.

In addition to the filters described above, the following filters are installed (as normal Spring Beans):

Pre filters:

  • PreDecorationFilter: This filter determines where and how to route based on the supplied RouteLocator. It also sets various proxy-related headers for downstream requests.

Route filters:

  • RibbonRoutingFilter: This filter uses Ribbon, Hystrix and pluggable HTTP clients to send requests. Service ids are found in the RequestContext attribute FilterConstants.SERVICE_ID_KEY. This filter can use different HTTP clients. They are:

    • Apache HttpClient. This is the default client.
    • Squareup OkHttpClient v3. This is enabled by having the com.squareup.okhttp3:okhttp library on the classpath and setting ribbon.okhttp.enabled=true.
    • Netflix Ribbon HTTP client. This is enabled by setting ribbon.restclient.enabled=true. This client has limitations, such as it doesn’t support the PATCH method, but also has built-in retry.
  • SimpleHostRoutingFilter: This filter sends requests to predetermined URLs via an Apache HttpClient. URLs are found in RequestContext.getRouteHost().

9.15.6 Custom Zuul Filter examples

Most of the following "How to Write" examples below are included Sample Zuul Filters project. There are also examples of manipulating the request or response body in that repository.

9.15.7 How to Write a Pre Filter

Pre filters are used to set up data in the RequestContext for use in filters downstream. The main use case is to set information required for route filters.

public class QueryParamPreFilter extends ZuulFilter {
-	@Override
+	@Override
 	public int filterOrder() {
-		return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration
+		return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration
 	}
 
-	@Override
+	@Override
 	public String filterType() {
 		return PRE_TYPE;
 	}
 
-	@Override
+	@Override
 	public boolean shouldFilter() {
 		RequestContext ctx = RequestContext.getCurrentContext();
 		return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded
 				&& !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId
 	}
-    @Override
+    @Override
     public Object run() {
         RequestContext ctx = RequestContext.getCurrentContext();
 		HttpServletRequest request = ctx.getRequest();
@@ -493,26 +493,26 @@ A LocationRewriteFilter Zuul filter can  be configu
         return null;
     }
 }

The filter above populates SERVICE_ID_KEY from the foo request parameter. In reality, it’s not a good idea to do that kind of direct mapping, but the service id should be looked up from the value of foo instead.

Now that SERVICE_ID_KEY is populated, PreDecorationFilter won’t run and RibbonRoutingFilter will. If you wanted to route to a full URL instead, call ctx.setRouteHost(url) instead.

To modify the path that routing filters will forward to, set the REQUEST_URI_KEY.

9.15.8 How to Write a Route Filter

Route filters are run after pre filters and are used to make requests to other services. Much of the work here is to translate request and response data to and from the client required model.

public class OkHttpRoutingFilter extends ZuulFilter {
-	@Autowired
+	@Autowired
 	private ProxyRequestHelper helper;
 
-	@Override
+	@Override
 	public String filterType() {
 		return ROUTE_TYPE;
 	}
 
-	@Override
+	@Override
 	public int filterOrder() {
-		return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1;
+		return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1;
 	}
 
-	@Override
+	@Override
 	public boolean shouldFilter() {
 		return RequestContext.getCurrentContext().getRouteHost() != null
 				&& RequestContext.getCurrentContext().sendZuulResponse();
 	}
 
-    @Override
+    @Override
     public Object run() {
 		OkHttpClient httpClient = new OkHttpClient.Builder()
 				// customize
@@ -567,22 +567,22 @@ A LocationRewriteFilter Zuul filter can  be configu
 		return null;
     }
 }

The above filter translates Servlet request information into OkHttp3 request information, executes an HTTP request, then translates OkHttp3 reponse information to the Servlet response. WARNING: this filter might have bugs and not function correctly.

9.15.9 How to Write a Post Filter

Post filters typically manipulate the response. In the filter below, we add a random UUID as the X-Foo header. Other manipulations, such as transforming the response body, are much more complex and compute-intensive.

public class AddResponseHeaderFilter extends ZuulFilter {
-	@Override
+	@Override
 	public String filterType() {
 		return POST_TYPE;
 	}
 
-	@Override
+	@Override
 	public int filterOrder() {
-		return SEND_RESPONSE_FILTER_ORDER - 1;
+		return SEND_RESPONSE_FILTER_ORDER - 1;
 	}
 
-	@Override
+	@Override
 	public boolean shouldFilter() {
 		return true;
 	}
 
-	@Override
+	@Override
 	public Object run() {
 		RequestContext context = RequestContext.getCurrentContext();
     	HttpServletResponse servletResponse = context.getResponse();
diff --git a/1.4.x/multi/multi__service_discovery_eureka_clients.html b/1.4.x/multi/multi__service_discovery_eureka_clients.html
index b8b561838..2bcdf84fe 100644
--- a/1.4.x/multi/multi__service_discovery_eureka_clients.html
+++ b/1.4.x/multi/multi__service_discovery_eureka_clients.html
@@ -6,13 +6,13 @@ for details on setting up your build system with the current Spring Cloud Releas
 such as host and port, health indicator URL, home page etc.  Eureka
 receives heartbeat messages from each instance belonging to a service.
 If the heartbeat fails over a configurable timetable, the instance is
-normally removed from the registry.

Example eureka client:

@Configuration
-@ComponentScan
-@EnableAutoConfiguration
-@RestController
+normally removed from the registry.

Example eureka client:

@Configuration
+@ComponentScan
+@EnableAutoConfiguration
+@RestController
 public class Application {
 
-    @RequestMapping("/")
+    @RequestMapping("/")
     public String home() {
         return "Hello world";
     }
@@ -104,8 +104,8 @@ implementing your own com.netflix.appinfo.HealthCheckHandl
   instance:
     hostname: ${vcap.application.uris[0]}
     nonSecurePort: 80

-

Depending on the way the security rules are set up in your Cloud Foundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls. This feature is not (yet) available on Pivotal Web Services (PWS).

1.7.2 Using Eureka on AWS

If the application is planned to be deployed to an AWS cloud, then the Eureka instance will have to be configured to be AWS aware and this can be done by customizing the EurekaInstanceConfigBean the following way:

@Bean
-@Profile("!default")
+

Depending on the way the security rules are set up in your Cloud Foundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls. This feature is not (yet) available on Pivotal Web Services (PWS).

1.7.2 Using Eureka on AWS

If the application is planned to be deployed to an AWS cloud, then the Eureka instance will have to be configured to be AWS aware and this can be done by customizing the EurekaInstanceConfigBean the following way:

@Bean
+@Profile("!default")
 public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) {
   EurekaInstanceConfigBean b = new EurekaInstanceConfigBean(inetUtils);
   AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
diff --git a/1.4.x/multi/multi_netflix-metrics.html b/1.4.x/multi/multi_netflix-metrics.html
index 6d2ad9551..8bb57a1d6 100644
--- a/1.4.x/multi/multi_netflix-metrics.html
+++ b/1.4.x/multi/multi_netflix-metrics.html
@@ -1,18 +1,18 @@
 
       
    12. Metrics: Spectator, Servo, and Atlas

12. Metrics: Spectator, Servo, and Atlas

When used together, Spectator/Servo and Atlas provide a near real-time operational insight platform.

Spectator and Servo are Netflix’s metrics collection libraries. Atlas is a Netflix metrics backend to manage dimensional time series data.

Servo served Netflix for several years and is still usable, but is gradually being phased out in favor of Spectator, which is only designed to work with Java 8. Spring Cloud Netflix provides support for both, but Java 8 based applications are encouraged to use Spectator.

To enable Servo you must set spring.metrics.servo.enabled to true.

12.1 Dimensional vs. Hierarchical Metrics

Spring Boot Actuator metrics are hierarchical and metrics are separated only by name. These names often follow a naming convention that embeds key/value attribute pairs (dimensions) into the name separated by periods. Consider the following metrics for two endpoints, root and star-star:

{
-    "counter.status.200.root": 20,
-    "counter.status.400.root": 3,
-    "counter.status.200.star-star": 5,
+    "counter.status.200.root": 20,
+    "counter.status.400.root": 3,
+    "counter.status.200.star-star": 5,
 }

The first metric gives us a normalized count of successful requests against the root endpoint per unit of time. But what if the system had 20 endpoints and you want to get a count of successful requests against all the endpoints? Some hierarchical metrics backends would allow you to specify a wild card such as counter.status.200.* that would read all 20 metrics and aggregate the results. Alternatively, you could provide a HandlerInterceptorAdapter that intercepts and records a metric like counter.status.200.all for all successful requests irrespective of the endpoint, but now you must write 20+1 different metrics. Similarly if you want to know the total number of successful requests for all endpoints in the service, you could specify a wild card such as counter.status.2*.*.

Even in the presence of wildcarding support on a hierarchical metrics backend, naming consistency can be difficult. Specifically the position of these tags in the name string can slip with time, breaking queries. For example, suppose we add an additional dimension to the hierarchical metrics above for HTTP method. Then counter.status.200.root becomes counter.status.200.method.get.root, etc. Our counter.status.200.* suddenly no longer has the same semantic meaning. Furthermore, if the new dimension is not applied uniformly across the codebase, certain queries may become impossible. This can quickly get out of hand.

Netflix metrics are tagged (a.k.a. dimensional). Each metric has a name, but this single named metric can contain multiple statistics and 'tag' key/value pairs that allows more querying flexibility. In fact, the statistics themselves are recorded in a special tag.

Recorded with Netflix Servo or Spectator, a timer for the root endpoint described above contains 4 statistics per status code, where the count statistic is identical to Spring Boot Actuator’s counter. In the event that we have encountered an HTTP 200 and 400 thus far, there will be 8 available data points:

{
-    "root(status=200,stastic=count)": 20,
-    "root(status=200,stastic=max)": 0.7265630630000001,
-    "root(status=200,stastic=totalOfSquares)": 0.04759702862580789,
-    "root(status=200,stastic=totalTime)": 0.2093076914666667,
-    "root(status=400,stastic=count)": 1,
-    "root(status=400,stastic=max)": 0,
-    "root(status=400,stastic=totalOfSquares)": 0,
-    "root(status=400,stastic=totalTime)": 0,
+    "root(status=200,stastic=count)": 20,
+    "root(status=200,stastic=max)": 0.7265630630000001,
+    "root(status=200,stastic=totalOfSquares)": 0.04759702862580789,
+    "root(status=200,stastic=totalTime)": 0.2093076914666667,
+    "root(status=400,stastic=count)": 1,
+    "root(status=400,stastic=max)": 0,
+    "root(status=400,stastic=totalOfSquares)": 0,
+    "root(status=400,stastic=totalTime)": 0,
 }

12.2 Default Metrics Collection

Without any additional dependencies or configuration, a Spring Cloud based service will autoconfigure a Servo MonitorRegistry and begin collecting metrics on every Spring MVC request. By default, a Servo timer with the name rest will be recorded for each MVC request which is tagged with:

  1. HTTP method
  2. HTTP status (e.g. 200, 400, 500)
  3. URI (or "root" if the URI is empty), sanitized for Atlas
  4. The exception class name, if the request handler threw an exception
  5. The caller, if a request header with a key matching netflix.metrics.rest.callerHeader is set on the request. There is no default key for netflix.metrics.rest.callerHeader. You must add it to your application properties if you wish to collect caller information.

Set the netflix.metrics.rest.metricName property to change the name of the metric from rest to a name you provide.

If Spring AOP is enabled and org.aspectj:aspectjweaver is present on your runtime classpath, Spring Cloud will also collect metrics on every client call made with RestTemplate. A Servo timer with the name of restclient will be recorded for each MVC request which is tagged with:

  1. HTTP method
  2. HTTP status (e.g. 200, 400, 500), "CLIENT_ERROR" if the response returned null, or "IO_ERROR" if an IOException occurred during the execution of the RestTemplate method
  3. URI, sanitized for Atlas
  4. Client name
[Warning]Warning

Avoid using hardcoded url parameters within RestTemplate. When targeting dynamic endpoints use URL variables. This will avoid potential "GC Overhead Limit Reached" issues where ServoMonitorCache treats each url as a unique key.

// recommended
 String orderid = "1";
 restTemplate.getForObject("http://testclient/orders/{orderid}", String.class, orderid)
@@ -24,7 +24,7 @@ restTemplate.getForObject(</dependency>

In Spectator parlance, a meter is a named, typed, and tagged configuration and a metric represents the value of a given meter at a point in time. Spectator meters are created and controlled by a registry, which currently has several different implementations. Spectator provides 4 meter types: counter, timer, gauge, and distribution summary.

Spring Cloud Spectator integration configures an injectable com.netflix.spectator.api.Registry instance for you. Specifically, it configures a ServoRegistry instance in order to unify the collection of REST metrics and the exporting of metrics to the Atlas backend under a single Servo API. Practically, this means that your code may use a mixture of Servo monitors and Spectator meters and both will be scooped up by Spring Boot Actuator MetricReader instances and both will be shipped to the Atlas backend.

12.3.1 Spectator Counter

A counter is used to measure the rate at which some event is occurring.

// create a counter with a name and a set of tags
 Counter counter = registry.counter("counterName", "tagKey1", "tagValue1", ...);
 counter.increment(); // increment when an event occurs
-counter.increment(10); // increment by a discrete amount

The counter records a single time-normalized statistic.

12.3.2 Spectator Timer

A timer is used to measure how long some event is taking. Spring Cloud automatically records timers for Spring MVC requests and conditionally RestTemplate requests, which can later be used to create dashboards for request related metrics like latency:

Figure 12.1. Request Latency

RequestLatency

// create a timer with a name and a set of tags
+counter.increment(10); // increment by a discrete amount

The counter records a single time-normalized statistic.

12.3.2 Spectator Timer

A timer is used to measure how long some event is taking. Spring Cloud automatically records timers for Spring MVC requests and conditionally RestTemplate requests, which can later be used to create dashboards for request related metrics like latency:

Figure 12.1. Request Latency

RequestLatency

// create a timer with a name and a set of tags
 Timer timer = registry.timer("timerName", "tagKey1", "tagValue1", ...);
 
 // execute an operation and time it at the same time
@@ -37,18 +37,18 @@ timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);

The timer registry.gauge("gaugeName", pool, Pool::numberOfRunningThreads); // manually sample a value in code at periodic intervals -- last resort! -registry.gauge("gaugeName", Arrays.asList("tagKey1", "tagValue1", ...), 1000);

12.3.4 Spectator Distribution Summaries

A distribution summary is used to track the distribution of events. It is similar to a timer, but more general in that the size does not have to be a period of time. For example, a distribution summary could be used to measure the payload sizes of requests hitting a server.

// the registry will automatically sample this gauge periodically
+registry.gauge("gaugeName", Arrays.asList("tagKey1", "tagValue1", ...), 1000);

12.3.4 Spectator Distribution Summaries

A distribution summary is used to track the distribution of events. It is similar to a timer, but more general in that the size does not have to be a period of time. For example, a distribution summary could be used to measure the payload sizes of requests hitting a server.

// the registry will automatically sample this gauge periodically
 DistributionSummary ds = registry.distributionSummary("dsName", "tagKey1", "tagValue1", ...);
 ds.record(request.sizeInBytes());

12.4 Metrics Collection: Servo

[Warning]Warning

If your code is compiled on Java 8, please use Spectator instead of Servo as Spectator is destined to replace Servo entirely in the long term.

In Servo parlance, a monitor is a named, typed, and tagged configuration and a metric represents the value of a given monitor at a point in time. Servo monitors are logically equivalent to Spectator meters. Servo monitors are created and controlled by a MonitorRegistry. In spite of the above warning, Servo does have a wider array of monitor options than Spectator has meters.

Spring Cloud integration configures an injectable com.netflix.servo.MonitorRegistry instance for you. Once you have created the appropriate Monitor type in Servo, the process of recording data is wholly similar to Spectator.

12.4.1 Creating Servo Monitors

If you are using the Servo MonitorRegistry instance provided by Spring Cloud (specifically, an instance of DefaultMonitorRegistry), Servo provides convenience classes for retrieving counters and timers. These convenience classes ensure that only one Monitor is registered for each unique combination of name and tags.

To manually create a Monitor type in Servo, especially for the more exotic monitor types for which convenience methods are not provided, instantiate the appropriate type by providing a MonitorConfig instance:

MonitorConfig config = MonitorConfig.builder("timerName").withTag("tagKey1", "tagValue1").build();
 
 // somewhere we should cache this Monitor by MonitorConfig
 Timer timer = new BasicTimer(config);
-monitorRegistry.register(timer);

12.5 Metrics Backend: Atlas

Atlas was developed by Netflix to manage dimensional time series data for near real-time operational insight. Atlas features in-memory data storage, allowing it to gather and report very large numbers of metrics, very quickly.

Atlas captures operational intelligence. Whereas business intelligence is data gathered for analyzing trends over time, operational intelligence provides a picture of what is currently happening within a system.

Spring Cloud provides a spring-cloud-starter-netflix-atlas that has all the dependencies you need. Then just annotate your Spring Boot application with @EnableAtlas and provide a location for your running Atlas server with the netflix.atlas.uri property.

12.5.1 Global tags

Spring Cloud enables you to add tags to every metric sent to the Atlas backend. Global tags can be used to separate metrics by application name, environment, region, etc.

Each bean implementing AtlasTagProvider will contribute to the global tag list:

@Bean
+monitorRegistry.register(timer);

12.5 Metrics Backend: Atlas

Atlas was developed by Netflix to manage dimensional time series data for near real-time operational insight. Atlas features in-memory data storage, allowing it to gather and report very large numbers of metrics, very quickly.

Atlas captures operational intelligence. Whereas business intelligence is data gathered for analyzing trends over time, operational intelligence provides a picture of what is currently happening within a system.

Spring Cloud provides a spring-cloud-starter-netflix-atlas that has all the dependencies you need. Then just annotate your Spring Boot application with @EnableAtlas and provide a location for your running Atlas server with the netflix.atlas.uri property.

12.5.1 Global tags

Spring Cloud enables you to add tags to every metric sent to the Atlas backend. Global tags can be used to separate metrics by application name, environment, region, etc.

Each bean implementing AtlasTagProvider will contribute to the global tag list:

@Bean
 AtlasTagProvider atlasCommonTags(
-    @Value("${spring.application.name}") String appName) {
+    @Value("${spring.application.name}") String appName) {
   return () -> Collections.singletonMap("app", appName);
-}

12.5.2 Using Atlas

To bootstrap a in-memory standalone Atlas instance:

$ curl -LO https://github.com/Netflix/atlas/releases/download/v1.4.2/atlas-1.4.2-standalone.jar
-$ java -jar atlas-1.4.2-standalone.jar
[Tip]Tip

An Atlas standalone node running on an r3.2xlarge (61GB RAM) can handle roughly 2 million metrics per minute for a given 6 hour window.

Once running and you have collected a handful of metrics, verify that your setup is correct by listing tags on the Atlas server:

$ curl http://ATLAS/api/v1/tags
[Tip]Tip

After executing several requests against your service, you can gather some very basic information on the request latency of every request by pasting the following url in your browser: http://ATLAS/api/v1/graph?q=name,rest,:eq,:avg

The Atlas wiki contains a compilation of sample queries for various scenarios.

Make sure to check out the alerting philosophy and docs on using double exponential smoothing to generate dynamic alert thresholds.

12.6 Retrying Failed Requests

Spring Cloud Netflix offers a variety of ways to make HTTP requests. You can use a load balanced +}

12.5.2 Using Atlas

To bootstrap a in-memory standalone Atlas instance:

$ curl -LO https://github.com/Netflix/atlas/releases/download/v1.4.2/atlas-1.4.2-standalone.jar
+$ java -jar atlas-1.4.2-standalone.jar
[Tip]Tip

An Atlas standalone node running on an r3.2xlarge (61GB RAM) can handle roughly 2 million metrics per minute for a given 6 hour window.

Once running and you have collected a handful of metrics, verify that your setup is correct by listing tags on the Atlas server:

$ curl http://ATLAS/api/v1/tags
[Tip]Tip

After executing several requests against your service, you can gather some very basic information on the request latency of every request by pasting the following url in your browser: http://ATLAS/api/v1/graph?q=name,rest,:eq,:avg

The Atlas wiki contains a compilation of sample queries for various scenarios.

Make sure to check out the alerting philosophy and docs on using double exponential smoothing to generate dynamic alert thresholds.

12.6 Retrying Failed Requests

Spring Cloud Netflix offers a variety of ways to make HTTP requests. You can use a load balanced RestTemplate, Ribbon, or Feign. No matter how you choose to your HTTP requests, there is always a chance the request may fail. When a request fails you may want to have the request retried automatically. To accomplish this when using Sping Cloud Netflix you need to include @@ -56,12 +56,12 @@ automatically. To accomplish this when using Sping Cloud Netflix you need to in When Spring Retry is present load balanced RestTemplates, Feign, and Zuul will automatically retry any failed requests (assuming you configuration allows it to).

12.6.1 BackOff Policies

By default no backoff policy is used when retrying requests. If you would like to configure a backoff policy you will need to create a bean of type LoadBalancedBackOffPolicyFactory -which will be used to create a BackOffPolicy for a given service.

@Configuration
+which will be used to create a BackOffPolicy for a given service.

@Configuration
 public class MyConfiguration {
-    @Bean
+    @Bean
     LoadBalancedBackOffPolicyFactory backOffPolciyFactory() {
         return new LoadBalancedBackOffPolicyFactory() {
-            @Override
+            @Override
             public BackOffPolicy createBackOffPolicy(String service) {
                 return new ExponentialBackOffPolicy();
             }
@@ -76,7 +76,7 @@ on the server’s resources due to the buffering of the request’s body
 response.  You can list the response codes you would like the Ribbon client to retry using the
  property clientName.ribbon.retryableStatusCodes.  For example

clientName:
   ribbon:
-    retryableStatusCodes: 404,502

You can also create a bean of type LoadBalancedRetryPolicy and implement the retryableStatusCode + retryableStatusCodes: 404,502

You can also create a bean of type LoadBalancedRetryPolicy and implement the retryableStatusCode method to determine whether you want to retry a request given the status code.

12.6.3 Zuul

You can turn off Zuul’s retry functionality by setting zuul.retryable to false. You can also disable retry functionality on route by route basis by setting zuul.routes.routename.retryable to false.

\ No newline at end of file diff --git a/1.4.x/multi/multi_netflix-rxjava-springmvc.html b/1.4.x/multi/multi_netflix-rxjava-springmvc.html index 4cf40f407..18e829a4c 100644 --- a/1.4.x/multi/multi_netflix-rxjava-springmvc.html +++ b/1.4.x/multi/multi_netflix-rxjava-springmvc.html @@ -1,35 +1,35 @@ - 11. RxJava with Spring MVC

11. RxJava with Spring MVC

Spring Cloud Netflix includes RxJava.

RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences.

Spring Cloud Netflix provides support for returning rx.Single objects from Spring MVC Controllers. It also supports using rx.Observable objects for Server-sent events (SSE). This can be very convenient if your internal APIs are already built using RxJava (see Section 7.4, “Feign Hystrix Support” for examples).

Here are some examples of using rx.Single:

@RequestMapping(method = RequestMethod.GET, value = "/single")
+   11. RxJava with Spring MVC

11. RxJava with Spring MVC

Spring Cloud Netflix includes RxJava.

RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences.

Spring Cloud Netflix provides support for returning rx.Single objects from Spring MVC Controllers. It also supports using rx.Observable objects for Server-sent events (SSE). This can be very convenient if your internal APIs are already built using RxJava (see Section 7.4, “Feign Hystrix Support” for examples).

Here are some examples of using rx.Single:

@RequestMapping(method = RequestMethod.GET, value = "/single")
 public Single<String> single() {
 	return Single.just("single value");
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/singleWithResponse")
+@RequestMapping(method = RequestMethod.GET, value = "/singleWithResponse")
 public ResponseEntity<Single<String>> singleWithResponse() {
 	return new ResponseEntity<>(Single.just("single value"),
 			HttpStatus.NOT_FOUND);
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/singleCreatedWithResponse")
+@RequestMapping(method = RequestMethod.GET, value = "/singleCreatedWithResponse")
 public Single<ResponseEntity<String>> singleOuterWithResponse() {
 	return Single.just(new ResponseEntity<>("single value", HttpStatus.CREATED));
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/throw")
+@RequestMapping(method = RequestMethod.GET, value = "/throw")
 public Single<Object> error() {
 	return Single.error(new RuntimeException("Unexpected"));
-}

If you have an Observable, rather than a single, you can use .toSingle() or .toList().toSingle(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/single")
+}

If you have an Observable, rather than a single, you can use .toSingle() or .toList().toSingle(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/single")
 public Single<String> single() {
 	return Observable.just("single value").toSingle();
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/multiple")
+@RequestMapping(method = RequestMethod.GET, value = "/multiple")
 public Single<List<String>> multiple() {
 	return Observable.just("multiple", "values").toList().toSingle();
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/responseWithObservable")
+@RequestMapping(method = RequestMethod.GET, value = "/responseWithObservable")
 public ResponseEntity<Single<String>> responseWithObservable() {
 
 	Observable<String> observable = Observable.just("single value");
@@ -38,27 +38,27 @@
 	return new ResponseEntity<>(observable.toSingle(), headers, HttpStatus.CREATED);
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/timeout")
+@RequestMapping(method = RequestMethod.GET, value = "/timeout")
 public Observable<String> timeout() {
-	return Observable.timer(1, TimeUnit.MINUTES).map(new Func1<Long, String>() {
-		@Override
+	return Observable.timer(1, TimeUnit.MINUTES).map(new Func1<Long, String>() {
+		@Override
 		public String call(Long aLong) {
 			return "single value";
 		}
 	});
-}

If you have a streaming endpoint and client, SSE could be an option. To convert rx.Observable to a Spring SseEmitter use RxResponse.sse(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/sse")
+}

If you have a streaming endpoint and client, SSE could be an option. To convert rx.Observable to a Spring SseEmitter use RxResponse.sse(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/sse")
 public SseEmitter single() {
 	return RxResponse.sse(Observable.just("single value"));
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/messages")
+@RequestMapping(method = RequestMethod.GET, value = "/messages")
 public SseEmitter messages() {
 	return RxResponse.sse(Observable.just("message 1", "message 2", "message 3"));
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/events")
+@RequestMapping(method = RequestMethod.GET, value = "/events")
 public SseEmitter event() {
 	return RxResponse.sse(APPLICATION_JSON_UTF8,
-			Observable.just(new EventDto("Spring io", getDate(2016, 5, 19)),
-					new EventDto("SpringOnePlatform", getDate(2016, 8, 1))));
+			Observable.just(new EventDto("Spring io", getDate(2016, 5, 19)),
+					new EventDto("SpringOnePlatform", getDate(2016, 8, 1))));
 }
\ No newline at end of file diff --git a/1.4.x/multi/multi_spring-cloud-eureka-server.html b/1.4.x/multi/multi_spring-cloud-eureka-server.html index f143f3537..f9b91ff7e 100644 --- a/1.4.x/multi/multi_spring-cloud-eureka-server.html +++ b/1.4.x/multi/multi_spring-cloud-eureka-server.html @@ -2,8 +2,8 @@ 2. Service Discovery: Eureka Server

2. Service Discovery: Eureka Server

2.1 How to Include Eureka Server

To include Eureka Server in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-netflix-eureka-server. See the Spring Cloud Project page -for details on setting up your build system with the current Spring Cloud Release Train.

2.2 How to Run a Eureka Server

Example eureka server;

@SpringBootApplication
-@EnableEurekaServer
+for details on setting up your build system with the current Spring Cloud Release Train.

2.2 How to Run a Eureka Server

Example eureka server;

@SpringBootApplication
+@EnableEurekaServer
 public class Application {
 
     public static void main(String[] args) {
diff --git a/1.4.x/multi/multi_spring-cloud-feign.html b/1.4.x/multi/multi_spring-cloud-feign.html
index 6dc450169..836646870 100644
--- a/1.4.x/multi/multi_spring-cloud-feign.html
+++ b/1.4.x/multi/multi_spring-cloud-feign.html
@@ -2,10 +2,10 @@
       
    7. Declarative REST Client: Feign

7. Declarative REST Client: Feign

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

7.1 How to Include Feign

To include Feign in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-openfeign. See the Spring Cloud Project page -for details on setting up your build system with the current Spring Cloud Release Train.

Example spring boot app

@Configuration
-@ComponentScan
-@EnableAutoConfiguration
-@EnableFeignClients
+for details on setting up your build system with the current Spring Cloud Release Train.

Example spring boot app

@Configuration
+@ComponentScan
+@EnableAutoConfiguration
+@EnableFeignClients
 public class Application {
 
     public static void main(String[] args) {
@@ -13,13 +13,13 @@ for details on setting up your build system with the current Spring Cloud Releas
     }
 
 }

StoreClient.java.  -

@FeignClient("stores")
+

@FeignClient("stores")
 public interface StoreClient {
-    @RequestMapping(method = RequestMethod.GET, value = "/stores")
+    @RequestMapping(method = RequestMethod.GET, value = "/stores")
     List<Store> getStores();
 
-    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
-    Store update(@PathVariable("storeId") Long storeId, Store store);
+    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
+    Store update(@PathVariable("storeId") Long storeId, Store store);
 }

In the @FeignClient annotation the String value ("stores" above) is an arbitrary client name, which is used to create a Ribbon load @@ -34,21 +34,21 @@ it will resolve the service in the Eureka service registry. If you don’t want to use Eureka, you can simply configure a list of servers in your external configuration (see above for example).

7.2 Overriding Feign Defaults

A central concept in Spring Cloud’s Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the @FeignClient annotation. Spring Cloud creates a new ensemble as an -ApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of the FeignClientsConfiguration) using @FeignClient. Example:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
+ApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of the FeignClientsConfiguration) using @FeignClient. Example:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
 public interface StoreClient {
     //..
-}

In this case the client is composed from the components already in FeignClientsConfiguration together with any in FooConfiguration (where the latter will override the former).

[Note]Note

FooConfiguration does not need to be annotated with @Configuration. However, if it is, then take care to exclude it from any @ComponentScan that would otherwise include this configuration as it will become the default source for feign.Decoder, feign.Encoder, feign.Contract, etc., when specified. This can be avoided by putting it in a separate, non-overlapping package from any @ComponentScan or @SpringBootApplication, or it can be explicitly excluded in @ComponentScan.

[Note]Note

The serviceId attribute is now deprecated in favor of the name attribute.

[Warning]Warning

Previously, using the url attribute, did not require the name attribute. Using name is now required.

Placeholders are supported in the name and url attributes.

@FeignClient(name = "${feign.name}", url = "${feign.url}")
+}

In this case the client is composed from the components already in FeignClientsConfiguration together with any in FooConfiguration (where the latter will override the former).

[Note]Note

FooConfiguration does not need to be annotated with @Configuration. However, if it is, then take care to exclude it from any @ComponentScan that would otherwise include this configuration as it will become the default source for feign.Decoder, feign.Encoder, feign.Contract, etc., when specified. This can be avoided by putting it in a separate, non-overlapping package from any @ComponentScan or @SpringBootApplication, or it can be explicitly excluded in @ComponentScan.

[Note]Note

The serviceId attribute is now deprecated in favor of the name attribute.

[Warning]Warning

Previously, using the url attribute, did not require the name attribute. Using name is now required.

Placeholders are supported in the name and url attributes.

@FeignClient(name = "${feign.name}", url = "${feign.url}")
 public interface StoreClient {
     //..
 }

Spring Cloud Netflix provides the following beans by default for feign (BeanType beanName: ClassName):

  • Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)
  • Encoder feignEncoder: SpringEncoder
  • Logger feignLogger: Slf4jLogger
  • Contract feignContract: SpringMvcContract
  • Feign.Builder feignBuilder: HystrixFeign.Builder
  • Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.

The OkHttpClient and ApacheHttpClient feign clients can be used by setting feign.okhttp.enabled or feign.httpclient.enabled to true, respectively, and having them on the classpath. -You can customize the HTTP client used by providing a bean of either ClosableHttpClient when using Apache or OkHttpClient whe using OK HTTP.

Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

Creating a bean of one of those type and placing it in a @FeignClient configuration (such as FooConfiguration above) allows you to override each one of the beans described. Example:

@Configuration
+You can customize the HTTP client used by providing a bean of either ClosableHttpClient when using Apache or OkHttpClient whe using OK HTTP.

Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

Creating a bean of one of those type and placing it in a @FeignClient configuration (such as FooConfiguration above) allows you to override each one of the beans described. Example:

@Configuration
 public class FooConfiguration {
-    @Bean
+    @Bean
     public Contract feignContract() {
         return new feign.Contract.Default();
     }
 
-    @Bean
+    @Bean
     public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
         return new BasicAuthRequestInterceptor("user", "password");
     }
@@ -56,8 +56,8 @@ You can customize the HTTP client used by providing a bean of either   client:
     config:
       feignName:
-        connectTimeout: 5000
-        readTimeout: 5000
+        connectTimeout: 5000
+        readTimeout: 5000
         loggerLevel: full
         errorDecoder: com.example.SimpleErrorDecoder
         retryer: com.example.SimpleRetryer
@@ -68,8 +68,8 @@ You can customize the HTTP client used by providing a bean of either   client:
     config:
       default:
-        connectTimeout: 5000
-        readTimeout: 5000
+        connectTimeout: 5000
+        readTimeout: 5000
         loggerLevel: basic

If we create both @Configuration bean and configuration properties, configuration properties will win. It will override @Configuration values. But if you want to change the priority to @Configuration, you can change feign.client.default-to-properties to false.

[Note]Note

If you need to use ThreadLocal bound variables in your RequestInterceptor`s you will need to either set the @@ -88,14 +88,14 @@ thread isolation strategy for Hystrix to `SEMAPHORE or disable Hystrix in possible using the methods above. In this case you can create Clients using the Feign Builder API. Below is an example which creates two Feign Clients with the same interface but configures each one with -a separate request interceptor.

@Import(FeignClientsConfiguration.class)
+a separate request interceptor.

@Import(FeignClientsConfiguration.class)
 class FooController {
 
 	private FooClient fooClient;
 
 	private FooClient adminClient;
 
-    	@Autowired
+    	@Autowired
 	public FooController(
 			Decoder decoder, Encoder encoder, Client client) {
 		this.fooClient = Feign.builder().client(client)
@@ -110,62 +110,62 @@ a separate request interceptor.

class, "http://PROD-SVC");
     }
 }
[Note]Note

In the above example FeignClientsConfiguration.class is the default configuration -provided by Spring Cloud Netflix.

[Note]Note

PROD-SVC is the name of the service the Clients will be making requests to.

7.4 Feign Hystrix Support

If Hystrix is on the classpath and feign.hystrix.enabled=true, Feign will wrap all methods with a circuit breaker. Returning a com.netflix.hystrix.HystrixCommand is also available. This lets you use reactive patterns (with a call to .toObservable() or .observe() or asynchronous use (with a call to .queue()).

To disable Hystrix support on a per-client basis create a vanilla Feign.Builder with the "prototype" scope, e.g.:

@Configuration
+provided by Spring Cloud Netflix.

[Note]Note

PROD-SVC is the name of the service the Clients will be making requests to.

7.4 Feign Hystrix Support

If Hystrix is on the classpath and feign.hystrix.enabled=true, Feign will wrap all methods with a circuit breaker. Returning a com.netflix.hystrix.HystrixCommand is also available. This lets you use reactive patterns (with a call to .toObservable() or .observe() or asynchronous use (with a call to .queue()).

To disable Hystrix support on a per-client basis create a vanilla Feign.Builder with the "prototype" scope, e.g.:

@Configuration
 public class FooConfiguration {
-    	@Bean
-	@Scope("prototype")
+    	@Bean
+	@Scope("prototype")
 	public Feign.Builder feignBuilder() {
 		return Feign.builder();
 	}
 }
[Warning]Warning

Prior to the Spring Cloud Dalston release, if Hystrix was on the classpath Feign would have wrapped all methods in a circuit breaker by default. This default behavior was changed in Spring Cloud Dalston in -favor for an opt-in approach.

7.5 Feign Hystrix Fallbacks

Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)
+favor for an opt-in approach.

7.5 Feign Hystrix Fallbacks

Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)
 protected interface HystrixClient {
-    @RequestMapping(method = RequestMethod.GET, value = "/hello")
+    @RequestMapping(method = RequestMethod.GET, value = "/hello")
     Hello iFailSometimes();
 }
 
 static class HystrixClientFallback implements HystrixClient {
-    @Override
+    @Override
     public Hello iFailSometimes() {
         return new Hello("fallback");
     }
-}

If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
+}

If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
 protected interface HystrixClient {
-	@RequestMapping(method = RequestMethod.GET, value = "/hello")
+	@RequestMapping(method = RequestMethod.GET, value = "/hello")
 	Hello iFailSometimes();
 }
 
-@Component
+@Component
 static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> {
-	@Override
+	@Override
 	public HystrixClient create(Throwable cause) {
 		return new HystrixClient() {
-			@Override
+			@Override
 			public Hello iFailSometimes() {
 				return new Hello("fallback; reason was: " + cause.getMessage());
 			}
 		};
 	}
-}
[Warning]Warning

There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.

7.6 Feign and @Primary

When using Feign with Hystrix fallbacks, there are multiple beans in the ApplicationContext of the same type. This will cause @Autowired to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud Netflix marks all Feign instances as @Primary, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the primary attribute of @FeignClient to false.

@FeignClient(name = "hello", primary = false)
+}
[Warning]Warning

There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.

7.6 Feign and @Primary

When using Feign with Hystrix fallbacks, there are multiple beans in the ApplicationContext of the same type. This will cause @Autowired to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud Netflix marks all Feign instances as @Primary, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the primary attribute of @FeignClient to false.

@FeignClient(name = "hello", primary = false)
 public interface HelloClient {
 	// methods here
 }

7.7 Feign Inheritance Support

Feign supports boilerplate apis via single-inheritance interfaces. This allows grouping common operations into convenient base interfaces.

UserService.java. 

public interface UserService {
 
-    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
-    User getUser(@PathVariable("id") long id);
+    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
+    User getUser(@PathVariable("id") long id);
 }

UserResource.java.  -

@RestController
+

@RestController
 public class UserResource implements UserService {
 
 }

UserClient.java. 

package project.user;
 
-@FeignClient("users")
+@FeignClient("users")
 public interface UserClient extends UserService {
 
 }

@@ -176,11 +176,11 @@ mapping is not inherited).

feign.compression.request.enabled=true
 feign.compression.response.enabled=true

Feign request compression gives you settings similar to what you may set for your web server:

feign.compression.request.enabled=true
 feign.compression.request.mime-types=text/xml,application/xml,application/json
-feign.compression.request.min-request-size=2048

These properties allow you to be selective about the compressed media types and minimum request threshold length.

7.9 Feign logging

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml.  +feign.compression.request.min-request-size=2048

These properties allow you to be selective about the compressed media types and minimum request threshold length.

7.9 Feign logging

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml. 

logging.level.project.user.UserClient: DEBUG

-

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:

  • NONE, No logging (DEFAULT).
  • BASIC, Log only the request method and URL and the response status code and execution time.
  • HEADERS, Log the basic information along with request and response headers.
  • FULL, Log the headers, body, and metadata for both requests and responses.

For example, the following would set the Logger.Level to FULL:

@Configuration
+

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:

  • NONE, No logging (DEFAULT).
  • BASIC, Log only the request method and URL and the response status code and execution time.
  • HEADERS, Log the basic information along with request and response headers.
  • FULL, Log the headers, body, and metadata for both requests and responses.

For example, the following would set the Logger.Level to FULL:

@Configuration
 public class FooConfiguration {
-    @Bean
+    @Bean
     Logger.Level feignLoggerLevel() {
         return Logger.Level.FULL;
     }
diff --git a/1.4.x/multi/multi_spring-cloud-ribbon.html b/1.4.x/multi/multi_spring-cloud-ribbon.html
index d47ab2a66..3b8805397 100644
--- a/1.4.x/multi/multi_spring-cloud-ribbon.html
+++ b/1.4.x/multi/multi_spring-cloud-ribbon.html
@@ -18,8 +18,8 @@ configuration files. The native options can
 be inspected as static fields in CommonClientConfigKey (part of
 ribbon-core).

Spring Cloud also lets you take full control of the client by declaring additional configuration (on top of the -RibbonClientConfiguration) using @RibbonClient. Example:

@Configuration
-@RibbonClient(name = "foo", configuration = FooConfiguration.class)
+RibbonClientConfiguration) using @RibbonClient. Example:

@Configuration
+@RibbonClient(name = "foo", configuration = FooConfiguration.class)
 public class TestConfiguration {
 }

In this case the client is composed from the components already in RibbonClientConfiguration together with any in FooConfiguration @@ -32,20 +32,20 @@ separate, non-overlapping package, or specify the packages to scan explicitly in the @ComponentScan).

Spring Cloud Netflix provides the following beans by default for ribbon (BeanType beanName: ClassName):

  • IClientConfig ribbonClientConfig: DefaultClientConfigImpl
  • IRule ribbonRule: ZoneAvoidanceRule
  • IPing ribbonPing: DummyPing
  • ServerList<Server> ribbonServerList: ConfigurationBasedServerList
  • ServerListFilter<Server> ribbonServerListFilter: ZonePreferenceServerListFilter
  • ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer
  • ServerListUpdater ribbonServerListUpdater: PollingServerListUpdater

Creating a bean of one of those type and placing it in a @RibbonClient configuration (such as FooConfiguration above) allows you to override each -one of the beans described. Example:

@Configuration
+one of the beans described.  Example:

@Configuration
 protected static class FooConfiguration {
-	@Bean
+	@Bean
 	public ZonePreferenceServerListFilter serverListFilter() {
 		ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
 		filter.setZone("myTestZone");
 		return filter;
 	}
 
-	@Bean
+	@Bean
 	public IPing ribbonPing() {
 		return new PingUrl();
 	}
-}

This replaces the NoOpPing with PingUrl and provides a custom serverListFilter

6.3 Customizing default for all Ribbon Clients

A default configuration can be provided for all Ribbon Clients using the @RibbonClients annotation and registering a default configuration as shown in the following example:

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
+}

This replaces the NoOpPing with PingUrl and provides a custom serverListFilter

6.3 Customizing default for all Ribbon Clients

A default configuration can be provided for all Ribbon Clients using the @RibbonClients annotation and registering a default configuration as shown in the following example:

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
 public class RibbonClientDefaultConfigurationTestsConfig {
 
 	public static class BazServiceList extends ConfigurationBasedServerList {
@@ -55,25 +55,25 @@ one of the beans described.  Example:

@Configuration
+@Configuration
 class DefaultRibbonConfig {
 
-	@Bean
+	@Bean
 	public IRule ribbonRule() {
 		return new BestAvailableRule();
 	}
 
-	@Bean
+	@Bean
 	public IPing ribbonPing() {
 		return new PingUrl();
 	}
 
-	@Bean
+	@Bean
 	public ServerList<Server> ribbonServerList(IClientConfig config) {
 		return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
 	}
 
-	@Bean
+	@Bean
 	public ServerListSubsetFilter serverListFilter() {
 		ServerListSubsetFilter filter = new ServerListSubsetFilter();
 		return filter;
@@ -125,7 +125,7 @@ disable the use of Eureka in Ribbon.

application.yml.  eureka: enabled: false

6.8 Using the Ribbon API Directly

You can also use the LoadBalancerClient directly. Example:

public class MyClass {
-    @Autowired
+    @Autowired
     private LoadBalancerClient loadBalancer;
 
     public void doStuff() {
diff --git a/1.4.x/single/spring-cloud-netflix.html b/1.4.x/single/spring-cloud-netflix.html
index aede27861..b70b19bf3 100644
--- a/1.4.x/single/spring-cloud-netflix.html
+++ b/1.4.x/single/spring-cloud-netflix.html
@@ -11,13 +11,13 @@ for details on setting up your build system with the current Spring Cloud Releas
 such as host and port, health indicator URL, home page etc.  Eureka
 receives heartbeat messages from each instance belonging to a service.
 If the heartbeat fails over a configurable timetable, the instance is
-normally removed from the registry.

Example eureka client:

@Configuration
-@ComponentScan
-@EnableAutoConfiguration
-@RestController
+normally removed from the registry.

Example eureka client:

@Configuration
+@ComponentScan
+@EnableAutoConfiguration
+@RestController
 public class Application {
 
-    @RequestMapping("/")
+    @RequestMapping("/")
     public String home() {
         return "Hello world";
     }
@@ -109,8 +109,8 @@ implementing your own com.netflix.appinfo.HealthCheckHandl
   instance:
     hostname: ${vcap.application.uris[0]}
     nonSecurePort: 80

-

Depending on the way the security rules are set up in your Cloud Foundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls. This feature is not (yet) available on Pivotal Web Services (PWS).

1.7.2 Using Eureka on AWS

If the application is planned to be deployed to an AWS cloud, then the Eureka instance will have to be configured to be AWS aware and this can be done by customizing the EurekaInstanceConfigBean the following way:

@Bean
-@Profile("!default")
+

Depending on the way the security rules are set up in your Cloud Foundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls. This feature is not (yet) available on Pivotal Web Services (PWS).

1.7.2 Using Eureka on AWS

If the application is planned to be deployed to an AWS cloud, then the Eureka instance will have to be configured to be AWS aware and this can be done by customizing the EurekaInstanceConfigBean the following way:

@Bean
+@Profile("!default")
 public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) {
   EurekaInstanceConfigBean b = new EurekaInstanceConfigBean(inetUtils);
   AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
@@ -195,8 +195,8 @@ and zone 2 you would need to set the following Eure
 eureka.client.preferSameZoneEureka = true

Service 1 in Zone 2

eureka.instance.metadataMap.zone = zone2
 eureka.client.preferSameZoneEureka = true

2. Service Discovery: Eureka Server

2.1 How to Include Eureka Server

To include Eureka Server in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-netflix-eureka-server. See the Spring Cloud Project page -for details on setting up your build system with the current Spring Cloud Release Train.

2.2 How to Run a Eureka Server

Example eureka server;

@SpringBootApplication
-@EnableEurekaServer
+for details on setting up your build system with the current Spring Cloud Release Train.

2.2 How to Run a Eureka Server

Example eureka server;

@SpringBootApplication
+@EnableEurekaServer
 public class Application {
 
     public static void main(String[] args) {
@@ -340,11 +340,11 @@ circuit, and what to do in case of a failure.

To configure the @HystrixProperty annotations. See here for more details. See the Hystrix wiki -for details on the properties available.

3.2 Propagating the Security Context or using Spring Scopes

If you want some thread local context to propagate into a @HystrixCommand the default declaration will not work because it executes the command in a thread pool (in case of timeouts). You can switch Hystrix to use the same thread as the caller using some configuration, or directly in the annotation, by asking it to use a different "Isolation Strategy". For example:

@HystrixCommand(fallbackMethod = "stubMyService",
+for details on the properties available.

3.2 Propagating the Security Context or using Spring Scopes

If you want some thread local context to propagate into a @HystrixCommand the default declaration will not work because it executes the command in a thread pool (in case of timeouts). You can switch Hystrix to use the same thread as the caller using some configuration, or directly in the annotation, by asking it to use a different "Isolation Strategy". For example:

@HystrixCommand(fallbackMethod = "stubMyService",
     commandProperties = {
       @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")
     }
-)
+)
 ...

The same thing applies if you are using @SessionScope or @RequestScope. You will know when you need to do this because of a runtime exception that says it can’t find the scoped context.

You also have the option to set the hystrix.shareSecurityContext property to true. Doing so will auto configure an Hystrix concurrency strategy plugin hook who will transfer the SecurityContext from your main thread to the one used by the Hystrix command. Hystrix does not allow multiple hystrix concurrency strategy to be registered so an extension mechanism is available by declaring your own HystrixConcurrencyStrategy as a Spring bean. Spring Cloud will lookup for your implementation within the Spring context and wrap it inside its own plugin.

3.3 Health Indicator

The state of the connected circuit breakers are also exposed in the /health endpoint of the calling application.

{
     "hystrix": {
@@ -403,8 +403,8 @@ configuration files. The native options can
 be inspected as static fields in CommonClientConfigKey (part of
 ribbon-core).

Spring Cloud also lets you take full control of the client by declaring additional configuration (on top of the -RibbonClientConfiguration) using @RibbonClient. Example:

@Configuration
-@RibbonClient(name = "foo", configuration = FooConfiguration.class)
+RibbonClientConfiguration) using @RibbonClient. Example:

@Configuration
+@RibbonClient(name = "foo", configuration = FooConfiguration.class)
 public class TestConfiguration {
 }

In this case the client is composed from the components already in RibbonClientConfiguration together with any in FooConfiguration @@ -417,20 +417,20 @@ separate, non-overlapping package, or specify the packages to scan explicitly in the @ComponentScan).

Spring Cloud Netflix provides the following beans by default for ribbon (BeanType beanName: ClassName):

  • IClientConfig ribbonClientConfig: DefaultClientConfigImpl
  • IRule ribbonRule: ZoneAvoidanceRule
  • IPing ribbonPing: DummyPing
  • ServerList<Server> ribbonServerList: ConfigurationBasedServerList
  • ServerListFilter<Server> ribbonServerListFilter: ZonePreferenceServerListFilter
  • ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer
  • ServerListUpdater ribbonServerListUpdater: PollingServerListUpdater

Creating a bean of one of those type and placing it in a @RibbonClient configuration (such as FooConfiguration above) allows you to override each -one of the beans described. Example:

@Configuration
+one of the beans described.  Example:

@Configuration
 protected static class FooConfiguration {
-	@Bean
+	@Bean
 	public ZonePreferenceServerListFilter serverListFilter() {
 		ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
 		filter.setZone("myTestZone");
 		return filter;
 	}
 
-	@Bean
+	@Bean
 	public IPing ribbonPing() {
 		return new PingUrl();
 	}
-}

This replaces the NoOpPing with PingUrl and provides a custom serverListFilter

6.3 Customizing default for all Ribbon Clients

A default configuration can be provided for all Ribbon Clients using the @RibbonClients annotation and registering a default configuration as shown in the following example:

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
+}

This replaces the NoOpPing with PingUrl and provides a custom serverListFilter

6.3 Customizing default for all Ribbon Clients

A default configuration can be provided for all Ribbon Clients using the @RibbonClients annotation and registering a default configuration as shown in the following example:

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
 public class RibbonClientDefaultConfigurationTestsConfig {
 
 	public static class BazServiceList extends ConfigurationBasedServerList {
@@ -440,25 +440,25 @@ one of the beans described.  Example:

@Configuration
+@Configuration
 class DefaultRibbonConfig {
 
-	@Bean
+	@Bean
 	public IRule ribbonRule() {
 		return new BestAvailableRule();
 	}
 
-	@Bean
+	@Bean
 	public IPing ribbonPing() {
 		return new PingUrl();
 	}
 
-	@Bean
+	@Bean
 	public ServerList<Server> ribbonServerList(IClientConfig config) {
 		return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
 	}
 
-	@Bean
+	@Bean
 	public ServerListSubsetFilter serverListFilter() {
 		ServerListSubsetFilter filter = new ServerListSubsetFilter();
 		return filter;
@@ -510,7 +510,7 @@ disable the use of Eureka in Ribbon.

application.yml.  eureka: enabled: false

6.8 Using the Ribbon API Directly

You can also use the LoadBalancerClient directly. Example:

public class MyClass {
-    @Autowired
+    @Autowired
     private LoadBalancerClient loadBalancer;
 
     public void doStuff() {
@@ -547,10 +547,10 @@ via RequestContext in pre filter, so it can be used
 If you don’t put any value with LOAD_BALANCER_KEY in RequestContext, null will be passed as a parameter of choose
 method.

7. Declarative REST Client: Feign

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

7.1 How to Include Feign

To include Feign in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-openfeign. See the Spring Cloud Project page -for details on setting up your build system with the current Spring Cloud Release Train.

Example spring boot app

@Configuration
-@ComponentScan
-@EnableAutoConfiguration
-@EnableFeignClients
+for details on setting up your build system with the current Spring Cloud Release Train.

Example spring boot app

@Configuration
+@ComponentScan
+@EnableAutoConfiguration
+@EnableFeignClients
 public class Application {
 
     public static void main(String[] args) {
@@ -558,13 +558,13 @@ for details on setting up your build system with the current Spring Cloud Releas
     }
 
 }

StoreClient.java.  -

@FeignClient("stores")
+

@FeignClient("stores")
 public interface StoreClient {
-    @RequestMapping(method = RequestMethod.GET, value = "/stores")
+    @RequestMapping(method = RequestMethod.GET, value = "/stores")
     List<Store> getStores();
 
-    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
-    Store update(@PathVariable("storeId") Long storeId, Store store);
+    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
+    Store update(@PathVariable("storeId") Long storeId, Store store);
 }

In the @FeignClient annotation the String value ("stores" above) is an arbitrary client name, which is used to create a Ribbon load @@ -579,21 +579,21 @@ it will resolve the service in the Eureka service registry. If you don’t want to use Eureka, you can simply configure a list of servers in your external configuration (see above for example).

7.2 Overriding Feign Defaults

A central concept in Spring Cloud’s Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the @FeignClient annotation. Spring Cloud creates a new ensemble as an -ApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of the FeignClientsConfiguration) using @FeignClient. Example:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
+ApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of the FeignClientsConfiguration) using @FeignClient. Example:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
 public interface StoreClient {
     //..
-}

In this case the client is composed from the components already in FeignClientsConfiguration together with any in FooConfiguration (where the latter will override the former).

[Note]Note

FooConfiguration does not need to be annotated with @Configuration. However, if it is, then take care to exclude it from any @ComponentScan that would otherwise include this configuration as it will become the default source for feign.Decoder, feign.Encoder, feign.Contract, etc., when specified. This can be avoided by putting it in a separate, non-overlapping package from any @ComponentScan or @SpringBootApplication, or it can be explicitly excluded in @ComponentScan.

[Note]Note

The serviceId attribute is now deprecated in favor of the name attribute.

[Warning]Warning

Previously, using the url attribute, did not require the name attribute. Using name is now required.

Placeholders are supported in the name and url attributes.

@FeignClient(name = "${feign.name}", url = "${feign.url}")
+}

In this case the client is composed from the components already in FeignClientsConfiguration together with any in FooConfiguration (where the latter will override the former).

[Note]Note

FooConfiguration does not need to be annotated with @Configuration. However, if it is, then take care to exclude it from any @ComponentScan that would otherwise include this configuration as it will become the default source for feign.Decoder, feign.Encoder, feign.Contract, etc., when specified. This can be avoided by putting it in a separate, non-overlapping package from any @ComponentScan or @SpringBootApplication, or it can be explicitly excluded in @ComponentScan.

[Note]Note

The serviceId attribute is now deprecated in favor of the name attribute.

[Warning]Warning

Previously, using the url attribute, did not require the name attribute. Using name is now required.

Placeholders are supported in the name and url attributes.

@FeignClient(name = "${feign.name}", url = "${feign.url}")
 public interface StoreClient {
     //..
 }

Spring Cloud Netflix provides the following beans by default for feign (BeanType beanName: ClassName):

  • Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)
  • Encoder feignEncoder: SpringEncoder
  • Logger feignLogger: Slf4jLogger
  • Contract feignContract: SpringMvcContract
  • Feign.Builder feignBuilder: HystrixFeign.Builder
  • Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.

The OkHttpClient and ApacheHttpClient feign clients can be used by setting feign.okhttp.enabled or feign.httpclient.enabled to true, respectively, and having them on the classpath. -You can customize the HTTP client used by providing a bean of either ClosableHttpClient when using Apache or OkHttpClient whe using OK HTTP.

Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

Creating a bean of one of those type and placing it in a @FeignClient configuration (such as FooConfiguration above) allows you to override each one of the beans described. Example:

@Configuration
+You can customize the HTTP client used by providing a bean of either ClosableHttpClient when using Apache or OkHttpClient whe using OK HTTP.

Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

Creating a bean of one of those type and placing it in a @FeignClient configuration (such as FooConfiguration above) allows you to override each one of the beans described. Example:

@Configuration
 public class FooConfiguration {
-    @Bean
+    @Bean
     public Contract feignContract() {
         return new feign.Contract.Default();
     }
 
-    @Bean
+    @Bean
     public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
         return new BasicAuthRequestInterceptor("user", "password");
     }
@@ -601,8 +601,8 @@ You can customize the HTTP client used by providing a bean of either   client:
     config:
       feignName:
-        connectTimeout: 5000
-        readTimeout: 5000
+        connectTimeout: 5000
+        readTimeout: 5000
         loggerLevel: full
         errorDecoder: com.example.SimpleErrorDecoder
         retryer: com.example.SimpleRetryer
@@ -613,8 +613,8 @@ You can customize the HTTP client used by providing a bean of either   client:
     config:
       default:
-        connectTimeout: 5000
-        readTimeout: 5000
+        connectTimeout: 5000
+        readTimeout: 5000
         loggerLevel: basic

If we create both @Configuration bean and configuration properties, configuration properties will win. It will override @Configuration values. But if you want to change the priority to @Configuration, you can change feign.client.default-to-properties to false.

[Note]Note

If you need to use ThreadLocal bound variables in your RequestInterceptor`s you will need to either set the @@ -633,14 +633,14 @@ thread isolation strategy for Hystrix to `SEMAPHORE or disable Hystrix in possible using the methods above. In this case you can create Clients using the Feign Builder API. Below is an example which creates two Feign Clients with the same interface but configures each one with -a separate request interceptor.

@Import(FeignClientsConfiguration.class)
+a separate request interceptor.

@Import(FeignClientsConfiguration.class)
 class FooController {
 
 	private FooClient fooClient;
 
 	private FooClient adminClient;
 
-    	@Autowired
+    	@Autowired
 	public FooController(
 			Decoder decoder, Encoder encoder, Client client) {
 		this.fooClient = Feign.builder().client(client)
@@ -655,62 +655,62 @@ a separate request interceptor.

class, "http://PROD-SVC");
     }
 }
[Note]Note

In the above example FeignClientsConfiguration.class is the default configuration -provided by Spring Cloud Netflix.

[Note]Note

PROD-SVC is the name of the service the Clients will be making requests to.

7.4 Feign Hystrix Support

If Hystrix is on the classpath and feign.hystrix.enabled=true, Feign will wrap all methods with a circuit breaker. Returning a com.netflix.hystrix.HystrixCommand is also available. This lets you use reactive patterns (with a call to .toObservable() or .observe() or asynchronous use (with a call to .queue()).

To disable Hystrix support on a per-client basis create a vanilla Feign.Builder with the "prototype" scope, e.g.:

@Configuration
+provided by Spring Cloud Netflix.

[Note]Note

PROD-SVC is the name of the service the Clients will be making requests to.

7.4 Feign Hystrix Support

If Hystrix is on the classpath and feign.hystrix.enabled=true, Feign will wrap all methods with a circuit breaker. Returning a com.netflix.hystrix.HystrixCommand is also available. This lets you use reactive patterns (with a call to .toObservable() or .observe() or asynchronous use (with a call to .queue()).

To disable Hystrix support on a per-client basis create a vanilla Feign.Builder with the "prototype" scope, e.g.:

@Configuration
 public class FooConfiguration {
-    	@Bean
-	@Scope("prototype")
+    	@Bean
+	@Scope("prototype")
 	public Feign.Builder feignBuilder() {
 		return Feign.builder();
 	}
 }
[Warning]Warning

Prior to the Spring Cloud Dalston release, if Hystrix was on the classpath Feign would have wrapped all methods in a circuit breaker by default. This default behavior was changed in Spring Cloud Dalston in -favor for an opt-in approach.

7.5 Feign Hystrix Fallbacks

Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)
+favor for an opt-in approach.

7.5 Feign Hystrix Fallbacks

Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)
 protected interface HystrixClient {
-    @RequestMapping(method = RequestMethod.GET, value = "/hello")
+    @RequestMapping(method = RequestMethod.GET, value = "/hello")
     Hello iFailSometimes();
 }
 
 static class HystrixClientFallback implements HystrixClient {
-    @Override
+    @Override
     public Hello iFailSometimes() {
         return new Hello("fallback");
     }
-}

If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
+}

If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
 protected interface HystrixClient {
-	@RequestMapping(method = RequestMethod.GET, value = "/hello")
+	@RequestMapping(method = RequestMethod.GET, value = "/hello")
 	Hello iFailSometimes();
 }
 
-@Component
+@Component
 static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> {
-	@Override
+	@Override
 	public HystrixClient create(Throwable cause) {
 		return new HystrixClient() {
-			@Override
+			@Override
 			public Hello iFailSometimes() {
 				return new Hello("fallback; reason was: " + cause.getMessage());
 			}
 		};
 	}
-}
[Warning]Warning

There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.

7.6 Feign and @Primary

When using Feign with Hystrix fallbacks, there are multiple beans in the ApplicationContext of the same type. This will cause @Autowired to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud Netflix marks all Feign instances as @Primary, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the primary attribute of @FeignClient to false.

@FeignClient(name = "hello", primary = false)
+}
[Warning]Warning

There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.

7.6 Feign and @Primary

When using Feign with Hystrix fallbacks, there are multiple beans in the ApplicationContext of the same type. This will cause @Autowired to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud Netflix marks all Feign instances as @Primary, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the primary attribute of @FeignClient to false.

@FeignClient(name = "hello", primary = false)
 public interface HelloClient {
 	// methods here
 }

7.7 Feign Inheritance Support

Feign supports boilerplate apis via single-inheritance interfaces. This allows grouping common operations into convenient base interfaces.

UserService.java. 

public interface UserService {
 
-    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
-    User getUser(@PathVariable("id") long id);
+    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
+    User getUser(@PathVariable("id") long id);
 }

UserResource.java.  -

@RestController
+

@RestController
 public class UserResource implements UserService {
 
 }

UserClient.java. 

package project.user;
 
-@FeignClient("users")
+@FeignClient("users")
 public interface UserClient extends UserService {
 
 }

@@ -721,11 +721,11 @@ mapping is not inherited).

feign.compression.request.enabled=true
 feign.compression.response.enabled=true

Feign request compression gives you settings similar to what you may set for your web server:

feign.compression.request.enabled=true
 feign.compression.request.mime-types=text/xml,application/xml,application/json
-feign.compression.request.min-request-size=2048

These properties allow you to be selective about the compressed media types and minimum request threshold length.

7.9 Feign logging

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml.  +feign.compression.request.min-request-size=2048

These properties allow you to be selective about the compressed media types and minimum request threshold length.

7.9 Feign logging

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml. 

logging.level.project.user.UserClient: DEBUG

-

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:

  • NONE, No logging (DEFAULT).
  • BASIC, Log only the request method and URL and the response status code and execution time.
  • HEADERS, Log the basic information along with request and response headers.
  • FULL, Log the headers, body, and metadata for both requests and responses.

For example, the following would set the Logger.Level to FULL:

@Configuration
+

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:

  • NONE, No logging (DEFAULT).
  • BASIC, Log only the request method and URL and the response status code and execution time.
  • HEADERS, Log the basic information along with request and response headers.
  • FULL, Log the headers, body, and metadata for both requests and responses.

For example, the following would set the Logger.Level to FULL:

@Configuration
 public class FooConfiguration {
-    @Bean
+    @Bean
     Logger.Level feignLoggerLevel() {
         return Logger.Level.FULL;
     }
@@ -809,10 +809,10 @@ To achieve this, you can specify a serviceId with a
   ribbon:
     NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
     listOfServers: https://example1.com,http://example2.com
-    ConnectTimeout: 1000
-    ReadTimeout: 3000
-    MaxTotalHttpConnections: 500
-    MaxConnectionsPerHost: 100

+ ConnectTimeout: 1000 + ReadTimeout: 3000 + MaxTotalHttpConnections: 500 + MaxConnectionsPerHost: 100

Another method is specifiying a service-route and configure a Ribbon client for the serviceId (this requires disabling Eureka support in Ribbon: see above for more information), e.g.

application.yml.  @@ -832,7 +832,7 @@ see @Bean +

@Bean
 public PatternServiceRouteMapper serviceRouteMapper() {
     return new PatternServiceRouteMapper(
         "(?<name>^.+)-(?<version>v.+$)",
@@ -977,7 +977,7 @@ but redirect some of the requests to new ones.

Example configuration:

< url: forward:/second third: path: /third/** - url: forward:/3rd + url: forward:/3rd legacy: path: /** url: https://legacy.example.com

@@ -1000,10 +1000,10 @@ path is externalized via zuul.servletPath. Extremel large files will also require elevated timeout settings if the proxy route takes you through a Ribbon load balancer, e.g.

application.yml.  -

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
+

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
 ribbon:
-  ConnectTimeout: 3000
-  ReadTimeout: 60000

+ ConnectTimeout: 3000 + ReadTimeout: 60000

Note that for streaming to work with large files, you need to use chunked encoding in the request (which some browsers do not do by default). E.g. on the command line:

$ curl -v -H "Transfer-Encoding: chunked" \
     -F "file=@mylarge.iso" localhost:9999/zuul/simple/file

9.9 Query String Encoding

When processing the incoming request, query params are decoded so they can be available for possible modifications in @@ -1035,40 +1035,40 @@ possible filters that are enabled. If you want to disable one, simply set by creating a bean of type ZuulFallbackProvider. Within this bean you need to specify the route ID the fallback is for and provide a ClientHttpResponse to return as a fallback. Here is a very simple ZuulFallbackProvider implementation.

class MyFallbackProvider implements ZuulFallbackProvider {
-    @Override
+    @Override
     public String getRoute() {
         return "customers";
     }
 
-    @Override
+    @Override
     public ClientHttpResponse fallbackResponse() {
         return new ClientHttpResponse() {
-            @Override
+            @Override
             public HttpStatus getStatusCode() throws IOException {
                 return HttpStatus.OK;
             }
 
-            @Override
+            @Override
             public int getRawStatusCode() throws IOException {
-                return 200;
+                return 200;
             }
 
-            @Override
+            @Override
             public String getStatusText() throws IOException {
                 return "OK";
             }
 
-            @Override
+            @Override
             public void close() {
 
             }
 
-            @Override
+            @Override
             public InputStream getBody() throws IOException {
                 return new ByteArrayInputStream("fallback".getBytes());
             }
 
-            @Override
+            @Override
             public HttpHeaders getHeaders() {
                 HttpHeaders headers = new HttpHeaders();
                 headers.setContentType(MediaType.APPLICATION_JSON);
@@ -1080,40 +1080,40 @@ as a fallback.  Here is a very simple ZuulFallbackProvider
   routes:
     customers: /customers/**

If you would like to provide a default fallback for all routes than you can create a bean of type ZuulFallbackProvider and have the getRoute method return * or null.

class MyFallbackProvider implements ZuulFallbackProvider {
-    @Override
+    @Override
     public String getRoute() {
         return "*";
     }
 
-    @Override
+    @Override
     public ClientHttpResponse fallbackResponse() {
         return new ClientHttpResponse() {
-            @Override
+            @Override
             public HttpStatus getStatusCode() throws IOException {
                 return HttpStatus.OK;
             }
 
-            @Override
+            @Override
             public int getRawStatusCode() throws IOException {
-                return 200;
+                return 200;
             }
 
-            @Override
+            @Override
             public String getStatusText() throws IOException {
                 return "OK";
             }
 
-            @Override
+            @Override
             public void close() {
 
             }
 
-            @Override
+            @Override
             public InputStream getBody() throws IOException {
                 return new ByteArrayInputStream("fallback".getBytes());
             }
 
-            @Override
+            @Override
             public HttpHeaders getHeaders() {
                 HttpHeaders headers = new HttpHeaders();
                 headers.setContentType(MediaType.APPLICATION_JSON);
@@ -1123,12 +1123,12 @@ type ZuulFallbackProvider and have the 

If you would like to choose the response based on the cause of the failure use FallbackProvider which will replace ZuulFallbackProvder in future versions.

class MyFallbackProvider implements FallbackProvider {
 
-    @Override
+    @Override
     public String getRoute() {
         return "*";
     }
 
-    @Override
+    @Override
     public ClientHttpResponse fallbackResponse(final Throwable cause) {
         if (cause instanceof HystrixTimeoutException) {
             return response(HttpStatus.GATEWAY_TIMEOUT);
@@ -1137,38 +1137,38 @@ type ZuulFallbackProvider and have the @Override
+    @Override
     public ClientHttpResponse fallbackResponse() {
         return response(HttpStatus.INTERNAL_SERVER_ERROR);
     }
 
     private ClientHttpResponse response(final HttpStatus status) {
         return new ClientHttpResponse() {
-            @Override
+            @Override
             public HttpStatus getStatusCode() throws IOException {
                 return status;
             }
 
-            @Override
+            @Override
             public int getRawStatusCode() throws IOException {
                 return status.value();
             }
 
-            @Override
+            @Override
             public String getStatusText() throws IOException {
                 return status.getReasonPhrase();
             }
 
-            @Override
+            @Override
             public void close() {
             }
 
-            @Override
+            @Override
             public InputStream getBody() throws IOException {
                 return new ByteArrayInputStream("fallback".getBytes());
             }
 
-            @Override
+            @Override
             public HttpHeaders getHeaders() {
                 HttpHeaders headers = new HttpHeaders();
                 headers.setContentType(MediaType.APPLICATION_JSON);
@@ -1197,31 +1197,31 @@ into account the Ribbon connect and read timeouts as well as any retries that ma
 A LocationRewriteFilter Zuul filter can  be configured to re-write the Location header to the Zuul’s url, it also adds back the stripped global and route specific prefixes. The filter can be added the following way via a Spring Configuration file:

import org.springframework.cloud.netflix.zuul.filters.post.LocationRewriteFilter;
 ...
 
-@Configuration
-@EnableZuulProxy
+@Configuration
+@EnableZuulProxy
 public class ZuulConfig {
-    @Bean
+    @Bean
     public LocationRewriteFilter locationRewriteFilter() {
         return new LocationRewriteFilter();
     }
 }
[Warning]Warning

Use this filter with caution though, the filter acts on the Location header of ALL 3XX response codes which may not be appropriate in all scenarios, say if the user is redirecting to an external URL.

9.15 Zuul Developer Guide

For a general overview of how Zuul works, please see the Zuul Wiki.

9.15.1 The Zuul Servlet

Zuul is implemented as a Servlet. For the general cases, Zuul is embedded into the Spring Dispatch mechanism. This allows Spring MVC to be in control of the routing. In this case, Zuul is configured to buffer requests. If there is a need to go through Zuul without buffering requests (e.g. for large file uploads), the Servlet is also installed outside of the Spring Dispatcher. By default, this is located at /zuul. This path can be changed with the zuul.servlet-path property.

9.15.2 Zuul RequestContext

To pass information between filters, Zuul uses a RequestContext. Its data is held in a ThreadLocal specific to each request. Information about where to route requests, errors and the actual HttpServletRequest and HttpServletResponse are stored there. The RequestContext extends ConcurrentHashMap, so anything can be stored in the context. FilterConstants contains the keys that are used by the filters installed by Spring Cloud Netflix (more on these later).

9.15.3 @EnableZuulProxy vs. @EnableZuulServer

Spring Cloud Netflix installs a number of filters based on which annotation was used to enable Zuul. @EnableZuulProxy is a superset of @EnableZuulServer. In other words, @EnableZuulProxy contains all filters installed by @EnableZuulServer. The additional filters in the "proxy" enable routing functionality. If you want a "blank" Zuul, you should use @EnableZuulServer.

9.15.4 @EnableZuulServer Filters

Creates a SimpleRouteLocator that loads route definitions from Spring Boot configuration files.

The following filters are installed (as normal Spring Beans):

Pre filters:

  • ServletDetectionFilter: Detects if the request is through the Spring Dispatcher. Sets boolean with key FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY.
  • FormBodyWrapperFilter: Parses form data and reencodes it for downstream requests.
  • DebugFilter: if the debug request parameter is set, this filter sets RequestContext.setDebugRouting() and RequestContext.setDebugRequest() to true.

Route filters:

  • SendForwardFilter: This filter forwards requests using the Servlet RequestDispatcher. The forwarding location is stored in the RequestContext attribute FilterConstants.FORWARD_TO_KEY. This is useful for forwarding to endpoints in the current application.

Post filters:

  • SendResponseFilter: Writes responses from proxied requests to the current response.

Error filters:

  • SendErrorFilter: Forwards to /error (by default) if RequestContext.getThrowable() is not null. The default forwarding path (/error) can be changed by setting the error.path property.

9.15.5 @EnableZuulProxy Filters

Creates a DiscoveryClientRouteLocator that loads route definitions from a DiscoveryClient (like Eureka), as well as from properties. A route is created for each serviceId from the DiscoveryClient. As new services are added, the routes will be refreshed.

In addition to the filters described above, the following filters are installed (as normal Spring Beans):

Pre filters:

  • PreDecorationFilter: This filter determines where and how to route based on the supplied RouteLocator. It also sets various proxy-related headers for downstream requests.

Route filters:

  • RibbonRoutingFilter: This filter uses Ribbon, Hystrix and pluggable HTTP clients to send requests. Service ids are found in the RequestContext attribute FilterConstants.SERVICE_ID_KEY. This filter can use different HTTP clients. They are:

    • Apache HttpClient. This is the default client.
    • Squareup OkHttpClient v3. This is enabled by having the com.squareup.okhttp3:okhttp library on the classpath and setting ribbon.okhttp.enabled=true.
    • Netflix Ribbon HTTP client. This is enabled by setting ribbon.restclient.enabled=true. This client has limitations, such as it doesn’t support the PATCH method, but also has built-in retry.
  • SimpleHostRoutingFilter: This filter sends requests to predetermined URLs via an Apache HttpClient. URLs are found in RequestContext.getRouteHost().

9.15.6 Custom Zuul Filter examples

Most of the following "How to Write" examples below are included Sample Zuul Filters project. There are also examples of manipulating the request or response body in that repository.

9.15.7 How to Write a Pre Filter

Pre filters are used to set up data in the RequestContext for use in filters downstream. The main use case is to set information required for route filters.

public class QueryParamPreFilter extends ZuulFilter {
-	@Override
+	@Override
 	public int filterOrder() {
-		return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration
+		return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration
 	}
 
-	@Override
+	@Override
 	public String filterType() {
 		return PRE_TYPE;
 	}
 
-	@Override
+	@Override
 	public boolean shouldFilter() {
 		RequestContext ctx = RequestContext.getCurrentContext();
 		return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded
 				&& !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId
 	}
-    @Override
+    @Override
     public Object run() {
         RequestContext ctx = RequestContext.getCurrentContext();
 		HttpServletRequest request = ctx.getRequest();
@@ -1232,26 +1232,26 @@ A LocationRewriteFilter Zuul filter can  be configu
         return null;
     }
 }

The filter above populates SERVICE_ID_KEY from the foo request parameter. In reality, it’s not a good idea to do that kind of direct mapping, but the service id should be looked up from the value of foo instead.

Now that SERVICE_ID_KEY is populated, PreDecorationFilter won’t run and RibbonRoutingFilter will. If you wanted to route to a full URL instead, call ctx.setRouteHost(url) instead.

To modify the path that routing filters will forward to, set the REQUEST_URI_KEY.

9.15.8 How to Write a Route Filter

Route filters are run after pre filters and are used to make requests to other services. Much of the work here is to translate request and response data to and from the client required model.

public class OkHttpRoutingFilter extends ZuulFilter {
-	@Autowired
+	@Autowired
 	private ProxyRequestHelper helper;
 
-	@Override
+	@Override
 	public String filterType() {
 		return ROUTE_TYPE;
 	}
 
-	@Override
+	@Override
 	public int filterOrder() {
-		return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1;
+		return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1;
 	}
 
-	@Override
+	@Override
 	public boolean shouldFilter() {
 		return RequestContext.getCurrentContext().getRouteHost() != null
 				&& RequestContext.getCurrentContext().sendZuulResponse();
 	}
 
-    @Override
+    @Override
     public Object run() {
 		OkHttpClient httpClient = new OkHttpClient.Builder()
 				// customize
@@ -1306,22 +1306,22 @@ A LocationRewriteFilter Zuul filter can  be configu
 		return null;
     }
 }

The above filter translates Servlet request information into OkHttp3 request information, executes an HTTP request, then translates OkHttp3 reponse information to the Servlet response. WARNING: this filter might have bugs and not function correctly.

9.15.9 How to Write a Post Filter

Post filters typically manipulate the response. In the filter below, we add a random UUID as the X-Foo header. Other manipulations, such as transforming the response body, are much more complex and compute-intensive.

public class AddResponseHeaderFilter extends ZuulFilter {
-	@Override
+	@Override
 	public String filterType() {
 		return POST_TYPE;
 	}
 
-	@Override
+	@Override
 	public int filterOrder() {
-		return SEND_RESPONSE_FILTER_ORDER - 1;
+		return SEND_RESPONSE_FILTER_ORDER - 1;
 	}
 
-	@Override
+	@Override
 	public boolean shouldFilter() {
 		return true;
 	}
 
-	@Override
+	@Override
 	public Object run() {
 		RequestContext context = RequestContext.getCurrentContext();
     	HttpServletResponse servletResponse = context.getResponse();
@@ -1355,14 +1355,14 @@ indicator.  It should return a json document like the following:

health }

Here is an example application.yml for a Sidecar application:

application.yml. 

server:
-  port: 5678
+  port: 5678
 spring:
   application:
     name: sidecar
 
 sidecar:
-  port: 8000
-  health-uri: http://localhost:8000/health.json

+ port: 8000 + health-uri: http://localhost:8000/health.json

The api for the DiscoveryClient.getInstances() method is /hosts/{serviceId}. Here is an example response for /hosts/customers that returns two instances on different hosts. This api is accessible to the non-jvm app (if the sidecar is @@ -1370,14 +1370,14 @@ on port 5678) at [ { "host": "myhost", - "port": 9000, + "port": 9000, "uri": "http://myhost:9000", "serviceId": "CUSTOMERS", "secure": false }, { "host": "myhost2", - "port": 9000, + "port": 9000, "uri": "http://myhost2:9000", "serviceId": "CUSTOMERS", "secure": false @@ -1394,40 +1394,40 @@ documents. For example, a call to eureka: client: serviceUrl: - defaultZone: http://localhost:8761/eureka/ + defaultZone: http://localhost:8761/eureka/ password: password info: description: Spring Cloud Samples - url: https://github.com/spring-cloud-samples

11. RxJava with Spring MVC

Spring Cloud Netflix includes RxJava.

RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences.

Spring Cloud Netflix provides support for returning rx.Single objects from Spring MVC Controllers. It also supports using rx.Observable objects for Server-sent events (SSE). This can be very convenient if your internal APIs are already built using RxJava (see Section 7.4, “Feign Hystrix Support” for examples).

Here are some examples of using rx.Single:

@RequestMapping(method = RequestMethod.GET, value = "/single")
+  url: https://github.com/spring-cloud-samples

11. RxJava with Spring MVC

Spring Cloud Netflix includes RxJava.

RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences.

Spring Cloud Netflix provides support for returning rx.Single objects from Spring MVC Controllers. It also supports using rx.Observable objects for Server-sent events (SSE). This can be very convenient if your internal APIs are already built using RxJava (see Section 7.4, “Feign Hystrix Support” for examples).

Here are some examples of using rx.Single:

@RequestMapping(method = RequestMethod.GET, value = "/single")
 public Single<String> single() {
 	return Single.just("single value");
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/singleWithResponse")
+@RequestMapping(method = RequestMethod.GET, value = "/singleWithResponse")
 public ResponseEntity<Single<String>> singleWithResponse() {
 	return new ResponseEntity<>(Single.just("single value"),
 			HttpStatus.NOT_FOUND);
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/singleCreatedWithResponse")
+@RequestMapping(method = RequestMethod.GET, value = "/singleCreatedWithResponse")
 public Single<ResponseEntity<String>> singleOuterWithResponse() {
 	return Single.just(new ResponseEntity<>("single value", HttpStatus.CREATED));
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/throw")
+@RequestMapping(method = RequestMethod.GET, value = "/throw")
 public Single<Object> error() {
 	return Single.error(new RuntimeException("Unexpected"));
-}

If you have an Observable, rather than a single, you can use .toSingle() or .toList().toSingle(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/single")
+}

If you have an Observable, rather than a single, you can use .toSingle() or .toList().toSingle(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/single")
 public Single<String> single() {
 	return Observable.just("single value").toSingle();
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/multiple")
+@RequestMapping(method = RequestMethod.GET, value = "/multiple")
 public Single<List<String>> multiple() {
 	return Observable.just("multiple", "values").toList().toSingle();
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/responseWithObservable")
+@RequestMapping(method = RequestMethod.GET, value = "/responseWithObservable")
 public ResponseEntity<Single<String>> responseWithObservable() {
 
 	Observable<String> observable = Observable.just("single value");
@@ -1436,42 +1436,42 @@ might result in a YAML document like the following

return new ResponseEntity<>(observable.toSingle(), headers, HttpStatus.CREATED);
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/timeout")
+@RequestMapping(method = RequestMethod.GET, value = "/timeout")
 public Observable<String> timeout() {
-	return Observable.timer(1, TimeUnit.MINUTES).map(new Func1<Long, String>() {
-		@Override
+	return Observable.timer(1, TimeUnit.MINUTES).map(new Func1<Long, String>() {
+		@Override
 		public String call(Long aLong) {
 			return "single value";
 		}
 	});
-}

If you have a streaming endpoint and client, SSE could be an option. To convert rx.Observable to a Spring SseEmitter use RxResponse.sse(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/sse")
+}

If you have a streaming endpoint and client, SSE could be an option. To convert rx.Observable to a Spring SseEmitter use RxResponse.sse(). Here are some examples:

@RequestMapping(method = RequestMethod.GET, value = "/sse")
 public SseEmitter single() {
 	return RxResponse.sse(Observable.just("single value"));
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/messages")
+@RequestMapping(method = RequestMethod.GET, value = "/messages")
 public SseEmitter messages() {
 	return RxResponse.sse(Observable.just("message 1", "message 2", "message 3"));
 }
 
-@RequestMapping(method = RequestMethod.GET, value = "/events")
+@RequestMapping(method = RequestMethod.GET, value = "/events")
 public SseEmitter event() {
 	return RxResponse.sse(APPLICATION_JSON_UTF8,
-			Observable.just(new EventDto("Spring io", getDate(2016, 5, 19)),
-					new EventDto("SpringOnePlatform", getDate(2016, 8, 1))));
+			Observable.just(new EventDto("Spring io", getDate(2016, 5, 19)),
+					new EventDto("SpringOnePlatform", getDate(2016, 8, 1))));
 }

12. Metrics: Spectator, Servo, and Atlas

When used together, Spectator/Servo and Atlas provide a near real-time operational insight platform.

Spectator and Servo are Netflix’s metrics collection libraries. Atlas is a Netflix metrics backend to manage dimensional time series data.

Servo served Netflix for several years and is still usable, but is gradually being phased out in favor of Spectator, which is only designed to work with Java 8. Spring Cloud Netflix provides support for both, but Java 8 based applications are encouraged to use Spectator.

To enable Servo you must set spring.metrics.servo.enabled to true.

12.1 Dimensional vs. Hierarchical Metrics

Spring Boot Actuator metrics are hierarchical and metrics are separated only by name. These names often follow a naming convention that embeds key/value attribute pairs (dimensions) into the name separated by periods. Consider the following metrics for two endpoints, root and star-star:

{
-    "counter.status.200.root": 20,
-    "counter.status.400.root": 3,
-    "counter.status.200.star-star": 5,
+    "counter.status.200.root": 20,
+    "counter.status.400.root": 3,
+    "counter.status.200.star-star": 5,
 }

The first metric gives us a normalized count of successful requests against the root endpoint per unit of time. But what if the system had 20 endpoints and you want to get a count of successful requests against all the endpoints? Some hierarchical metrics backends would allow you to specify a wild card such as counter.status.200.* that would read all 20 metrics and aggregate the results. Alternatively, you could provide a HandlerInterceptorAdapter that intercepts and records a metric like counter.status.200.all for all successful requests irrespective of the endpoint, but now you must write 20+1 different metrics. Similarly if you want to know the total number of successful requests for all endpoints in the service, you could specify a wild card such as counter.status.2*.*.

Even in the presence of wildcarding support on a hierarchical metrics backend, naming consistency can be difficult. Specifically the position of these tags in the name string can slip with time, breaking queries. For example, suppose we add an additional dimension to the hierarchical metrics above for HTTP method. Then counter.status.200.root becomes counter.status.200.method.get.root, etc. Our counter.status.200.* suddenly no longer has the same semantic meaning. Furthermore, if the new dimension is not applied uniformly across the codebase, certain queries may become impossible. This can quickly get out of hand.

Netflix metrics are tagged (a.k.a. dimensional). Each metric has a name, but this single named metric can contain multiple statistics and 'tag' key/value pairs that allows more querying flexibility. In fact, the statistics themselves are recorded in a special tag.

Recorded with Netflix Servo or Spectator, a timer for the root endpoint described above contains 4 statistics per status code, where the count statistic is identical to Spring Boot Actuator’s counter. In the event that we have encountered an HTTP 200 and 400 thus far, there will be 8 available data points:

{
-    "root(status=200,stastic=count)": 20,
-    "root(status=200,stastic=max)": 0.7265630630000001,
-    "root(status=200,stastic=totalOfSquares)": 0.04759702862580789,
-    "root(status=200,stastic=totalTime)": 0.2093076914666667,
-    "root(status=400,stastic=count)": 1,
-    "root(status=400,stastic=max)": 0,
-    "root(status=400,stastic=totalOfSquares)": 0,
-    "root(status=400,stastic=totalTime)": 0,
+    "root(status=200,stastic=count)": 20,
+    "root(status=200,stastic=max)": 0.7265630630000001,
+    "root(status=200,stastic=totalOfSquares)": 0.04759702862580789,
+    "root(status=200,stastic=totalTime)": 0.2093076914666667,
+    "root(status=400,stastic=count)": 1,
+    "root(status=400,stastic=max)": 0,
+    "root(status=400,stastic=totalOfSquares)": 0,
+    "root(status=400,stastic=totalTime)": 0,
 }

12.2 Default Metrics Collection

Without any additional dependencies or configuration, a Spring Cloud based service will autoconfigure a Servo MonitorRegistry and begin collecting metrics on every Spring MVC request. By default, a Servo timer with the name rest will be recorded for each MVC request which is tagged with:

  1. HTTP method
  2. HTTP status (e.g. 200, 400, 500)
  3. URI (or "root" if the URI is empty), sanitized for Atlas
  4. The exception class name, if the request handler threw an exception
  5. The caller, if a request header with a key matching netflix.metrics.rest.callerHeader is set on the request. There is no default key for netflix.metrics.rest.callerHeader. You must add it to your application properties if you wish to collect caller information.

Set the netflix.metrics.rest.metricName property to change the name of the metric from rest to a name you provide.

If Spring AOP is enabled and org.aspectj:aspectjweaver is present on your runtime classpath, Spring Cloud will also collect metrics on every client call made with RestTemplate. A Servo timer with the name of restclient will be recorded for each MVC request which is tagged with:

  1. HTTP method
  2. HTTP status (e.g. 200, 400, 500), "CLIENT_ERROR" if the response returned null, or "IO_ERROR" if an IOException occurred during the execution of the RestTemplate method
  3. URI, sanitized for Atlas
  4. Client name
[Warning]Warning

Avoid using hardcoded url parameters within RestTemplate. When targeting dynamic endpoints use URL variables. This will avoid potential "GC Overhead Limit Reached" issues where ServoMonitorCache treats each url as a unique key.

// recommended
 String orderid = "1";
 restTemplate.getForObject("http://testclient/orders/{orderid}", String.class, orderid)
@@ -1483,7 +1483,7 @@ restTemplate.getForObject(</dependency>

In Spectator parlance, a meter is a named, typed, and tagged configuration and a metric represents the value of a given meter at a point in time. Spectator meters are created and controlled by a registry, which currently has several different implementations. Spectator provides 4 meter types: counter, timer, gauge, and distribution summary.

Spring Cloud Spectator integration configures an injectable com.netflix.spectator.api.Registry instance for you. Specifically, it configures a ServoRegistry instance in order to unify the collection of REST metrics and the exporting of metrics to the Atlas backend under a single Servo API. Practically, this means that your code may use a mixture of Servo monitors and Spectator meters and both will be scooped up by Spring Boot Actuator MetricReader instances and both will be shipped to the Atlas backend.

12.3.1 Spectator Counter

A counter is used to measure the rate at which some event is occurring.

// create a counter with a name and a set of tags
 Counter counter = registry.counter("counterName", "tagKey1", "tagValue1", ...);
 counter.increment(); // increment when an event occurs
-counter.increment(10); // increment by a discrete amount

The counter records a single time-normalized statistic.

12.3.2 Spectator Timer

A timer is used to measure how long some event is taking. Spring Cloud automatically records timers for Spring MVC requests and conditionally RestTemplate requests, which can later be used to create dashboards for request related metrics like latency:

Figure 12.1. Request Latency

RequestLatency

// create a timer with a name and a set of tags
+counter.increment(10); // increment by a discrete amount

The counter records a single time-normalized statistic.

12.3.2 Spectator Timer

A timer is used to measure how long some event is taking. Spring Cloud automatically records timers for Spring MVC requests and conditionally RestTemplate requests, which can later be used to create dashboards for request related metrics like latency:

Figure 12.1. Request Latency

RequestLatency

// create a timer with a name and a set of tags
 Timer timer = registry.timer("timerName", "tagKey1", "tagValue1", ...);
 
 // execute an operation and time it at the same time
@@ -1496,18 +1496,18 @@ timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);

The timer registry.gauge("gaugeName", pool, Pool::numberOfRunningThreads); // manually sample a value in code at periodic intervals -- last resort! -registry.gauge("gaugeName", Arrays.asList("tagKey1", "tagValue1", ...), 1000);

12.3.4 Spectator Distribution Summaries

A distribution summary is used to track the distribution of events. It is similar to a timer, but more general in that the size does not have to be a period of time. For example, a distribution summary could be used to measure the payload sizes of requests hitting a server.

// the registry will automatically sample this gauge periodically
+registry.gauge("gaugeName", Arrays.asList("tagKey1", "tagValue1", ...), 1000);

12.3.4 Spectator Distribution Summaries

A distribution summary is used to track the distribution of events. It is similar to a timer, but more general in that the size does not have to be a period of time. For example, a distribution summary could be used to measure the payload sizes of requests hitting a server.

// the registry will automatically sample this gauge periodically
 DistributionSummary ds = registry.distributionSummary("dsName", "tagKey1", "tagValue1", ...);
 ds.record(request.sizeInBytes());

12.4 Metrics Collection: Servo

[Warning]Warning

If your code is compiled on Java 8, please use Spectator instead of Servo as Spectator is destined to replace Servo entirely in the long term.

In Servo parlance, a monitor is a named, typed, and tagged configuration and a metric represents the value of a given monitor at a point in time. Servo monitors are logically equivalent to Spectator meters. Servo monitors are created and controlled by a MonitorRegistry. In spite of the above warning, Servo does have a wider array of monitor options than Spectator has meters.

Spring Cloud integration configures an injectable com.netflix.servo.MonitorRegistry instance for you. Once you have created the appropriate Monitor type in Servo, the process of recording data is wholly similar to Spectator.

12.4.1 Creating Servo Monitors

If you are using the Servo MonitorRegistry instance provided by Spring Cloud (specifically, an instance of DefaultMonitorRegistry), Servo provides convenience classes for retrieving counters and timers. These convenience classes ensure that only one Monitor is registered for each unique combination of name and tags.

To manually create a Monitor type in Servo, especially for the more exotic monitor types for which convenience methods are not provided, instantiate the appropriate type by providing a MonitorConfig instance:

MonitorConfig config = MonitorConfig.builder("timerName").withTag("tagKey1", "tagValue1").build();
 
 // somewhere we should cache this Monitor by MonitorConfig
 Timer timer = new BasicTimer(config);
-monitorRegistry.register(timer);

12.5 Metrics Backend: Atlas

Atlas was developed by Netflix to manage dimensional time series data for near real-time operational insight. Atlas features in-memory data storage, allowing it to gather and report very large numbers of metrics, very quickly.

Atlas captures operational intelligence. Whereas business intelligence is data gathered for analyzing trends over time, operational intelligence provides a picture of what is currently happening within a system.

Spring Cloud provides a spring-cloud-starter-netflix-atlas that has all the dependencies you need. Then just annotate your Spring Boot application with @EnableAtlas and provide a location for your running Atlas server with the netflix.atlas.uri property.

12.5.1 Global tags

Spring Cloud enables you to add tags to every metric sent to the Atlas backend. Global tags can be used to separate metrics by application name, environment, region, etc.

Each bean implementing AtlasTagProvider will contribute to the global tag list:

@Bean
+monitorRegistry.register(timer);

12.5 Metrics Backend: Atlas

Atlas was developed by Netflix to manage dimensional time series data for near real-time operational insight. Atlas features in-memory data storage, allowing it to gather and report very large numbers of metrics, very quickly.

Atlas captures operational intelligence. Whereas business intelligence is data gathered for analyzing trends over time, operational intelligence provides a picture of what is currently happening within a system.

Spring Cloud provides a spring-cloud-starter-netflix-atlas that has all the dependencies you need. Then just annotate your Spring Boot application with @EnableAtlas and provide a location for your running Atlas server with the netflix.atlas.uri property.

12.5.1 Global tags

Spring Cloud enables you to add tags to every metric sent to the Atlas backend. Global tags can be used to separate metrics by application name, environment, region, etc.

Each bean implementing AtlasTagProvider will contribute to the global tag list:

@Bean
 AtlasTagProvider atlasCommonTags(
-    @Value("${spring.application.name}") String appName) {
+    @Value("${spring.application.name}") String appName) {
   return () -> Collections.singletonMap("app", appName);
-}

12.5.2 Using Atlas

To bootstrap a in-memory standalone Atlas instance:

$ curl -LO https://github.com/Netflix/atlas/releases/download/v1.4.2/atlas-1.4.2-standalone.jar
-$ java -jar atlas-1.4.2-standalone.jar
[Tip]Tip

An Atlas standalone node running on an r3.2xlarge (61GB RAM) can handle roughly 2 million metrics per minute for a given 6 hour window.

Once running and you have collected a handful of metrics, verify that your setup is correct by listing tags on the Atlas server:

$ curl http://ATLAS/api/v1/tags
[Tip]Tip

After executing several requests against your service, you can gather some very basic information on the request latency of every request by pasting the following url in your browser: http://ATLAS/api/v1/graph?q=name,rest,:eq,:avg

The Atlas wiki contains a compilation of sample queries for various scenarios.

Make sure to check out the alerting philosophy and docs on using double exponential smoothing to generate dynamic alert thresholds.

12.6 Retrying Failed Requests

Spring Cloud Netflix offers a variety of ways to make HTTP requests. You can use a load balanced +}

12.5.2 Using Atlas

To bootstrap a in-memory standalone Atlas instance:

$ curl -LO https://github.com/Netflix/atlas/releases/download/v1.4.2/atlas-1.4.2-standalone.jar
+$ java -jar atlas-1.4.2-standalone.jar
[Tip]Tip

An Atlas standalone node running on an r3.2xlarge (61GB RAM) can handle roughly 2 million metrics per minute for a given 6 hour window.

Once running and you have collected a handful of metrics, verify that your setup is correct by listing tags on the Atlas server:

$ curl http://ATLAS/api/v1/tags
[Tip]Tip

After executing several requests against your service, you can gather some very basic information on the request latency of every request by pasting the following url in your browser: http://ATLAS/api/v1/graph?q=name,rest,:eq,:avg

The Atlas wiki contains a compilation of sample queries for various scenarios.

Make sure to check out the alerting philosophy and docs on using double exponential smoothing to generate dynamic alert thresholds.

12.6 Retrying Failed Requests

Spring Cloud Netflix offers a variety of ways to make HTTP requests. You can use a load balanced RestTemplate, Ribbon, or Feign. No matter how you choose to your HTTP requests, there is always a chance the request may fail. When a request fails you may want to have the request retried automatically. To accomplish this when using Sping Cloud Netflix you need to include @@ -1515,12 +1515,12 @@ automatically. To accomplish this when using Sping Cloud Netflix you need to in When Spring Retry is present load balanced RestTemplates, Feign, and Zuul will automatically retry any failed requests (assuming you configuration allows it to).

12.6.1 BackOff Policies

By default no backoff policy is used when retrying requests. If you would like to configure a backoff policy you will need to create a bean of type LoadBalancedBackOffPolicyFactory -which will be used to create a BackOffPolicy for a given service.

@Configuration
+which will be used to create a BackOffPolicy for a given service.

@Configuration
 public class MyConfiguration {
-    @Bean
+    @Bean
     LoadBalancedBackOffPolicyFactory backOffPolciyFactory() {
         return new LoadBalancedBackOffPolicyFactory() {
-            @Override
+            @Override
             public BackOffPolicy createBackOffPolicy(String service) {
                 return new ExponentialBackOffPolicy();
             }
@@ -1535,7 +1535,7 @@ on the server’s resources due to the buffering of the request’s body
 response.  You can list the response codes you would like the Ribbon client to retry using the
  property clientName.ribbon.retryableStatusCodes.  For example

clientName:
   ribbon:
-    retryableStatusCodes: 404,502

You can also create a bean of type LoadBalancedRetryPolicy and implement the retryableStatusCode + retryableStatusCodes: 404,502

You can also create a bean of type LoadBalancedRetryPolicy and implement the retryableStatusCode method to determine whether you want to retry a request given the status code.

12.6.3 Zuul

You can turn off Zuul’s retry functionality by setting zuul.retryable to false. You can also disable retry functionality on route by route basis by setting zuul.routes.routename.retryable to false.

13. HTTP Clients

Spring Cloud Netflix will automatically create the HTTP client used by Ribbon, Feign, and