From 51beb38e91fccf9e4ccd78b99c2ccfc295de7414 Mon Sep 17 00:00:00 2001 From: Nitesh Kant Date: Wed, 16 Jul 2014 13:15:41 -0700 Subject: [PATCH] Adding a perf optimized helloworld The current helloworld server does the following for usability: -- Prints the headers. -- Uses HTTP request aggregation. The above is not optimal for a benchmark. This new example will provide a ready to use perf test server. --- rx-netty-examples/README.md | 1 + rx-netty-examples/build.gradle | 19 +++++ .../http/helloworld/HelloWorldClient.java | 7 +- .../http/plaintext/PlainTextServer.java | 71 +++++++++++++++++++ .../netty/examples/http/plaintext/README.md | 27 +++++++ .../http/plaintext/PlainTextServerTest.java | 55 ++++++++++++++ 6 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/PlainTextServer.java create mode 100644 rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/README.md create mode 100644 rx-netty-examples/src/test/java/io/reactivex/netty/examples/http/plaintext/PlainTextServerTest.java diff --git a/rx-netty-examples/README.md b/rx-netty-examples/README.md index e53fd422..de5cc86b 100644 --- a/rx-netty-examples/README.md +++ b/rx-netty-examples/README.md @@ -9,6 +9,7 @@ Examples Catalog Protocol | Example / Test | Description ---------|---------|------------ +HTTP | [Plain text](src/main/java/io/reactivex/netty/examples/http/plaintext) | A performance optimized helloworld. Use this as a template for any simple perf tests. HTTP | [Hello World](src/main/java/io/reactivex/netty/examples/http/helloworld) | Simple HTTP GET client/server implementation. HTTP | [SSL Hello World](src/main/java/io/reactivex/netty/examples/http/ssl) | Hello World version with SSL connection. HTTP | [Simple POST](src/main/java/io/reactivex/netty/examples/http/post) | Simple HTTP POST client/server implementation. diff --git a/rx-netty-examples/build.gradle b/rx-netty-examples/build.gradle index 6f53c40e..96e9d006 100644 --- a/rx-netty-examples/build.gradle +++ b/rx-netty-examples/build.gradle @@ -16,6 +16,8 @@ + + sourceCompatibility = JavaVersion.VERSION_1_6 targetCompatibility = JavaVersion.VERSION_1_6 @@ -45,6 +47,23 @@ task runHelloWorldServer (dependsOn: [classes], type: JavaExec) { classpath = sourceSets.main.runtimeClasspath } +task runPlainTextServer (dependsOn: [classes], type: JavaExec) { + group = "Examples" + description = "Run Plain text HTTP server" + + main = "io.reactivex.netty.examples.http.plaintext.PlainTextServer" + classpath = sourceSets.main.runtimeClasspath +} + +task runPlainTextClient (dependsOn: [classes], type: JavaExec) { + group = "Examples" + description = "Run Plain text HTTP client" + + args "8111" + main = "io.reactivex.netty.examples.http.helloworld.HelloWorldClient" + classpath = sourceSets.main.runtimeClasspath +} + task runSslHelloWorldClient (dependsOn: [classes], type: JavaExec) { group = "Examples" description = "Run SSL Hello World client" diff --git a/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/helloworld/HelloWorldClient.java b/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/helloworld/HelloWorldClient.java index 6849b495..6b8042c9 100644 --- a/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/helloworld/HelloWorldClient.java +++ b/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/helloworld/HelloWorldClient.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.reactivex.netty.examples.http.helloworld; import io.netty.buffer.ByteBuf; @@ -76,6 +77,10 @@ public void printResponseHeader(HttpClientResponse response) { } public static void main(String[] args) { - new HelloWorldClient(DEFAULT_PORT).sendHelloRequest(); + int port = DEFAULT_PORT; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } + new HelloWorldClient(port).sendHelloRequest(); } } diff --git a/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/PlainTextServer.java b/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/PlainTextServer.java new file mode 100644 index 00000000..6ab0921d --- /dev/null +++ b/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/PlainTextServer.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014 Netflix, Inc. + * + * Licensed 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 io.reactivex.netty.examples.http.plaintext; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.HttpHeaders; +import io.reactivex.netty.RxNetty; +import io.reactivex.netty.protocol.http.server.HttpServer; +import io.reactivex.netty.protocol.http.server.HttpServerRequest; +import io.reactivex.netty.protocol.http.server.HttpServerResponse; +import io.reactivex.netty.protocol.http.server.RequestHandler; +import rx.Observable; + +/** + * @author Nitesh Kant + */ +public final class PlainTextServer { + + static final int DEFAULT_PORT = 8111; + public static final String WELCOME_MSG = "Welcome!!"; + private static final byte[] WELCOME_MSG_BYTES = WELCOME_MSG.getBytes(); + private static final String CONTENT_LENGTH_HEADER_VAL = String.valueOf(WELCOME_MSG_BYTES.length); // Does not use int as this omits conversion to string for every response. + + private final int port; + + public PlainTextServer(int port) { + this.port = port; + } + + public HttpServer createServer() { + HttpServer server = + RxNetty.createHttpServer(port, + new RequestHandler() { + @Override + public Observable handle(HttpServerRequest request, + final HttpServerResponse response) { + response.getHeaders().set(HttpHeaders.Names.CONTENT_LENGTH, + CONTENT_LENGTH_HEADER_VAL); // This makes RxNetty write a single Full response as opposed to writing header, content & lastHttpContent. + ByteBuf content = response.getAllocator() + .buffer(WELCOME_MSG_BYTES.length) + .writeBytes(WELCOME_MSG_BYTES); + response.write(content); + return response.close( + false); // Let RxNetty take care of flushing appropriately. Do NOT use when processing in a different thread. + } + }); + + return server; + } + + public static void main(final String[] args) throws InterruptedException { + HttpServer server = new PlainTextServer(DEFAULT_PORT).createServer(); + server.start(); + System.out.println("HTTP plain text server started at port: " + server.getServerPort()); + server.waitTillShutdown(); + } +} diff --git a/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/README.md b/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/README.md new file mode 100644 index 00000000..66b7a0c5 --- /dev/null +++ b/rx-netty-examples/src/main/java/io/reactivex/netty/examples/http/plaintext/README.md @@ -0,0 +1,27 @@ +Overview +======== + +This example is intended to be a sample used for "helloworld" performance tests for RxNetty and has optimizations specific +for helloworld kind of tests. + +The following are the primary differences over the [HelloWorld example](../helloworld) + +- This example does NOT aggregate HTTP requests. +- This example does NOT print the request headers. + +Running +======= + +To run the example execute: + +``` +$ cd RxNetty/rx-netty-examples +$ ../gradlew runPlainTextServer +``` + +and in another console: + +``` +$ cd RxNetty/rx-netty-examples +$ ../gradlew runPlainTextClient +``` \ No newline at end of file diff --git a/rx-netty-examples/src/test/java/io/reactivex/netty/examples/http/plaintext/PlainTextServerTest.java b/rx-netty-examples/src/test/java/io/reactivex/netty/examples/http/plaintext/PlainTextServerTest.java new file mode 100644 index 00000000..7f934508 --- /dev/null +++ b/rx-netty-examples/src/test/java/io/reactivex/netty/examples/http/plaintext/PlainTextServerTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 Netflix, Inc. + * + * Licensed 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 io.reactivex.netty.examples.http.plaintext; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.reactivex.netty.examples.ExamplesEnvironment; +import io.reactivex.netty.examples.http.helloworld.HelloWorldClient; +import io.reactivex.netty.protocol.http.server.HttpServer; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static io.reactivex.netty.examples.http.plaintext.PlainTextServer.DEFAULT_PORT; + +/** + * @author Tomasz Bak + */ +public class PlainTextServerTest extends ExamplesEnvironment { + + private HttpServer server; + + @Before + public void setupHttpHelloServer() { + server = new PlainTextServer(DEFAULT_PORT).createServer(); + server.start(); + } + + @After + public void stopServer() throws InterruptedException { + server.shutdown(); + } + + @Test + public void testRequestReplySequence() { + HelloWorldClient client = new HelloWorldClient(DEFAULT_PORT); // The client is no different than hello world. + HttpResponseStatus statusCode = client.sendHelloRequest(); + Assert.assertEquals(HttpResponseStatus.OK, statusCode); + } +}