mirror of https://github.com/grpc/grpc-java.git
netty: disable huffman coding in headers (#10563)
Huffman in the datacenter doesn't add much value in the common cases. It could be useful to turn on huffman based on the connection latency (say, >10ms means "assume cross-datacenter") but the Netty API doesn't lend it to that. The savings here aren't huge and it is expensive; the table provides the biggest savings.
This commit is contained in:
parent
90e76a1b4a
commit
2b65e660c0
|
|
@ -54,6 +54,7 @@ import io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
|
import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
||||||
|
import io.netty.handler.codec.http2.DefaultHttp2HeadersEncoder;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2LocalFlowController;
|
import io.netty.handler.codec.http2.DefaultHttp2LocalFlowController;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2RemoteFlowController;
|
import io.netty.handler.codec.http2.DefaultHttp2RemoteFlowController;
|
||||||
import io.netty.handler.codec.http2.Http2CodecUtil;
|
import io.netty.handler.codec.http2.Http2CodecUtil;
|
||||||
|
|
@ -69,6 +70,7 @@ import io.netty.handler.codec.http2.Http2FrameReader;
|
||||||
import io.netty.handler.codec.http2.Http2FrameWriter;
|
import io.netty.handler.codec.http2.Http2FrameWriter;
|
||||||
import io.netty.handler.codec.http2.Http2Headers;
|
import io.netty.handler.codec.http2.Http2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2HeadersDecoder;
|
import io.netty.handler.codec.http2.Http2HeadersDecoder;
|
||||||
|
import io.netty.handler.codec.http2.Http2HeadersEncoder;
|
||||||
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2Settings;
|
import io.netty.handler.codec.http2.Http2Settings;
|
||||||
|
|
@ -150,7 +152,9 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive");
|
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive");
|
||||||
Http2HeadersDecoder headersDecoder = new GrpcHttp2ClientHeadersDecoder(maxHeaderListSize);
|
Http2HeadersDecoder headersDecoder = new GrpcHttp2ClientHeadersDecoder(maxHeaderListSize);
|
||||||
Http2FrameReader frameReader = new DefaultHttp2FrameReader(headersDecoder);
|
Http2FrameReader frameReader = new DefaultHttp2FrameReader(headersDecoder);
|
||||||
Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
|
Http2HeadersEncoder encoder = new DefaultHttp2HeadersEncoder(
|
||||||
|
Http2HeadersEncoder.NEVER_SENSITIVE, false, 16, Integer.MAX_VALUE);
|
||||||
|
Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter(encoder);
|
||||||
Http2Connection connection = new DefaultHttp2Connection(false);
|
Http2Connection connection = new DefaultHttp2Connection(false);
|
||||||
WeightedFairQueueByteDistributor dist = new WeightedFairQueueByteDistributor(connection);
|
WeightedFairQueueByteDistributor dist = new WeightedFairQueueByteDistributor(connection);
|
||||||
dist.allocationQuantum(16 * 1024); // Make benchmarks fast again.
|
dist.allocationQuantum(16 * 1024); // Make benchmarks fast again.
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Ticker;
|
import com.google.common.base.Ticker;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
|
|
@ -69,6 +70,7 @@ import io.grpc.internal.testing.TestUtils;
|
||||||
import io.grpc.netty.NettyChannelBuilder.LocalSocketPicker;
|
import io.grpc.netty.NettyChannelBuilder.LocalSocketPicker;
|
||||||
import io.grpc.netty.NettyTestUtil.TrackingObjectPoolForTest;
|
import io.grpc.netty.NettyTestUtil.TrackingObjectPoolForTest;
|
||||||
import io.grpc.testing.TlsTesting;
|
import io.grpc.testing.TlsTesting;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelConfig;
|
import io.netty.channel.ChannelConfig;
|
||||||
import io.netty.channel.ChannelDuplexHandler;
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
|
|
@ -76,6 +78,7 @@ import io.netty.channel.ChannelFactory;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.ChannelPromise;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.ReflectiveChannelFactory;
|
import io.netty.channel.ReflectiveChannelFactory;
|
||||||
import io.netty.channel.local.LocalChannel;
|
import io.netty.channel.local.LocalChannel;
|
||||||
|
|
@ -92,6 +95,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -101,6 +105,7 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.SSLHandshakeException;
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
|
|
@ -538,6 +543,46 @@ public class NettyClientTransportTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void huffmanCodingShouldNotBePerformed() throws Exception {
|
||||||
|
String longStringOfA = Strings.repeat("a", 128);
|
||||||
|
|
||||||
|
negotiator = ProtocolNegotiators.serverPlaintext();
|
||||||
|
startServer();
|
||||||
|
|
||||||
|
NettyClientTransport transport = newTransport(ProtocolNegotiators.plaintext(),
|
||||||
|
DEFAULT_MAX_MESSAGE_SIZE, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, null, false,
|
||||||
|
TimeUnit.SECONDS.toNanos(10L), TimeUnit.SECONDS.toNanos(1L),
|
||||||
|
new ReflectiveChannelFactory<>(NioSocketChannel.class), group);
|
||||||
|
|
||||||
|
Metadata headers = new Metadata();
|
||||||
|
headers.put(Metadata.Key.of("test", Metadata.ASCII_STRING_MARSHALLER),
|
||||||
|
longStringOfA);
|
||||||
|
|
||||||
|
callMeMaybe(transport.start(clientTransportListener));
|
||||||
|
|
||||||
|
AtomicBoolean foundExpectedHeaderBytes = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
transport.channel().pipeline().addFirst(new ChannelDuplexHandler() {
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
|
||||||
|
throws Exception {
|
||||||
|
if (msg instanceof ByteBuf) {
|
||||||
|
if (((ByteBuf) msg).toString(StandardCharsets.UTF_8).contains(longStringOfA)) {
|
||||||
|
foundExpectedHeaderBytes.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.write(ctx, msg, promise);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
new Rpc(transport, headers).halfClose().waitForResponse();
|
||||||
|
|
||||||
|
if (!foundExpectedHeaderBytes.get()) {
|
||||||
|
fail("expected to find UTF-8 encoded 'a's in the header");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void maxHeaderListSizeShouldBeEnforcedOnServer() throws Exception {
|
public void maxHeaderListSizeShouldBeEnforcedOnServer() throws Exception {
|
||||||
startServer(100, 1);
|
startServer(100, 1);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue