Optimize spring cloud gateway in concurrent scenes with asyncSpan api (#3265)

* update gateway
This commit is contained in:
于玉桔 2019-08-14 22:02:52 +08:00 committed by 吴晟 Wu Sheng
parent ffe1df579f
commit 19b37cab6f
13 changed files with 183 additions and 68 deletions

View File

@ -15,17 +15,20 @@
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context.Constants;
public class DefaultHttpHeadersInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
if (ContextManager.isActive()) {
objInst.setSkyWalkingDynamicField(ContextManager.capture());
Object transmitter = ContextManager.getRuntimeContext().get(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER);
if (transmitter != null) {
objInst.setSkyWalkingDynamicField(transmitter);
ContextManager.getRuntimeContext().remove(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER);
}
}
}

View File

@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
@ -42,7 +42,11 @@ public class HttpClientOperationsHeadersInterceptor implements InstanceMethodsAr
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
((EnhancedInstance) ret).setSkyWalkingDynamicField(((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField());
Object transmitter = ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();
if (transmitter != null) {
objInst.setSkyWalkingDynamicField(transmitter);
((EnhancedInstance) allArguments[0]).setSkyWalkingDynamicField(null);
}
return ret;
}

View File

@ -16,13 +16,12 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
import io.netty.handler.codec.http.HttpHeaders;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@ -30,6 +29,7 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedI
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context.SWTransmitter;
import reactor.netty.channel.ChannelOperations;
import reactor.netty.http.client.HttpClientRequest;
@ -45,30 +45,32 @@ public class HttpClientOperationsSendInterceptor implements InstanceMethodsAroun
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
HttpClientRequest request = (HttpClientRequest) objInst;
EnhancedInstance instance = (EnhancedInstance) request;
SWTransmitter transmitter = (SWTransmitter) objInst.getSkyWalkingDynamicField();
if (transmitter != null) {
HttpClientRequest request = (HttpClientRequest) objInst;
HttpHeaders header = request.requestHeaders();
ChannelOperations channelOpt = (ChannelOperations) objInst;
InetSocketAddress remote = (InetSocketAddress) (channelOpt.channel().remoteAddress());
String peer = remote.getHostName() + ":" + remote.getPort();
HttpHeaders header = request.requestHeaders();
ChannelOperations channelOpt = (ChannelOperations) objInst;
InetSocketAddress remote = (InetSocketAddress) (channelOpt.channel().remoteAddress());
String peer = remote.getHostName() + ":" + remote.getPort();
AbstractSpan span = ContextManager.createExitSpan(toPath(request.uri()), peer);
ContextSnapshot snapshot = (ContextSnapshot) instance.getSkyWalkingDynamicField();
AbstractSpan span = ContextManager.createExitSpan(transmitter.getOperationName(), peer);
ContextManager.continued(transmitter.getSnapshot());
ContextCarrier contextCarrier = new ContextCarrier();
ContextManager.inject(contextCarrier);
ContextManager.continued(snapshot);
ContextCarrier contextCarrier = new ContextCarrier();
ContextManager.inject(contextCarrier);
span.setComponent(ComponentsDefine.SPRING_CLOUD_GATEWAY);
Tags.URL.set(span, peer + request.uri());
Tags.HTTP.METHOD.set(span, request.method().name());
SpanLayer.asHttp(span);
span.setComponent(ComponentsDefine.SPRING_CLOUD_GATEWAY);
Tags.URL.set(span, peer + request.uri());
Tags.HTTP.METHOD.set(span, request.method().name());
SpanLayer.asHttp(span);
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
header.set(next.getHeadKey(), next.getHeadValue());
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
header.set(next.getHeadKey(), next.getHeadValue());
}
transmitter.setSpanGateway(span.prepareForAsync());
ContextManager.stopSpan(span);
}
}
@ -84,13 +86,4 @@ public class HttpClientOperationsSendInterceptor implements InstanceMethodsAroun
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
private static String toPath(String uri) {
int index = uri.indexOf("?");
if (index > -1) {
return uri.substring(0, index);
} else {
return uri;
}
}
}

View File

@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
@ -24,6 +24,7 @@ import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context.SWTransmitter;
import java.lang.reflect.Method;
@ -41,12 +42,18 @@ public class HttpClientOperationsStatusInterceptor implements InstanceMethodsAro
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
HttpResponseStatus response = (HttpResponseStatus) ret;
if (response.code() >= 400) {
ContextManager.activeSpan().errorOccurred();
Tags.STATUS_CODE.set(ContextManager.activeSpan(), String.valueOf(response.code()));
SWTransmitter transmitter = (SWTransmitter) objInst.getSkyWalkingDynamicField();
if (transmitter != null) {
HttpResponseStatus response = (HttpResponseStatus) ret;
if (response.code() >= 400) {
Tags.STATUS_CODE.set(transmitter.getSpanGateway().errorOccurred(), String.valueOf(response.code()));
Tags.STATUS_CODE.set(transmitter.getSpanWebflux().errorOccurred(), String.valueOf(response.code()));
}
transmitter.getSpanGateway().asyncFinish();
transmitter.getSpanWebflux().asyncFinish();
objInst.setSkyWalkingDynamicField(null);
}
ContextManager.stopSpan();
return ret;
}

View File

@ -16,13 +16,15 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context.Constants;
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context.SWTransmitter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.web.server.ServerWebExchange;
@ -34,22 +36,32 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G
/**
* @author zhaoyuguang
*/
public class FilteringWebHandlerInterceptor implements InstanceMethodsAroundInterceptor {
public class NettyRoutingFilterInterceptor implements InstanceMethodsAroundInterceptor {
private static final String SPRING_CLOUD_GATEWAY_ROUTE_PREFIX = "GATEWAY/";
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
if (ContextManager.isActive()) {
ContextManager.activeSpan().tag("route", route.getId());
AbstractSpan span = (AbstractSpan) ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();
String operationName = SPRING_CLOUD_GATEWAY_ROUTE_PREFIX;
if (span != null) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
operationName = operationName + route.getId();
span.setOperationName(operationName);
SWTransmitter transmitter = new SWTransmitter(span.prepareForAsync(), ContextManager.capture(), operationName);
ContextManager.stopSpan(span);
ContextManager.getRuntimeContext().put(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER, transmitter);
}
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
if (ContextManager.getRuntimeContext().get(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER) != null) {
ContextManager.getRuntimeContext().remove(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER);
}
return ret;
}
@ -57,10 +69,5 @@ public class FilteringWebHandlerInterceptor implements InstanceMethodsAroundInte
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
AbstractSpan span = ContextManager.activeSpan();
if (span != null) {
span.errorOccurred();
span.log(t);
}
}
}

View File

@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context;
/**
* @author zhaoyuguang
*/
public interface Constants {
String SPRING_CLOUD_GATEWAY_TRANSMITTER = "spring.cloud.gateway.transmitter";
}

View File

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.context;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
/**
* @author zhaoyuguang
*/
public class SWTransmitter {
private AbstractSpan spanWebflux;
private AbstractSpan spanGateway;
private ContextSnapshot snapshot;
private String operationName;
public SWTransmitter(AbstractSpan spanWebflux, ContextSnapshot snapshot, String operationName) {
this.spanWebflux = spanWebflux;
this.snapshot = snapshot;
this.operationName = operationName;
}
public AbstractSpan getSpanWebflux() {
return spanWebflux;
}
public void setSpanWebflux(AbstractSpan spanWebflux) {
this.spanWebflux = spanWebflux;
}
public AbstractSpan getSpanGateway() {
return spanGateway;
}
public void setSpanGateway(AbstractSpan spanGateway) {
this.spanGateway = spanGateway;
}
public ContextSnapshot getSnapshot() {
return snapshot;
}
public void setSnapshot(ContextSnapshot snapshot) {
this.snapshot = snapshot;
}
public String getOperationName() {
return operationName;
}
public void setOperationName(String operationName) {
this.operationName = operationName;
}
}

View File

@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.define;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
@ -42,7 +42,7 @@ public class DefaultHttpHeadersInstrumentation extends ClassInstanceMethodsEnhan
}
@Override public String getConstructorInterceptor() {
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.DefaultHttpHeadersInterceptor";
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.DefaultHttpHeadersInterceptor";
}
}
};

View File

@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.define;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
@ -50,7 +50,7 @@ public class HttpClientOperationsInstrumentation extends ClassInstanceMethodsEnh
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.HttpClientOperationsHeadersInterceptor";
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.HttpClientOperationsHeadersInterceptor";
}
@Override
@ -65,7 +65,7 @@ public class HttpClientOperationsInstrumentation extends ClassInstanceMethodsEnh
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.HttpClientOperationsSendInterceptor";
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.HttpClientOperationsSendInterceptor";
}
@Override
@ -81,7 +81,7 @@ public class HttpClientOperationsInstrumentation extends ClassInstanceMethodsEnh
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.HttpClientOperationsStatusInterceptor";
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.HttpClientOperationsStatusInterceptor";
}
@Override

View File

@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.define;
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
@ -33,7 +33,7 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName
* @author zhaoyuguang
*/
public class FilteringWebHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public class NettyRoutingFilterInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
@ -46,12 +46,14 @@ public class FilteringWebHandlerInstrumentation extends ClassInstanceMethodsEnha
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("handle").and(takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
return named("filter").and(takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.FilteringWebHandlerInterceptor";
return "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.NettyRoutingFilterInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
@ -62,7 +64,7 @@ public class FilteringWebHandlerInstrumentation extends ClassInstanceMethodsEnha
@Override
public ClassMatch enhanceClass() {
return byName("org.springframework.cloud.gateway.handler.FilteringWebHandler");
return byName("org.springframework.cloud.gateway.filter.NettyRoutingFilter");
}
@Override

View File

@ -14,6 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
spring-cloud-gateway-2.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.define.DefaultHttpHeadersInstrumentation
spring-cloud-gateway-2.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.define.FilteringWebHandlerInstrumentation
spring-cloud-gateway-2.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v2.define.HttpClientOperationsInstrumentation
spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.DefaultHttpHeadersInstrumentation
spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.HttpClientOperationsInstrumentation
spring-cloud-gateway-2.1.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x.define.NettyRoutingFilterInstrumentation

View File

@ -28,7 +28,7 @@
<artifactId>optional-spring-cloud</artifactId>
<modules>
<module>gateway-2.x-plugin</module>
<module>gateway-2.1.x-plugin</module>
</modules>
<packaging>pom</packaging>