fix:optimize instance circuit beaker. (#909)

pull/921/head
Haotian Zhang 2 years ago committed by GitHub
parent 93c85ec3cc
commit eae5f68c4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,3 +3,4 @@
- [fix: fix log feign response stream close bug.](https://github.com/Tencent/spring-cloud-tencent/pull/897) - [fix: fix log feign response stream close bug.](https://github.com/Tencent/spring-cloud-tencent/pull/897)
- [fix:remove the secondary report.](https://github.com/Tencent/spring-cloud-tencent/pull/899) - [fix:remove the secondary report.](https://github.com/Tencent/spring-cloud-tencent/pull/899)
- [fix:optimize instance circuit beaker.](https://github.com/Tencent/spring-cloud-tencent/pull/909)

@ -80,6 +80,20 @@
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>healthchecker-http</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>healthchecker-udp</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>healthchecker-tcp</artifactId>
</dependency>
<!-- Polaris dependencies end --> <!-- Polaris dependencies end -->
<dependency> <dependency>

@ -17,7 +17,7 @@
<!-- Spring Cloud Tencent dependencies start --> <!-- Spring Cloud Tencent dependencies start -->
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-context</artifactId> <artifactId>spring-cloud-tencent-rpc-enhancement</artifactId>
</dependency> </dependency>
<!-- Spring Cloud Tencent dependencies end --> <!-- Spring Cloud Tencent dependencies end -->

@ -73,7 +73,7 @@
<revision>1.11.0-2021.0.6-SNAPSHOT</revision> <revision>1.11.0-2021.0.6-SNAPSHOT</revision>
<!-- Dependencies --> <!-- Dependencies -->
<polaris.version>1.11.1</polaris.version> <polaris.version>1.11.2</polaris.version>
<guava.version>31.0.1-jre</guava.version> <guava.version>31.0.1-jre</guava.version>
<logback.version>1.2.11</logback.version> <logback.version>1.2.11</logback.version>
<mocktio.version>4.5.1</mocktio.version> <mocktio.version>4.5.1</mocktio.version>

@ -18,10 +18,14 @@
package com.tencent.cloud.polaris.ciruitbreaker.example; package com.tencent.cloud.polaris.ciruitbreaker.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/** /**
@ -33,14 +37,47 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/example/service/b") @RequestMapping("/example/service/b")
public class ServiceBController { public class ServiceBController {
private static final Logger LOG = LoggerFactory.getLogger(ServiceBController.class);
private boolean ifBadGateway = true;
private boolean ifDelay = true;
@GetMapping("/setBadGateway")
public void setBadGateway(@RequestParam boolean param) {
if (param) {
LOG.info("info is set to return HttpStatus.BAD_GATEWAY.");
}
else {
LOG.info("info is set to return HttpStatus.OK.");
}
this.ifBadGateway = param;
}
@GetMapping("/setDelay")
public void setDelay(@RequestParam boolean param) {
if (param) {
LOG.info("info is set to delay 100ms.");
}
else {
LOG.info("info is set to no delay.");
}
this.ifDelay = param;
}
/** /**
* Get service information. * Get service information.
* *
* @return service information * @return service information
*/ */
@GetMapping("/info") @GetMapping("/info")
@ResponseStatus(value = HttpStatus.BAD_GATEWAY, reason = "failed for call my service") public ResponseEntity<String> info() throws InterruptedException {
public String info() { if (ifBadGateway) {
return "failed for call service B2"; return new ResponseEntity<>("failed for call my service", HttpStatus.BAD_GATEWAY);
}
if (ifDelay) {
Thread.sleep(100);
}
return new ResponseEntity<>("hello world ! I'm a service B2", HttpStatus.OK);
} }
} }

@ -40,7 +40,7 @@ public class EnhancedFeignClient implements Client {
private final Client delegate; private final Client delegate;
private EnhancedFeignPluginRunner pluginRunner; private final EnhancedFeignPluginRunner pluginRunner;
public EnhancedFeignClient(Client target, EnhancedFeignPluginRunner pluginRunner) { public EnhancedFeignClient(Client target, EnhancedFeignPluginRunner pluginRunner) {
this.delegate = checkNotNull(target, "target"); this.delegate = checkNotNull(target, "target");
@ -56,7 +56,9 @@ public class EnhancedFeignClient implements Client {
// Run pre enhanced feign plugins. // Run pre enhanced feign plugins.
pluginRunner.run(PRE, enhancedFeignContext); pluginRunner.run(PRE, enhancedFeignContext);
try { try {
long startMillis = System.currentTimeMillis();
Response response = delegate.execute(request, options); Response response = delegate.execute(request, options);
enhancedFeignContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedFeignContext.setResponse(response); enhancedFeignContext.setResponse(response);
// Run post enhanced feign plugins. // Run post enhanced feign plugins.

@ -35,6 +35,8 @@ public class EnhancedFeignContext {
private Exception exception; private Exception exception;
private long delay;
public Request getRequest() { public Request getRequest() {
return request; return request;
} }
@ -66,4 +68,12 @@ public class EnhancedFeignContext {
public void setException(Exception exception) { public void setException(Exception exception) {
this.exception = exception; this.exception = exception;
} }
public long getDelay() {
return delay;
}
public void setDelay(long delay) {
this.delay = delay;
}
} }

@ -72,12 +72,13 @@ public class ExceptionPolarisReporter implements EnhancedFeignPlugin {
Response response = context.getResponse(); Response response = context.getResponse();
Exception exception = context.getException(); Exception exception = context.getException();
RetStatus retStatus = RetStatus.RetFail; RetStatus retStatus = RetStatus.RetFail;
long delay = context.getDelay();
if (exception instanceof SocketTimeoutException) { if (exception instanceof SocketTimeoutException) {
retStatus = RetStatus.RetTimeout; retStatus = RetStatus.RetTimeout;
} }
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}].", retStatus.name(), request.httpMethod() LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.", retStatus.name(), request.httpMethod()
.name(), request.url(), response.status()); .name(), request.url(), response.status(), delay);
ServiceCallResult resultRequest = ReporterUtils.createServiceCallResult(request, retStatus); ServiceCallResult resultRequest = ReporterUtils.createServiceCallResult(request, response, delay, retStatus);
consumerAPI.updateServiceCallResult(resultRequest); consumerAPI.updateServiceCallResult(resultRequest);
} }
} }

@ -30,6 +30,7 @@ import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.CollectionUtils;
import feign.Request; import feign.Request;
import feign.RequestTemplate; import feign.RequestTemplate;
import feign.Response;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -48,7 +49,7 @@ public final class ReporterUtils {
private ReporterUtils() { private ReporterUtils() {
} }
public static ServiceCallResult createServiceCallResult(final Request request, RetStatus retStatus) { public static ServiceCallResult createServiceCallResult(final Request request, final Response response, long delay, RetStatus retStatus) {
ServiceCallResult resultRequest = new ServiceCallResult(); ServiceCallResult resultRequest = new ServiceCallResult();
resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE); resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE);
@ -68,7 +69,9 @@ public final class ReporterUtils {
} }
URI uri = URI.create(request.url()); URI uri = URI.create(request.url());
resultRequest.setMethod(uri.getPath()); resultRequest.setMethod(uri.getPath());
resultRequest.setRetCode(response.status());
resultRequest.setRetStatus(retStatus); resultRequest.setRetStatus(retStatus);
resultRequest.setDelay(delay);
String sourceNamespace = MetadataContext.LOCAL_NAMESPACE; String sourceNamespace = MetadataContext.LOCAL_NAMESPACE;
String sourceService = MetadataContext.LOCAL_SERVICE; String sourceService = MetadataContext.LOCAL_SERVICE;
if (StringUtils.isNotBlank(sourceNamespace) && StringUtils.isNotBlank(sourceService)) { if (StringUtils.isNotBlank(sourceNamespace) && StringUtils.isNotBlank(sourceService)) {

@ -69,12 +69,13 @@ public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter imple
Request request = context.getRequest(); Request request = context.getRequest();
Response response = context.getResponse(); Response response = context.getResponse();
RetStatus retStatus = RetStatus.RetSuccess; RetStatus retStatus = RetStatus.RetSuccess;
long delay = context.getDelay();
if (apply(HttpStatus.resolve(response.status()))) { if (apply(HttpStatus.resolve(response.status()))) {
retStatus = RetStatus.RetFail; retStatus = RetStatus.RetFail;
} }
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}].", retStatus.name(), request.httpMethod() LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.", retStatus.name(), request.httpMethod()
.name(), request.url(), response.status()); .name(), request.url(), response.status(), delay);
ServiceCallResult resultRequest = ReporterUtils.createServiceCallResult(request, retStatus); ServiceCallResult resultRequest = ReporterUtils.createServiceCallResult(request, response, delay, retStatus);
consumerAPI.updateServiceCallResult(resultRequest); consumerAPI.updateServiceCallResult(resultRequest);
} }
} }

@ -117,12 +117,14 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter
} }
private void reportResult(URI url, ClientHttpResponse response) { private void reportResult(URI url, ClientHttpResponse response) {
ServiceCallResult resultRequest = createServiceCallResult(url);
try { try {
ServiceCallResult resultRequest = createServiceCallResult(url, response);
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata(); Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
String targetHost = loadBalancerContext.get("host"); String targetHost = loadBalancerContext.get("host");
String targetPort = loadBalancerContext.get("port"); String targetPort = loadBalancerContext.get("port");
String startMillis = loadBalancerContext.get("startMillis");
long delay = System.currentTimeMillis() - Long.parseLong(startMillis);
if (StringUtils.isBlank(targetHost) || StringUtils.isBlank(targetPort)) { if (StringUtils.isBlank(targetHost) || StringUtils.isBlank(targetPort)) {
LOGGER.warn("Can not get target host or port from metadata context. host = {}, port = {}", targetHost, targetPort); LOGGER.warn("Can not get target host or port from metadata context. host = {}, port = {}", targetHost, targetPort);
@ -131,6 +133,7 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter
resultRequest.setHost(targetHost); resultRequest.setHost(targetHost);
resultRequest.setPort(Integer.parseInt(targetPort)); resultRequest.setPort(Integer.parseInt(targetPort));
resultRequest.setDelay(delay);
// checking response http status code // checking response http status code
if (apply(response.getStatusCode())) { if (apply(response.getStatusCode())) {
@ -150,8 +153,8 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter
} }
// processing report with consumerAPI . // processing report with consumerAPI .
LOGGER.debug("Will report result of {}. URL=[{}]. Response=[{}].", resultRequest.getRetStatus().name(), LOGGER.debug("Will report result of {}. Request=[{}]. Response=[{}]. Delay=[{}]ms.", resultRequest.getRetStatus()
url, response); .name(), url, response.getStatusCode().value(), delay);
consumerAPI.updateServiceCallResult(resultRequest); consumerAPI.updateServiceCallResult(resultRequest);
} }
catch (Exception e) { catch (Exception e) {
@ -193,12 +196,13 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter
response.getHeaders().remove(HEADER_HAS_ERROR); response.getHeaders().remove(HEADER_HAS_ERROR);
} }
private ServiceCallResult createServiceCallResult(URI uri) { private ServiceCallResult createServiceCallResult(URI uri, ClientHttpResponse response) throws IOException {
ServiceCallResult resultRequest = new ServiceCallResult(); ServiceCallResult resultRequest = new ServiceCallResult();
String serviceName = uri.getHost(); String serviceName = uri.getHost();
resultRequest.setService(serviceName); resultRequest.setService(serviceName);
resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE); resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE);
resultRequest.setMethod(uri.getPath()); resultRequest.setMethod(uri.getPath());
resultRequest.setRetCode(response.getStatusCode().value());
resultRequest.setRetStatus(RetStatus.RetSuccess); resultRequest.setRetStatus(RetStatus.RetSuccess);
String sourceNamespace = MetadataContext.LOCAL_NAMESPACE; String sourceNamespace = MetadataContext.LOCAL_NAMESPACE;
String sourceService = MetadataContext.LOCAL_SERVICE; String sourceService = MetadataContext.LOCAL_SERVICE;

@ -38,6 +38,7 @@ public final class LoadBalancerClientAspectUtils {
ServiceInstance instance = (ServiceInstance) server; ServiceInstance instance = (ServiceInstance) server;
MetadataContextHolder.get().setLoadbalancer("host", instance.getHost()); MetadataContextHolder.get().setLoadbalancer("host", instance.getHost());
MetadataContextHolder.get().setLoadbalancer("port", String.valueOf(instance.getPort())); MetadataContextHolder.get().setLoadbalancer("port", String.valueOf(instance.getPort()));
MetadataContextHolder.get().setLoadbalancer("startMillis", String.valueOf(System.currentTimeMillis()));
} }
} }
} }

@ -39,6 +39,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@ -63,7 +64,7 @@ public class ExceptionPolarisReporterTest {
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
mockedReporterUtils = Mockito.mockStatic(ReporterUtils.class); mockedReporterUtils = Mockito.mockStatic(ReporterUtils.class);
mockedReporterUtils.when(() -> ReporterUtils.createServiceCallResult(any(Request.class), any(RetStatus.class))) mockedReporterUtils.when(() -> ReporterUtils.createServiceCallResult(any(Request.class), any(Response.class), anyLong(), any(RetStatus.class)))
.thenReturn(mock(ServiceCallResult.class)); .thenReturn(mock(ServiceCallResult.class));
} }

@ -27,6 +27,7 @@ import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.rpc.ServiceCallResult; import com.tencent.polaris.api.rpc.ServiceCallResult;
import feign.Request; import feign.Request;
import feign.RequestTemplate; import feign.RequestTemplate;
import feign.Response;
import feign.Target; import feign.Target;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -94,7 +95,11 @@ public class ReporterUtilsTest {
doReturn(requestTemplate).when(request).requestTemplate(); doReturn(requestTemplate).when(request).requestTemplate();
doReturn("http://1.1.1.1:2345/path").when(request).url(); doReturn("http://1.1.1.1:2345/path").when(request).url();
ServiceCallResult serviceCallResult = ReporterUtils.createServiceCallResult(request, RetStatus.RetSuccess); // mock request
Response response = mock(Response.class);
doReturn(502).when(response).status();
ServiceCallResult serviceCallResult = ReporterUtils.createServiceCallResult(request, response, 10L, RetStatus.RetSuccess);
assertThat(serviceCallResult.getNamespace()).isEqualTo(NAMESPACE_TEST); assertThat(serviceCallResult.getNamespace()).isEqualTo(NAMESPACE_TEST);
assertThat(serviceCallResult.getService()).isEqualTo(SERVICE_PROVIDER); assertThat(serviceCallResult.getService()).isEqualTo(SERVICE_PROVIDER);
assertThat(serviceCallResult.getHost()).isEqualTo("1.1.1.1"); assertThat(serviceCallResult.getHost()).isEqualTo("1.1.1.1");
@ -104,5 +109,7 @@ public class ReporterUtilsTest {
assertThat(serviceCallResult.getCallerService().getNamespace()).isEqualTo(NAMESPACE_TEST); assertThat(serviceCallResult.getCallerService().getNamespace()).isEqualTo(NAMESPACE_TEST);
assertThat(serviceCallResult.getCallerService().getService()).isEqualTo(SERVICE_PROVIDER); assertThat(serviceCallResult.getCallerService().getService()).isEqualTo(SERVICE_PROVIDER);
assertThat(serviceCallResult.getLabels()).isEqualTo("k1:v1|k2:v2"); assertThat(serviceCallResult.getLabels()).isEqualTo("k1:v1|k2:v2");
assertThat(serviceCallResult.getRetCode()).isEqualTo(502);
assertThat(serviceCallResult.getDelay()).isEqualTo(10L);
} }
} }

@ -39,6 +39,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@ -63,7 +64,7 @@ public class SuccessPolarisReporterTest {
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
mockedReporterUtils = Mockito.mockStatic(ReporterUtils.class); mockedReporterUtils = Mockito.mockStatic(ReporterUtils.class);
mockedReporterUtils.when(() -> ReporterUtils.createServiceCallResult(any(Request.class), any(RetStatus.class))) mockedReporterUtils.when(() -> ReporterUtils.createServiceCallResult(any(Request.class), any(Response.class), anyLong(), any(RetStatus.class)))
.thenReturn(mock(ServiceCallResult.class)); .thenReturn(mock(ServiceCallResult.class));
} }

@ -89,6 +89,7 @@ public class EnhancedRestTemplateReporterTest {
Map<String, String> loadBalancerContext = new HashMap<>(); Map<String, String> loadBalancerContext = new HashMap<>();
loadBalancerContext.put("host", "1.1.1.1"); loadBalancerContext.put("host", "1.1.1.1");
loadBalancerContext.put("port", "8080"); loadBalancerContext.put("port", "8080");
loadBalancerContext.put("startMillis", String.valueOf(System.currentTimeMillis()));
when(metadataContext.getLoadbalancerMetadata()).thenReturn(loadBalancerContext); when(metadataContext.getLoadbalancerMetadata()).thenReturn(loadBalancerContext);
mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class); mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class);

Loading…
Cancel
Save