Record load balancer stats in RibbonHttpRequest.
fixes gh-731
This commit is contained in:
@@ -67,7 +67,7 @@ public class RibbonAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(LoadBalancerClient.class)
|
||||
public LoadBalancerClient loadBalancerClient() {
|
||||
public RibbonLoadBalancerClient loadBalancerClient() {
|
||||
return new RibbonLoadBalancerClient(springClientFactory());
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class RibbonAutoConfiguration {
|
||||
private SpringClientFactory springClientFactory;
|
||||
|
||||
@Autowired
|
||||
private LoadBalancerClient loadBalancerClient;
|
||||
private RibbonLoadBalancerClient loadBalancerClient;
|
||||
|
||||
@Bean
|
||||
public RestTemplateCustomizer restTemplateCustomizer() {
|
||||
|
||||
@@ -19,8 +19,7 @@ package org.springframework.cloud.netflix.ribbon;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.RibbonServer;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
@@ -36,9 +35,9 @@ public class RibbonClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||
|
||||
private final SpringClientFactory clientFactory;
|
||||
|
||||
private LoadBalancerClient loadBalancer;
|
||||
private RibbonLoadBalancerClient loadBalancer;
|
||||
|
||||
public RibbonClientHttpRequestFactory(SpringClientFactory clientFactory, LoadBalancerClient loadBalancer) {
|
||||
public RibbonClientHttpRequestFactory(SpringClientFactory clientFactory, RibbonLoadBalancerClient loadBalancer) {
|
||||
this.clientFactory = clientFactory;
|
||||
this.loadBalancer = loadBalancer;
|
||||
}
|
||||
@@ -51,17 +50,19 @@ public class RibbonClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||
if (serviceId == null) {
|
||||
throw new IOException("Invalid hostname in the URI [" + originalUri.toASCIIString() + "]");
|
||||
}
|
||||
ServiceInstance instance = loadBalancer.choose(serviceId);
|
||||
RibbonServer instance = loadBalancer.chooseRibbonServer(serviceId);
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("No instances available for "+serviceId);
|
||||
}
|
||||
URI uri = loadBalancer.reconstructURI(instance, originalUri);
|
||||
URI uri = this.loadBalancer.reconstructURI(instance, originalUri);
|
||||
//@formatter:off
|
||||
IClientConfig clientConfig = clientFactory.getClientConfig(instance.getServiceId());
|
||||
RestClient client = clientFactory.getClient(instance.getServiceId(), RestClient.class);
|
||||
IClientConfig clientConfig = this.clientFactory.getClientConfig(instance.getServiceId());
|
||||
RestClient client = this.clientFactory.getClient(instance.getServiceId(), RestClient.class);
|
||||
HttpRequest.Verb verb = HttpRequest.Verb.valueOf(httpMethod.name());
|
||||
RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
|
||||
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, instance.getServer());
|
||||
//@formatter:on
|
||||
return new RibbonHttpRequest(uri, verb, client, clientConfig);
|
||||
return new RibbonHttpRequest(uri, verb, client, clientConfig, statsRecorder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class RibbonHttpRequest extends AbstractClientHttpRequest {
|
||||
|
||||
private HttpRequest.Builder builder;
|
||||
@@ -41,14 +42,16 @@ public class RibbonHttpRequest extends AbstractClientHttpRequest {
|
||||
private HttpRequest.Verb verb;
|
||||
private RestClient client;
|
||||
private IClientConfig config;
|
||||
private RibbonStatsRecorder statsRecorder;
|
||||
private ByteArrayOutputStream outputStream = null;
|
||||
|
||||
public RibbonHttpRequest(URI uri, HttpRequest.Verb verb, RestClient client,
|
||||
IClientConfig config) {
|
||||
IClientConfig config, RibbonStatsRecorder statsRecorder) {
|
||||
this.uri = uri;
|
||||
this.verb = verb;
|
||||
this.client = client;
|
||||
this.config = config;
|
||||
this.statsRecorder = statsRecorder;
|
||||
this.builder = HttpRequest.newBuilder().uri(uri).verb(verb);
|
||||
}
|
||||
|
||||
@@ -71,7 +74,6 @@ public class RibbonHttpRequest extends AbstractClientHttpRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected ClientHttpResponse executeInternal(HttpHeaders headers)
|
||||
throws IOException {
|
||||
try {
|
||||
@@ -82,18 +84,12 @@ public class RibbonHttpRequest extends AbstractClientHttpRequest {
|
||||
}
|
||||
HttpRequest request = builder.build();
|
||||
HttpResponse response = client.execute(request, config);
|
||||
statsRecorder.recordStats(response);
|
||||
return new RibbonHttpResponse(response);
|
||||
} catch (Exception e) {
|
||||
statsRecorder.recordStats(e);
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
//TODO: fix stats, now that execute is not called
|
||||
// use execute here so stats are collected
|
||||
/*return loadBalancer.execute(this.config.getClientName(), new LoadBalancerRequest<ClientHttpResponse>() {
|
||||
@Override
|
||||
public ClientHttpResponse apply(ServiceInstance instance) throws Exception {
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
private void addHeaders(HttpHeaders headers) {
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.cloud.netflix.ribbon;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
@@ -33,8 +32,6 @@ import com.netflix.client.config.CommonClientConfigKey;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.servo.monitor.Stopwatch;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -65,6 +62,10 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
|
||||
@Override
|
||||
public ServiceInstance choose(String serviceId) {
|
||||
return this.chooseRibbonServer(serviceId);
|
||||
}
|
||||
|
||||
RibbonServer chooseRibbonServer(String serviceId) {
|
||||
Server server = getServer(serviceId);
|
||||
if (server == null) {
|
||||
return null;
|
||||
@@ -76,23 +77,21 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
@Override
|
||||
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) {
|
||||
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
|
||||
RibbonLoadBalancerContext context = this.clientFactory
|
||||
.getLoadBalancerContext(serviceId);
|
||||
Server server = getServer(loadBalancer);
|
||||
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
|
||||
serviceId), serverIntrospector(serviceId).getMetadata(server));
|
||||
|
||||
ServerStats serverStats = context.getServerStats(server);
|
||||
context.noteOpenConnection(serverStats);
|
||||
Stopwatch tracer = context.getExecuteTracer().start();
|
||||
RibbonLoadBalancerContext context = this.clientFactory
|
||||
.getLoadBalancerContext(serviceId);
|
||||
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
|
||||
|
||||
try {
|
||||
T returnVal = request.apply(ribbonServer);
|
||||
recordStats(context, tracer, serverStats, returnVal, null);
|
||||
statsRecorder.recordStats(returnVal);
|
||||
return returnVal;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
recordStats(context, tracer, serverStats, null, ex);
|
||||
statsRecorder.recordStats(ex);
|
||||
ReflectionUtils.rethrowRuntimeException(ex);
|
||||
}
|
||||
return null;
|
||||
@@ -116,13 +115,6 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
return serverIntrospector(serviceId).isSecure(server);
|
||||
}
|
||||
|
||||
private void recordStats(RibbonLoadBalancerContext context, Stopwatch tracer,
|
||||
ServerStats serverStats, Object entity, Throwable exception) {
|
||||
tracer.stop();
|
||||
long duration = tracer.getDuration(TimeUnit.MILLISECONDS);
|
||||
context.noteRequestCompletion(serverStats, entity, exception, duration, null/* errorHandler */);
|
||||
}
|
||||
|
||||
protected Server getServer(String serviceId) {
|
||||
return getServer(getLoadBalancer(serviceId));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.springframework.cloud.netflix.ribbon;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.servo.monitor.Stopwatch;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class RibbonStatsRecorder {
|
||||
|
||||
private RibbonLoadBalancerContext context;
|
||||
private final ServerStats serverStats;
|
||||
private final Stopwatch tracer;
|
||||
|
||||
public RibbonStatsRecorder(RibbonLoadBalancerContext context, Server server) {
|
||||
this.context = context;
|
||||
serverStats = context.getServerStats(server);
|
||||
context.noteOpenConnection(serverStats);
|
||||
tracer = context.getExecuteTracer().start();
|
||||
}
|
||||
|
||||
public void recordStats(Object entity) {
|
||||
this.recordStats(entity, null);
|
||||
}
|
||||
|
||||
public void recordStats(Throwable t) {
|
||||
this.recordStats(null, t);
|
||||
}
|
||||
|
||||
protected void recordStats(Object entity, Throwable exception) {
|
||||
this.tracer.stop();
|
||||
long duration = this.tracer.getDuration(TimeUnit.MILLISECONDS);
|
||||
this.context.noteRequestCompletion(serverStats, entity, exception, duration, null/* errorHandler */);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user