New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance improvements to Californium-proxy #479
Performance improvements to Californium-proxy #479
Conversation
Before this gets merged: Both me and @vikram919 have had some issues regarding the dependencies. Im building the Californium framework by running |
@martinmine
as from the example we can acheieve
how can we establsih?
|
californium-proxy/pom.xml
Outdated
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>net.sourceforge.streamsupport</groupId> | ||
<artifactId>streamsupport</artifactId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GPL!
I'm not sure, if you read the ECA carefully, but I guess using GPL is not possible :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've read through it briefly (and now, yet again) and to my understanding they are talking about including source code, not referencing through maven. This is more discussed here: https://www.eclipse.org/legal/eplfaq.php#USEINANOTHER What do you think? Edit: Nvm, it does not work lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making me aware of this, I'll try and find a workaround :)
Thanks! For the "httpasyncclient" we (the committers) must apply a CQ at eclipse for that. |
Very promising! |
@sophokles73 |
@vikram919 I wrote my setup based on the proxy example in the repo. Requests are then made towards the coap2http resource. There is also one small change I made in CoapTranslator.java to make it work (for some reason it wasn't setting the proxy URIs on the requests: diff --git a/californium-proxy/src/main/java/org/eclipse/californium/proxy/CoapTranslator.java b/californium-proxy/src/main/java/org/eclipse/californium/proxy/CoapTranslator.java
index 6ef83f6e..4d81c92a 100755
--- a/californium-proxy/src/main/java/org/eclipse/californium/proxy/CoapTranslator.java
+++ b/californium-proxy/src/main/java/org/eclipse/californium/proxy/CoapTranslator.java
@@ -90,6 +90,7 @@ public final class CoapTranslator {
// get the uri address from the proxy-uri option
URI serverUri;
+ String proxyUriForward = null;
try {
/*
* The new draft (14) only allows one proxy-uri option. Thus, this
@@ -97,6 +98,13 @@ public final class CoapTranslator {
*/
String proxyUriString = URLDecoder.decode(
incomingRequest.getOptions().getProxyUri(), "UTF-8");
+
+ final String proxyEndpoint = "coap2http/";
+ final int proxyEndpointPos = proxyUriString.indexOf(proxyEndpoint);
+ if (proxyEndpointPos > 0) {
+ proxyUriForward = proxyUriString.substring(proxyEndpointPos + proxyEndpoint.length());
+ proxyUriString = proxyUriString.substring(0, proxyEndpointPos + proxyEndpoint.length());
+ }
serverUri = new URI(proxyUriString);
} catch (UnsupportedEncodingException e) {
LOGGER.warn("UTF-8 do not support this encoding: {}", e);
@@ -121,6 +129,11 @@ public final class CoapTranslator {
options.removeBlock2();
options.clearUriPath();
options.clearUriQuery();
+
+ if (proxyUriForward != null && proxyUriForward.length() > 0) {
+ options.setProxyUri(proxyUriForward);
+ }
+
outgoingRequest.setOptions(options);
// set the proxy-uri as the outgoing uri |
@boaks I've rebased and re-implemented the CompletableFuture class under the compat package. Should be good from the GPL license now :) |
Hi @martinmine |
@vikram919 Do you also have some warmup period/request in your test? What was the standard deviation in your result? In my setup, I run as many requests as possible through the system for 10 minutes on one single thread requesting a HTML document and one warmup request. |
Btw, what system are you testing it on? (CPU/OS/memory) |
SD is 3.105ms, I see at the beginning it started with 16ms (initially).
CPU: Intel 4600M, i7 2.90GHz processor
|
@@ -0,0 +1,59 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2015 Institute for Pervasive Computing, ETH Zurich and others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems to be a new class so you should
- put in the current year
- use your name/affiliation instead of Institute of Pervasive ... suffixed by
and others.
- just put yourself to the list of contributors since nobody else has contributed anything to this class (yet)
* Backport of the class introduced in Java java.util.concurrent.CompletableFuture<T>. | ||
* @param <T> Type of the result the future shall complete with. | ||
*/ | ||
public class CompletableFuture<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has any of this code been copied from somewhere (given that you call it a backport)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, I just wrote it from the top of my head. It is a very basic straight-forward implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, that's good :-)
@@ -0,0 +1,32 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2015 Institute for Pervasive Computing, ETH Zurich and others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above ...
@@ -99,10 +99,10 @@ public static Request getRequest(final Request incomingRequest) throws Translati | |||
incomingRequest.getOptions().getProxyUri(), "UTF-8"); | |||
serverUri = new URI(proxyUriString); | |||
} catch (UnsupportedEncodingException e) { | |||
LOGGER.warn("UTF-8 do not support this encoding: " + e); | |||
LOGGER.warn("UTF-8 do not support this encoding: {}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you want to include the stack trace in the log statement, then you do not need to have a {}
placeholder in here.
The placeholder syntax makes more sense if you just want to include the exception's message property:
LOGGER.warn("....: {}", e.getMessage());
@@ -0,0 +1,80 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2015 Institute for Pervasive Computing, ETH Zurich and others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above ...
context.handleRequestForwarding(response); | ||
LOGGER.info("HTTP returned {}", response); | ||
} catch (Exception e) { | ||
LOGGER.warn("Exception while responding to Http request {}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either remove placeholder or use e.getMessage()
LOGGER.warn("Exception while responding to Http request", e); | ||
context.handleRequestForwarding(response); | ||
LOGGER.info("HTTP returned {}", response); | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please catch specific exceptions only
LOGGER.debug("Sending proxied CoAP request."); | ||
|
||
if (outgoingRequest.getDestination() == null) | ||
throw new NullPointerException("Destination is null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add brackets
if (outgoingRequest.getDestination() == null) | ||
throw new NullPointerException("Destination is null"); | ||
if (outgoingRequest.getDestinationPort() == 0) | ||
throw new NullPointerException("Destination port is 0"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add brackets
californium-proxy/pom.xml
Outdated
@@ -18,6 +18,7 @@ | |||
|
|||
<properties> | |||
<httpcomponents.version>4.2.5</httpcomponents.version> | |||
<httpasyncclient.version>4.1.3</httpasyncclient.version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in order for this to work properly we should also update http-core etc accordingly. IMHO since the dependency on the async client pulls in everything else needed from HttpComponents, we should remove the explicit dependency on httpcore-nio and also remove the httpcomponents.version
property.
@martinmine
|
@vikram919 @sophokles73 Thanks for your comments, I will address them shortly. |
@sophokles73 Maybe you should add the thing about the copyright headers to the contributors.md file as well? :) Regarding the exceptions, I highly appreciate (as a developer when using Californium) that I get a more appropriate message out rather than just for example "Null pointer exception". A stack trace is soooo much more useful if no other exception is thrown. For future work, I would suggest that you go by the convention of providing the Throwable object to the logger so it can print the stack trace (if any). |
@martinmine This time I run the tests using a single thread sending 1000 get requets and calculating delay on every response in approx nano time precision with the same machine mentioned above |
californium-proxy/pom.xml
Outdated
<httpcomponents.version>4.2.5</httpcomponents.version> | ||
<httpcomponents.version.lowerbound>4.2</httpcomponents.version.lowerbound> | ||
<httpcomponents.version.upperbound>5</httpcomponents.version.upperbound> | ||
<httpasyncclient.version>4.1.3</httpasyncclient.version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I have done some research regarding already approved CQs for HttpComponents artifacts at Eclipse. It seems that using version 4.1.2 of the async client will induce the least effort regarding dependencies while still being sufficiently up to date. So please change the version to 4.1.2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we will then need to make a lot of additions to the maven bundle plugin configuration in order to specify the required versions of packages to import. Sadly but truly it seems that the arbitrary HttpComponents artifacts do not contain separate sub-trees of packages which would allow us to use some reasonable wild cards but instead contain a wild mix of complementary packages at all levels of the package hierarchy (sigh). I will take take of that once this PR is integrated, though, so you do not need to bother ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -0,0 +1,56 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2017 NTNU Gjøvik and others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks good 👍
@vikram919 Thanks for your investigation, did you run it without the changes from this PR as well? |
@martinmine yes, I run it without changing anything in the current pull request. |
@vikram919 Sorry, if I was unclear. Did you run your benchmark on the head of the branch |
@martinmine seems like it is twice the values taken for the current PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, now we will need to wait for the CQs being approved by the Eclipse IP team. Then I can merge the PR.
Thanks for contributing and your patience :-)
@vikram919 Thats awesome! Thanks a lot for looking into this! |
@martinmine can you please squash your changes into one or two commits, e.g. one adapting the logging and the other implementing the improvements? |
@sophokles73 Done. I squashed it into one commit as I had commits between log-related changes that I didn't want to start mess with. Hope this is fine. |
@martinmine |
This commit improves the performance of californium-proxy. The changes are summarized as follows: - Proper use of log formatting. - Avoid spawning two threads for processing incoming requests. - Outgoing HTTP requests are now using the Apache HttpAsyncClient. - Prevent race conditions where concurrent HTTP requests may use the same Endpoint for CoAP requests where the message body might get inter-mixed with other concurrent messages. This is solved by using a pool of EndpointManagers across requests. Signed-off-by: martinmine <martin_mine@hotmail.com>
@sophokles73 Thanks. Do you think it looks better now? |
Excellent 👍 |
@martinmine |
@vikram919 are you talking about this? https://github.com/martinmine/californium/blob/8c0fbe3cf92d99a3e6e3385471fdd662b41edea7/californium-proxy/src/main/java/org/eclipse/californium/proxy/resources/ProxyCoapClientResource.java#L78 Otherwise, I use the proxy example in the current master. |
@martinmine |
@vikram919 Nope. The goal of my project was to proxy HTTP requests using CoAP, so I have not looked into that. |
@vikram919 But thanks, you gave me some ideas for some more things I can discuss in my thesis :) |
@martinmine |
@vikram919 I see. One problem might be how we use the endpoint pooling to avoid the race condition I mentioned earlier. If you want to discuss this more, we can take it somewhere else as it goes beyond the scope of this PR (maybe on Twitter or whatever else you can use for IM?) |
@martinmine |
This is another submission of PR #474 which targets the 2.0.x branch instead of the master branch in addition to support Java versions prior to Java 8. I will paste the original text from #474 here:
With this PR, the stability and throughput of the californium-proxy gets significantly improved:
To benchmark the impact of these performance optimizations, I send as many requests through a http/coap/http pipeline for 5 minutes towards a local nginx server:
With the current master, I get an average request throughput of 2.7ms (std.dev 2.5ms), with the changes propsed in this PR: 2.1ms (std.dev 1.01ms). This can be further improved by scaling down the threading model in Californium. Currently, each request is captured in a networking thread, which is then queued to a "protocol stage thread" which will do the actual packet processing. Messages sent back are also running on their own thread. This leads to each message being passed through 4 different threads (2 additional in the current master) which introduce delays where a message is picked up by the next thread, and limits cache-hit rate for threads. Some of these threads could have been taken care of at a lower level, both simplifying application design and performance. However, this goes beyond the scope of this PR.