Commit 4f6b2bce by Spencer Gibb

Record load balancer stats in RibbonHttpRequest.

fixes gh-731
parent 472b9d17
......@@ -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));
}
......
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 */);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment