68 lines
30 KiB
HTML
68 lines
30 KiB
HTML
<html><head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>22. Metrics: Spectator, Servo, and Atlas</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_netflix-rxjava-springmvc.html" title="21. RxJava with Spring MVC"><link rel="next" href="multi__spring_cloud_stream.html" title="Part IV. Spring Cloud Stream"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">22. Metrics: Spectator, Servo, and Atlas</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_netflix-rxjava-springmvc.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_stream.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="netflix-metrics" href="#netflix-metrics"></a>22. Metrics: Spectator, Servo, and Atlas</h2></div></div></div><p>When used together, Spectator/Servo and Atlas provide a near real-time operational insight platform.</p><p>Spectator and Servo are Netflix’s metrics collection libraries. Atlas is a Netflix metrics backend to manage dimensional time series data.</p><p>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.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_dimensional_vs_hierarchical_metrics" href="#_dimensional_vs_hierarchical_metrics"></a>22.1 Dimensional vs. Hierarchical Metrics</h2></div></div></div><p>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:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"counter.status.200.root"</span>: <span class="hl-number">20</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"counter.status.400.root"</span>: <span class="hl-number">3</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"counter.status.200.star-star"</span>: <span class="hl-number">5</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre><p>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 <code class="literal">counter.status.200.*</code> that would read all 20 metrics and aggregate the results. Alternatively, you could provide a <code class="literal">HandlerInterceptorAdapter</code> that intercepts and records a metric like <code class="literal">counter.status.200.all</code> 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 <code class="literal">counter.status.2*.*</code>.</p><p>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 <code class="literal">counter.status.200.root</code> becomes <code class="literal">counter.status.200.method.get.root</code>, etc. Our <code class="literal">counter.status.200.*</code> 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.</p><p>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.</p><p>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:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=200,stastic=count)"</span>: <span class="hl-number">20</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=200,stastic=max)"</span>: <span class="hl-number">0.7265630630000001</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=200,stastic=totalOfSquares)"</span>: <span class="hl-number">0.04759702862580789</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=200,stastic=totalTime)"</span>: <span class="hl-number">0.2093076914666667</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=400,stastic=count)"</span>: <span class="hl-number">1</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=400,stastic=max)"</span>: <span class="hl-number">0</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=400,stastic=totalOfSquares)"</span>: <span class="hl-number">0</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root(status=400,stastic=totalTime)"</span>: <span class="hl-number">0</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_default_metrics_collection" href="#_default_metrics_collection"></a>22.2 Default Metrics Collection</h2></div></div></div><p>Without any additional dependencies or configuration, a Spring Cloud based service will autoconfigure a Servo <code class="literal">MonitorRegistry</code> and begin collecting metrics on every Spring MVC request. By default, a Servo timer with the name <code class="literal">rest</code> will be recorded for each MVC request which is tagged with:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">HTTP method</li><li class="listitem">HTTP status (e.g. 200, 400, 500)</li><li class="listitem">URI (or "root" if the URI is empty), sanitized for Atlas</li><li class="listitem">The exception class name, if the request handler threw an exception</li><li class="listitem">The caller, if a request header with a key matching <code class="literal">netflix.metrics.rest.callerHeader</code> is set on the request. There is no default key for <code class="literal">netflix.metrics.rest.callerHeader</code>. You must add it to your application properties if you wish to collect caller information.</li></ol></div><p>Set the <code class="literal">netflix.metrics.rest.metricName</code> property to change the name of the metric from <code class="literal">rest</code> to a name you provide.</p><p>If Spring AOP is enabled and <code class="literal">org.aspectj:aspectjweaver</code> is present on your runtime classpath, Spring Cloud will also collect metrics on every client call made with <code class="literal">RestTemplate</code>. A Servo timer with the name of <code class="literal">restclient</code> will be recorded for each MVC request which is tagged with:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">HTTP method</li><li class="listitem">HTTP status (e.g. 200, 400, 500), "CLIENT_ERROR" if the response returned null, or "IO_ERROR" if an <code class="literal">IOException</code> occurred during the execution of the <code class="literal">RestTemplate</code> method</li><li class="listitem">URI, sanitized for Atlas</li><li class="listitem">Client name</li></ol></div><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>Avoid using hardcoded url parameters within <code class="literal">RestTemplate</code>. When targeting dynamic endpoints use URL variables. This will avoid potential "GC Overhead Limit Reached" issues where <code class="literal">ServoMonitorCache</code> treats each url as a unique key.</p></td></tr></table></div><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// recommended</span>
|
|
String orderid = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"1"</span>;
|
|
restTemplate.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://testeurekabrixtonclient/orders/{orderid}"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, orderid)
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// avoid</span>
|
|
restTemplate.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://testeurekabrixtonclient/orders/1"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-metrics-spectator" href="#netflix-metrics-spectator"></a>22.3 Metrics Collection: Spectator</h2></div></div></div><p>To enable Spectator metrics, include a dependency on <code class="literal">spring-boot-starter-spectator</code>:</p><pre class="programlisting"> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-spectator<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>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.</p><p>Spring Cloud Spectator integration configures an injectable <code class="literal">com.netflix.spectator.api.Registry</code> instance for you. Specifically, it configures a <code class="literal">ServoRegistry</code> 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 <code class="literal">MetricReader</code> instances and both will be shipped to the Atlas backend.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spectator_counter" href="#_spectator_counter"></a>22.3.1 Spectator Counter</h3></div></div></div><p>A counter is used to measure the rate at which some event is occurring.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// create a counter with a name and a set of tags</span>
|
|
Counter counter = registry.counter(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"counterName"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagKey1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagValue1"</span>, ...);
|
|
counter.increment(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// increment when an event occurs</span>
|
|
counter.increment(<span class="hl-number">10</span>); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// increment by a discrete amount</span></pre><p>The counter records a single time-normalized statistic.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spectator_timer" href="#_spectator_timer"></a>22.3.2 Spectator Timer</h3></div></div></div><p>A timer is used to measure how long some event is taking. Spring Cloud automatically records timers for Spring MVC requests and conditionally <code class="literal">RestTemplate</code> requests, which can later be used to create dashboards for request related metrics like latency:</p><div class="figure"><a name="d0e5502" href="#d0e5502"></a><p class="title"><b>Figure 22.1. Request Latency</b></p><div class="figure-contents"><div class="mediaobject"><img src="images/RequestLatency.png" alt="RequestLatency"></div></div></div><br class="figure-break"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// create a timer with a name and a set of tags</span>
|
|
Timer timer = registry.timer(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"timerName"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagKey1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagValue1"</span>, ...);
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// execute an operation and time it at the same time</span>
|
|
T result = timer.record(() -> fooReturnsT());
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// alternatively, if you must manually record the time</span>
|
|
Long start = System.nanoTime();
|
|
T result = fooReturnsT();
|
|
timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);</pre><p>The timer simultaneously records 4 statistics: count, max, totalOfSquares, and totalTime. The count statistic will always match the single normalized value provided by a counter if you had called <code class="literal">increment()</code> once on the counter for each time you recorded a timing, so it is rarely necessary to count and time separately for a single operation.</p><p>For <a class="link" href="https://github.com/Netflix/spectator/wiki/Timer-Usage#longtasktimer" target="_top">long running operations</a>, Spectator provides a special <code class="literal">LongTaskTimer</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spectator_gauge" href="#_spectator_gauge"></a>22.3.3 Spectator Gauge</h3></div></div></div><p>Gauges are used to determine some current value like the size of a queue or number of threads in a running state. Since gauges are sampled, they provide no information about how these values fluctuate between samples.</p><p>The normal use of a gauge involves registering the gauge once in initialization with an id, a reference to the object to be sampled, and a function to get or compute a numeric value based on the object. The reference to the object is passed in separately and the Spectator registry will keep a weak reference to the object. If the object is garbage collected, then Spectator will automatically drop the registration. See <a class="link" href="https://github.com/Netflix/spectator/wiki/Gauge-Usage#using-lambda" target="_top">the note</a> in Spectator’s documentation about potential memory leaks if this API is misused.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// the registry will automatically sample this gauge periodically</span>
|
|
registry.gauge(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"gaugeName"</span>, pool, Pool::numberOfRunningThreads);
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// manually sample a value in code at periodic intervals -- last resort!</span>
|
|
registry.gauge(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"gaugeName"</span>, Arrays.asList(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagKey1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagValue1"</span>, ...), <span class="hl-number">1000</span>);</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spectator_distribution_summaries" href="#_spectator_distribution_summaries"></a>22.3.4 Spectator Distribution Summaries</h3></div></div></div><p>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.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// the registry will automatically sample this gauge periodically</span>
|
|
DistributionSummary ds = registry.distributionSummary(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"dsName"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagKey1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagValue1"</span>, ...);
|
|
ds.record(request.sizeInBytes());</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-metrics-servo" href="#netflix-metrics-servo"></a>22.4 Metrics Collection: Servo</h2></div></div></div><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>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.</p></td></tr></table></div><p>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 <code class="literal">MonitorRegistry</code>. In spite of the above warning, Servo does have a <a class="link" href="https://github.com/Netflix/servo/wiki/Getting-Started" target="_top">wider array</a> of monitor options than Spectator has meters.</p><p>Spring Cloud integration configures an injectable <code class="literal">com.netflix.servo.MonitorRegistry</code> instance for you. Once you have created the appropriate <code class="literal">Monitor</code> type in Servo, the process of recording data is wholly similar to Spectator.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_creating_servo_monitors" href="#_creating_servo_monitors"></a>22.4.1 Creating Servo Monitors</h3></div></div></div><p>If you are using the Servo <code class="literal">MonitorRegistry</code> instance provided by Spring Cloud (specifically, an instance of <code class="literal">DefaultMonitorRegistry</code>), Servo provides convenience classes for retrieving <a class="link" href="https://github.com/Netflix/spectator/wiki/Servo-Comparison#dynamiccounter" target="_top">counters</a> and <a class="link" href="https://github.com/Netflix/spectator/wiki/Servo-Comparison#dynamictimer" target="_top">timers</a>. These convenience classes ensure that only one <code class="literal">Monitor</code> is registered for each unique combination of name and tags.</p><p>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 <code class="literal">MonitorConfig</code> instance:</p><pre class="programlisting">MonitorConfig config = MonitorConfig.builder(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"timerName"</span>).withTag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagKey1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tagValue1"</span>).build();
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// somewhere we should cache this Monitor by MonitorConfig</span>
|
|
Timer timer = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> BasicTimer(config);
|
|
monitorRegistry.register(timer);</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-metrics-atlas" href="#netflix-metrics-atlas"></a>22.5 Metrics Backend: Atlas</h2></div></div></div><p>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.</p><p>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.</p><p>Spring Cloud provides a <code class="literal">spring-cloud-starter-atlas</code> that has all the dependencies you need. Then just annotate your Spring Boot application with <code class="literal">@EnableAtlas</code> and provide a location for your running Atlas server with the <code class="literal">netflix.atlas.uri</code> property.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_global_tags" href="#_global_tags"></a>22.5.1 Global tags</h3></div></div></div><p>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.</p><p>Each bean implementing <code class="literal">AtlasTagProvider</code> will contribute to the global tag list:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
|
AtlasTagProvider atlasCommonTags(
|
|
<em><span class="hl-annotation" style="color: gray">@Value("${spring.application.name}")</span></em> String appName) {
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> () -> Collections.singletonMap(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"app"</span>, appName);
|
|
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_atlas" href="#_using_atlas"></a>22.5.2 Using Atlas</h3></div></div></div><p>To bootstrap a in-memory standalone Atlas instance:</p><pre class="programlisting">$ curl -LO https://github.com/Netflix/atlas/releases/download/v1.<span class="hl-number">4.2</span>/atlas-<span class="hl-number">1.4</span>.<span class="hl-number">2</span>-standalone.jar
|
|
$ java -jar atlas-<span class="hl-number">1.4</span>.<span class="hl-number">2</span>-standalone.jar</pre><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>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.</p></td></tr></table></div><p>Once running and you have collected a handful of metrics, verify that your setup is correct by listing tags on the Atlas server:</p><pre class="programlisting">$ curl http://ATLAS/api/v1/tags</pre><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>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: <code class="literal"><a class="link" href="http://ATLAS/api/v1/graph?q=name,rest,:eq,:avg" target="_top">http://ATLAS/api/v1/graph?q=name,rest,:eq,:avg</a></code></p></td></tr></table></div><p>The Atlas wiki contains a <a class="link" href="https://github.com/Netflix/atlas/wiki/Single-Line" target="_top">compilation of sample queries</a> for various scenarios.</p><p>Make sure to check out the <a class="link" href="https://github.com/Netflix/atlas/wiki/Alerting-Philosophy" target="_top">alerting philosophy</a> and docs on using <a class="link" href="https://github.com/Netflix/atlas/wiki/DES" target="_top">double exponential smoothing</a> to generate dynamic alert thresholds.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="retrying-failed-requests" href="#retrying-failed-requests"></a>22.6 Retrying Failed Requests</h2></div></div></div><p>Spring Cloud Netflix offers a variety of ways to make HTTP requests. You can use a load balanced
|
|
<code class="literal">RestTemplate</code>, 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
|
|
<a class="link" href="https://github.com/spring-projects/spring-retry" target="_top">Spring Retry</a> on your application’s classpath.
|
|
When Spring Retry is present load balanced <code class="literal">RestTemplates</code>, Feign, and Zuul will automatically
|
|
retry any failed requests (assuming you configuration allows it to).</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_configuration" href="#_configuration"></a>22.6.1 Configuration</h3></div></div></div><p>Anytime Ribbon is used with Spring Retry you can control the retry functionality by configuring
|
|
certain Ribbon properties. The properties you can use are
|
|
<code class="literal">client.ribbon.MaxAutoRetries</code>, <code class="literal">client.ribbon.MaxAutoRetriesNextServer</code>, and
|
|
<code class="literal">client.ribbon.OkToRetryOnAllOperations</code>. See the <a class="link" href="https://github.com/Netflix/ribbon/wiki/Getting-Started#the-properties-file-sample-clientproperties" target="_top">Ribbon documentation</a>
|
|
for a description of what there properties do.</p><p>In addition you may want to retry requests when certain status codes are returned in the
|
|
response. You can list the response codes you would like the Ribbon client to retry using the
|
|
property <code class="literal">clientName.ribbon.retryableStatusCodes</code>. For example</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">clientName</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> ribbon</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> retryableStatusCodes</span>: <span class="hl-number">404</span>,<span class="hl-number">502</span></pre><p>You can also create a bean of type <code class="literal">LoadBalancedRetryPolicy</code> and implement the <code class="literal">retryableStatusCode</code>
|
|
method to determine whether you want to retry a request given the status code.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_zuul" href="#_zuul"></a>22.6.2 Zuul</h3></div></div></div><p>You can turn off Zuul’s retry functionality by setting <code class="literal">zuul.retryable</code> to <code class="literal">false</code>. You
|
|
can also disable retry functionality on route by route basis by setting
|
|
<code class="literal">zuul.routes.routename.retryable</code> to <code class="literal">false</code>.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_netflix-rxjava-springmvc.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_stream.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">21. RxJava with Spring MVC </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part IV. Spring Cloud Stream</td></tr></table></div></body></html> |