Add instructions for setting up traffic shaping on loopback

Enable benchmarks to detect shaped loopback binding and use it
This commit is contained in:
Louis Ryan 2015-06-23 10:58:27 -07:00
parent a69fbb0a2b
commit a02503ada7
2 changed files with 107 additions and 2 deletions

View File

@ -31,9 +31,14 @@ import io.netty.channel.nio.NioEventLoopGroup;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
@ -92,6 +97,61 @@ public abstract class AbstractBenchmark {
NIO, LOCAL;
}
private static final InetAddress BENCHMARK_ADDR;
/**
* Resolve the address bound to the benchmark interface. Currently we assume it's a
* child interface of the loopback interface with the term 'benchmark' in its name.
*
* <p>>This allows traffic shaping to be applied to an IP address and to have the benchmarks
* detect it's presence and use it. E.g for Linux we can apply netem to a specific IP to
* do traffic shaping, bind that IP to the loopback adapter and then apply a label to that
* binding so that it appears as a child interface.
*
* <pre>
* sudo tc qdisc del dev lo root
* sudo tc qdisc add dev lo root handle 1: prio
* sudo tc qdisc add dev lo parent 1:1 handle 2: netem delay 0.1ms rate 10gbit
* sudo tc filter add dev lo parent 1:0 protocol ip prio 1 \
* u32 match ip dst 127.127.127.127 flowid 2:1
* sudo ip addr add dev lo 127.127.127.127/32 label lo:benchmark
* </pre>
*/
static {
InetAddress tmp = null;
try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
outer: while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (!networkInterface.isLoopback()) {
continue;
}
Enumeration<NetworkInterface> subInterfaces = networkInterface.getSubInterfaces();
while (subInterfaces.hasMoreElements()) {
NetworkInterface subLoopback = subInterfaces.nextElement();
if (subLoopback.getDisplayName().contains("benchmark")) {
tmp = subLoopback.getInetAddresses().nextElement();
System.out.println("\nResolved benchmark address to " + tmp + " on "
+ subLoopback.getDisplayName() + "\n\n");
break outer;
}
}
}
} catch (SocketException se) {
System.out.println("\nWARNING: Error trying to resolve benchmark interface \n" + se);
}
if (tmp == null) {
try {
System.out.println(
"\nWARNING: Unable to resolve benchmark interface, defaulting to localhost");
tmp = InetAddress.getLocalHost();
} catch (UnknownHostException uhe) {
throw new RuntimeException(uhe);
}
}
BENCHMARK_ADDR = tmp;
}
protected ServerImpl server;
protected ByteBuf request;
@ -124,9 +184,9 @@ public abstract class AbstractBenchmark {
channelBuilder = NettyChannelBuilder.forAddress(address);
channelBuilder.channelType(LocalChannel.class);
} else {
// Pick a port using an ephemeral socket.
ServerSocket sock = new ServerSocket();
sock.bind(new InetSocketAddress("localhost", 0));
// Pick a port using an ephemeral socket.
sock.bind(new InetSocketAddress(BENCHMARK_ADDR, 0));
SocketAddress address = sock.getLocalSocketAddress();
sock.close();
serverBuilder = NettyServerBuilder.forAddress(address);

View File

@ -0,0 +1,45 @@
Benchmarks
==========
This directory contains the standard benchmarks used to assess the performance of GRPC. Since these
benchmarks run on localhost over loopback the performance of the underlying network is considerably
different to real networks and their behavior. To address this issue we recommend the use of
a network emulator to make loopback behave more like a real network. To this end the benchmark
code looks for a loopback interface with 'benchmark' in its name and attempts to use the address
bound to that interface when creating the client and server. If it cannot find such an interface it
will print a warning and continue with the default localhost address.
To attempt to standardize benchmark behavior across machines we attempt to emulate a 10gbit
ethernet interface with a packet delay of 0.1ms.
Linux
=====
On Linux we can use [netem](http://www.linuxfoundation.org/collaborate/workgroups/networking/netem) to shape the traffic appropriately.
```sh
# Remove all traffic shaping from loopback
sudo tc qdisc del dev lo root
# Add a priority traffic class to the root of loopback
sudo tc qdisc add dev lo root handle 1: prio
# Add a qdisc under the new class with the appropriate shaping
sudo tc qdisc add dev lo parent 1:1 handle 2: netem delay 0.1ms rate 10gbit
# Add a filter which selects the new qdisc class for traffic to 127.127.127.127
sudo tc filter add dev lo parent 1:0 protocol ip prio 1 u32 match ip dst 127.127.127.127 flowid 2:1
# Create an interface alias call 'lo:benchmark' that maps 127.127.127.126 to loopback
sudo ip addr add dev lo 127.127.127.127/32 label lo:benchmark
```
to remove this configuration
```sh
sudo tc qdisc del dev lo root
sudo ip addr del dev lo 127.127.127.127/32 label lo:benchmark
```
Other Platforms
===============
Contributions welcome!