mirror of https://github.com/grpc/grpc-java.git
netty: speed up header conversion by caching user agent string
Performance gain seems to be about 100-200ns based on a a couple trials. Benchmark (headerCount) (validate) Mode Cnt Score Error Units HeadersBenchmark.convertClientHeadersOld 10 false sample 187490 858.234 ± 3.992 ns/op HeadersBenchmark.convertClientHeadersOld 20 false sample 113589 1407.557 ± 45.178 ns/op HeadersBenchmark.convertClientHeadersOld 50 false sample 100725 3141.936 ± 55.175 ns/op HeadersBenchmark.convertClientHeadersOld 100 false sample 109742 5707.748 ± 38.222 ns/op HeadersBenchmark.convertHeaders 10 false sample 109137 748.486 ± 4.060 ns/op HeadersBenchmark.convertHeaders 20 false sample 133639 1238.528 ± 51.914 ns/op HeadersBenchmark.convertHeaders 50 false sample 107914 2915.602 ± 10.017 ns/op HeadersBenchmark.convertHeaders 100 false sample 110305 5682.404 ± 44.032 ns/op
This commit is contained in:
parent
ac9a5a5679
commit
5e30b2f7ba
|
@ -76,6 +76,7 @@ public class HeadersBenchmark {
|
|||
private AsciiString scheme = new AsciiString("https");
|
||||
private AsciiString defaultPath = new AsciiString("/Service.MethodMethodMethod");
|
||||
private AsciiString authority = new AsciiString("authority.googleapis.bogus");
|
||||
private AsciiString userAgent = new AsciiString("grpc-java-netty");
|
||||
|
||||
@Setup
|
||||
public void setUp() throws Exception {
|
||||
|
@ -89,7 +90,7 @@ public class HeadersBenchmark {
|
|||
@BenchmarkMode(Mode.SampleTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public Http2Headers convertHeaders() {
|
||||
return Utils.convertClientHeaders(metadata, scheme, defaultPath, authority);
|
||||
return Utils.convertClientHeaders(metadata, scheme, defaultPath, authority, userAgent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ public final class GrpcUtil {
|
|||
|
||||
public static final Joiner ACCEPT_ENCODING_JOINER = Joiner.on(',');
|
||||
|
||||
private static final String IMPLEMENTATION_VERION = getImplementationVersion();
|
||||
|
||||
/**
|
||||
* Maps HTTP error response status codes to transport codes.
|
||||
*/
|
||||
|
@ -303,8 +305,8 @@ public final class GrpcUtil {
|
|||
/**
|
||||
* Gets the User-Agent string for the gRPC transport.
|
||||
*/
|
||||
public static String getGrpcUserAgent(String transportName,
|
||||
@Nullable String applicationUserAgent) {
|
||||
public static String getGrpcUserAgent(
|
||||
String transportName, @Nullable String applicationUserAgent) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (applicationUserAgent != null) {
|
||||
builder.append(applicationUserAgent);
|
||||
|
@ -312,11 +314,7 @@ public final class GrpcUtil {
|
|||
}
|
||||
builder.append("grpc-java-");
|
||||
builder.append(transportName);
|
||||
String version = GrpcUtil.class.getPackage().getImplementationVersion();
|
||||
if (version != null) {
|
||||
builder.append("/");
|
||||
builder.append(version);
|
||||
}
|
||||
builder.append(IMPLEMENTATION_VERION);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
@ -491,4 +489,12 @@ public final class GrpcUtil {
|
|||
}
|
||||
|
||||
private GrpcUtil() {}
|
||||
|
||||
private static String getImplementationVersion() {
|
||||
String version = GrpcUtil.class.getPackage().getImplementationVersion();
|
||||
if (version != null) {
|
||||
return "/" + version;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,17 @@ abstract class NettyClientStream extends Http2ClientStream implements StreamIdHo
|
|||
private Metadata headers;
|
||||
private final Channel channel;
|
||||
private final NettyClientHandler handler;
|
||||
private AsciiString authority;
|
||||
private final AsciiString scheme;
|
||||
private final AsciiString userAgent;
|
||||
private AsciiString authority;
|
||||
|
||||
private Http2Stream http2Stream;
|
||||
private Integer id;
|
||||
private WriteQueue writeQueue;
|
||||
|
||||
NettyClientStream(MethodDescriptor<?, ?> method, Metadata headers, Channel channel,
|
||||
NettyClientHandler handler, int maxMessageSize, AsciiString authority, AsciiString scheme) {
|
||||
NettyClientHandler handler, int maxMessageSize, AsciiString authority, AsciiString scheme,
|
||||
AsciiString userAgent) {
|
||||
super(new NettyWritableBufferAllocator(channel.alloc()), maxMessageSize);
|
||||
this.method = checkNotNull(method, "method");
|
||||
this.headers = checkNotNull(headers, "headers");
|
||||
|
@ -76,6 +79,7 @@ abstract class NettyClientStream extends Http2ClientStream implements StreamIdHo
|
|||
this.handler = checkNotNull(handler, "handler");
|
||||
this.authority = checkNotNull(authority, "authority");
|
||||
this.scheme = checkNotNull(scheme, "scheme");
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +95,7 @@ abstract class NettyClientStream extends Http2ClientStream implements StreamIdHo
|
|||
// Convert the headers into Netty HTTP/2 headers.
|
||||
AsciiString defaultPath = new AsciiString("/" + method.getFullMethodName());
|
||||
Http2Headers http2Headers
|
||||
= Utils.convertClientHeaders(headers, scheme, defaultPath, authority);
|
||||
= Utils.convertClientHeaders(headers, scheme, defaultPath, authority, userAgent);
|
||||
headers = null;
|
||||
|
||||
ChannelFutureListener failureListener = new ChannelFutureListener() {
|
||||
|
|
|
@ -60,6 +60,9 @@ import java.util.concurrent.Executor;
|
|||
* A Netty-based {@link ManagedClientTransport} implementation.
|
||||
*/
|
||||
class NettyClientTransport implements ManagedClientTransport {
|
||||
private static final AsciiString DEFAULT_AGENT =
|
||||
new AsciiString(GrpcUtil.getGrpcUserAgent("netty", null));
|
||||
|
||||
private final SocketAddress address;
|
||||
private final Class<? extends Channel> channelType;
|
||||
private final EventLoopGroup group;
|
||||
|
@ -68,6 +71,7 @@ class NettyClientTransport implements ManagedClientTransport {
|
|||
private final int flowControlWindow;
|
||||
private final int maxMessageSize;
|
||||
private final int maxHeaderListSize;
|
||||
|
||||
private ProtocolNegotiator.Handler negotiationHandler;
|
||||
private NettyClientHandler handler;
|
||||
// We should not send on the channel until negotiation completes. This is a hard requirement
|
||||
|
@ -110,8 +114,11 @@ class NettyClientTransport implements ManagedClientTransport {
|
|||
public ClientStream newStream(MethodDescriptor<?, ?> method, Metadata headers) {
|
||||
Preconditions.checkNotNull(method, "method");
|
||||
Preconditions.checkNotNull(headers, "headers");
|
||||
AsciiString userAgent = headers.containsKey(GrpcUtil.USER_AGENT_KEY)
|
||||
? new AsciiString(GrpcUtil.getGrpcUserAgent("netty", headers.get(GrpcUtil.USER_AGENT_KEY)))
|
||||
: DEFAULT_AGENT;
|
||||
return new NettyClientStream(method, headers, channel, handler, maxMessageSize, authority,
|
||||
negotiationHandler.scheme()) {
|
||||
negotiationHandler.scheme(), userAgent) {
|
||||
@Override
|
||||
protected Status statusFromFailedFuture(ChannelFuture f) {
|
||||
return NettyClientTransport.this.statusFromFailedFuture(f);
|
||||
|
|
|
@ -117,7 +117,8 @@ class Utils {
|
|||
public static Http2Headers convertClientHeaders(Metadata headers,
|
||||
AsciiString scheme,
|
||||
AsciiString defaultPath,
|
||||
AsciiString authority) {
|
||||
AsciiString authority,
|
||||
AsciiString userAgent) {
|
||||
Preconditions.checkNotNull(defaultPath, "defaultPath");
|
||||
Preconditions.checkNotNull(authority, "authority");
|
||||
// Add any application-provided headers first.
|
||||
|
@ -132,8 +133,8 @@ class Utils {
|
|||
.set(TE_HEADER, TE_TRAILERS);
|
||||
|
||||
// Set the User-Agent header.
|
||||
String userAgent = GrpcUtil.getGrpcUserAgent("netty", headers.get(USER_AGENT_KEY));
|
||||
http2Headers.set(USER_AGENT, new AsciiString(userAgent.getBytes(UTF_8)));
|
||||
//String userAgent = GrpcUtil.getGrpcUserAgent("netty", headers.get(USER_AGENT_KEY));
|
||||
http2Headers.set(USER_AGENT, userAgent);
|
||||
|
||||
return http2Headers;
|
||||
}
|
||||
|
|
|
@ -358,7 +358,8 @@ public class NettyClientStreamTest extends NettyStreamTestBase<NettyClientStream
|
|||
listener = mock(ClientStreamListener.class);
|
||||
|
||||
stream = new NettyClientStreamImpl(methodDescriptor, new Metadata(), channel, handler,
|
||||
DEFAULT_MAX_MESSAGE_SIZE, AsciiString.of("localhost"), AsciiString.of("http"));
|
||||
DEFAULT_MAX_MESSAGE_SIZE, AsciiString.of("localhost"), AsciiString.of("http"),
|
||||
AsciiString.of("agent"));
|
||||
stream.start(listener);
|
||||
stream().id(STREAM_ID);
|
||||
verify(listener, never()).onReady();
|
||||
|
@ -382,7 +383,8 @@ public class NettyClientStreamTest extends NettyStreamTestBase<NettyClientStream
|
|||
}).when(writeQueue).enqueue(any(), any(ChannelPromise.class), anyBoolean());
|
||||
when(writeQueue.enqueue(any(), anyBoolean())).thenReturn(future);
|
||||
NettyClientStream stream = new NettyClientStreamImpl(methodDescriptor, new Metadata(), channel,
|
||||
handler, DEFAULT_MAX_MESSAGE_SIZE, AsciiString.of("localhost"), AsciiString.of("http"));
|
||||
handler, DEFAULT_MAX_MESSAGE_SIZE, AsciiString.of("localhost"), AsciiString.of("http"),
|
||||
AsciiString.of("agent"));
|
||||
stream.start(listener);
|
||||
assertTrue(stream.canSend());
|
||||
assertTrue(stream.canReceive());
|
||||
|
@ -422,8 +424,9 @@ public class NettyClientStreamTest extends NettyStreamTestBase<NettyClientStream
|
|||
|
||||
class NettyClientStreamImpl extends NettyClientStream {
|
||||
NettyClientStreamImpl(MethodDescriptor<?, ?> method, Metadata headers, Channel channel,
|
||||
NettyClientHandler handler, int maxMessageSize, AsciiString authority, AsciiString scheme) {
|
||||
super(method, headers, channel, handler, maxMessageSize, authority, scheme);
|
||||
NettyClientHandler handler, int maxMessageSize, AsciiString authority, AsciiString scheme,
|
||||
AsciiString userAgent) {
|
||||
super(method, headers, channel, handler, maxMessageSize, authority, scheme, userAgent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue