CPU stuck between 95% to 100% for Standalone Jetty server - jetty

I am using Jetty to start a main class as a service. Below a extract of the code to demonstrate the problem.
Server server = new Server(8080);
ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[] {"index.html"});
resource_handler.setResourceBase(".");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] {resource_handler, new DefaultHandler()});
server.setHandler(handlers);
server.start();
server.join();
I am running this application from eclipse on a windows machine with 2 CPU.
After I start this application, I execute below program on different machine. Below code just spawns 100 concurrent threads and executes a simple http request to get the index.html page.
ExecutorService service = Executors.newFixedThreadPool(100);
for (int i = 0; i < 10000; i++) {
service.execute(new Runnable() {
public void run() {
try {
long startTime = System.nanoTime();
URL url = new URL("http://localhost:8080");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
long endTime = System.nanoTime();
System.out.println(conn.getResponseMessage() + ":" + ((endTime - startTime)/1000000) + " (ms)");
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
service.shutdown();
When I execute this program, the server's CPU immediately reaches 100% (for both cores).
I have tried modifying maxThreads, acceptorThreads, buffer size parameters as suggested in https://wiki.eclipse.org/Jetty/Howto/High_Load.
But even then, the CPU still remains stuck between 95-100 for high load.
So the question here is, is there any configuration that I am missing to minimize the CPU? Or this is expected and can only be rectified by adding more CPUs or clustering the services?
Thanks for your help.

You state you do run the ExecutorService part on a different machine, but the URL is http://localhost:8080. That's a no-no in load testing.
Some advice:
Don't have the Client Load and the Server Load on the same machine (don't cheat and attempt to put the load on 2 different VMs on a single physical machine)
Use multiple client machines, not just 1 (when the Jetty developers test load characteristics, we use at least 10:1 ratio of client machines to server machines)
Don't test with loopback, virtual network interfaces, localhost, etc.. Use a real network interface.
Don't test with unrealistic load scenarios. A real-world usage of your server will be a majority of HTTP/1.1 pipelined connections with multiple requests per physical connection. Some on fast networks, some on slow networks, some even on unreliable networks (think mobile)
If you must use HttpURLConnection, understand how it manages its HTTP version + connections (such as keep-alive or http/1.1 close), and make sure you read the response body content, close the streams, and disconnect() the connection.
Finally, be sure you are testing load in realistic ways.

Related

Example of embedded Jetty and using Micrometer for stats (without Spring)

I am new to using Micrometer as a metrics/stats producer and I am having a hard time in getting it configured correctly with my Jersey/Embedded Jetty server. I would like to get Jetty statistics added.
I already have the servlet producing stats for the JVM in a Prometheus format.
Does anyone know of a good working example on how to configure it?
I am not using SpringBoot.
The best way is to look at the Spring Boot code. For example it binds the jetty connections
JettyConnectionMetrics.addToAllConnectors(server, this.meterRegistry, this.tags);
And it uses an ApplicationStartedEvent to find the server reference.
private Server findServer(ApplicationContext applicationContext) {
if (applicationContext instanceof WebServerApplicationContext) {
WebServer webServer = ((WebServerApplicationContext) applicationContext).getWebServer();
if (webServer instanceof JettyWebServer) {
return ((JettyWebServer) webServer).getServer();
}
}
return null;
}
There are other classes that record the thread usage and SSL handshake metrics.

Jetty HTTP 2 Clients sharing same thread pool

Using Jetty 9.4.7
We are creating 2 clients using this code:
client = new HTTP2Client();
client.setIdleTimeout(-1);//disable client session timeout
client.setExecutor(httpThreadPool);
client.setConnectTimeout(connectionTimeoutMs);
try {
client.addBean(this.sslContextFactory);
client.start();
FuturePromise<Session> sessionPromise = new FuturePromise<>();
client.connect(sslContextFactory, new InetSocketAddress(this.host, this.port), new CustomSessionListener(clientInstanceName, this), sessionPromise);
this.session = sessionPromise.get(this.connectionTimeoutMs, TimeUnit.MILLISECONDS);
} catch(...
The httpThreadPool is common between the two clients. It is a ThreadPoolExecutor with core pool size 4 and max pool size 128.
The first client is created successfully. The second client fails with TimeoutException (regardless of the target servers, we even pointed them at the same server).
If we assign separate thread pools (or let the client construct its own default QueuedThreadPool) everything works fine.
Aside for an advice on the issue itself, is there any way to unwrap whatever exception is thrown when connecting the Http2 client? We tried overriding onFailure(Session,Throwable) in SessionListener, but it doesn't get there.
Thanks.
EDIT: Log excerpt on DEBUG: https://pastebin.com/MUKrw4JP

HttpClient: Connection reset after 5 minutes idle, keep-alive possible?

I'm using a HttpClient to send a SOAP request to an webservice to query some data. For some webservice parameters the execution of the webservice takes longer than 5 minutes and after 5 minutes I get an java.net.SocketException: Connection reset.
I think that the error occures because the connection idles for more than 5 minutes and then a firewall caps the connection.
Is there a way to send a keep-alive package for a http post request or something to keep the connection alive? (I need a client-side solution if possible)
If you google for HttpClient keep-alive you find a lot of topics regarding reusing a connection. In my case I only want to keep the connection alive until I get a response.
Method to execute the SOAP request:
def executeSOAPRequest(String url, String content, String soapAction, Integer timeout) {
def retVal = new SoapResponse();
PostMethod post = new PostMethod(url);
RequestEntity entity = new StringRequestEntity(content,"ISO-8859-1","ISO-8859-1");
post.setRequestEntity(entity);
post.setRequestHeader("SOAPAction", soapAction);
HttpClient httpclient = new HttpClient()
httpclient.setTimeout(timeout)
try {
retVal.httpResponse = httpclient.executeMethod(post);
retVal.httpResponseBody = post.getResponseBodyAsString();
} catch(Exception e){
... exception handling ...
} finally {
... finally stuff ...
}
return retVal;
}
Currently the HttpClient v3.1 is used.
5 minutes are an eternity in telecommunications, this days one giga can be transferred in less time, and keeping a connection idle consumes resources not only in the ending machines but in the intermediate nodes such as routers and firewalls.
So IMHO you shouldn't try to keep the connection alive for so long, especially if you don't manage the networks you are using (ie, firewalls can have their own timeouts and kill your connection), you should reduce the time the server needs to respond, or use other asynchronous communication mechanism.

How do I programmatically shut down an instance of ExpressJS?

I'm trying to figure out how to shut down an instance of Express. Basically, I want the inverse of the .listen(port) call - how do I get an Express server to STOP listening, release the port, and shutdown cleanly?
I know this seems like it might be a strange query, so here's the context; maybe there's another way to approach this and I'm thinking about it the wrong way. I'm trying to setup a testing framework for my socket.io/nodejs app. It's a single-page app, so in my testing scripts (I'm using Mocha, but that doesn't really matter) I want to be able to start up the server, run tests against it, and then shut the server down. I can get around this by assuming that either the server is turned on before the test starts or by having one of the tests start the server and having every subsequent test assume it's up, but that's really messy. I would much prefer to have each test file start a server instance with the appropriate settings and then shut that instance down when the tests are over. That means there's no weird dependencies to running the test and everything is clean. It also means I can do startup/shutdown testing.
So, any advice about how to do this? I've thought about manually triggering exceptions to bring it down, but that seems messy. I've dug through Express docs and source, but can't seem to find any method that will shut down the server. There might also be something in socket.io for this, but since the socket server is just attached to the Express server, I think this needs to happen at the express layer.
Things have changed because the express server no longer inherits from the node http server. Fortunately, app.listen returns the server instance.
var server = app.listen(3000);
// listen for an event
var handler = function() {
server.close();
};
Use app.close(). Full example:
var app = require('express').createServer();
app.get('/', function(req, res){
res.send('hello world');
});
app.get('/quit', function(req,res) {
res.send('closing..');
app.close();
});
app.listen(3000);
Call app.close() inside the callback when tests have ended. But remember that the process is still running(though it is not listening anymore).
If after this, you need to end the process, then call process.exit(0).
Links:
app.close: http://nodejs.org/docs/latest/api/http.html#server.close (same applies for)
process.exit:
http://nodejs.org/docs/latest/api/process.html#process.exit
//... some stuff
var server = app.listen(3000);
server.close();
I have answered a variation of "how to terminate a HTTP server" many times on different node.js support channels. Unfortunately, I couldn't recommend any of the existing libraries because they are lacking in one or another way. I have since put together a package that (I believe) is handling all the cases expected of graceful HTTP server termination.
https://github.com/gajus/http-terminator
The main benefit of http-terminator is that:
it does not monkey-patch Node.js API
it immediately destroys all sockets without an attached HTTP request
it allows graceful timeout to sockets with ongoing HTTP requests
it properly handles HTTPS connections
it informs connections using keep-alive that server is shutting down by setting a connection: close header
it does not terminate the Node.js process
Usage with Express.js:
import express from 'express';
import {
createHttpTerminator,
} from 'http-terminator';
const app = express();
const server = app.listen();
const httpTerminator = createHttpTerminator({
server,
});
await httpTerminator.terminate();
More recent version of express support this solution:
const server = app.listen(port);
const shutdown = () => {
server.close();
}
You can easily do this by writing a bash script to start the server, run the tests, and stop the server. This has the advantage of allowing you to alias to that script to run all your tests quickly and easily.
I use such scripts for my entire continuous deployment process. You should look at Jon Rohan's Dead Simple Git Workflow for some insight on this.

how to set connection/request timeout for jetty server?

I'm running an embedded jetty server (jetty 6.1.24) inside my application like this:
Handler handler=new AbstractHandler()
{
#Override
public void handle(String target, HttpServletRequest request,
HttpServletResponse response, int dispatch)
throws IOException, ServletException {
//this can take a long time
doSomething();
}
};
Server server = new Server(8080);
Connector connector = new org.mortbay.jetty.nio.SelectChannelConnector();
server.addConnector(connector);
server.setHandler(handler);
server.start();
I would like to set a timeout value (2 seconds) so that if handler.handle() method takes more than 2 seconds, jetty server will timeout and response to the client with 408 http code (request timeout).
This is to guarantee that my application will not hold the client request for a long time and always response within 2 seconds.
I did some research and tested it with "connector.setMaxIdleTime(2000);" but it doesn't work.
Take a look at the API for SelectChannelConnector (Jetty):
http://download.eclipse.org/jetty/7.6.17.v20150415/apidocs/org/eclipse/jetty/server/nio/SelectChannelConnector.html
I've tried to locate any timeout features of the channel (which controls incoming connections): setMaxIdleTime(), setLowResourceMaxIdleTime() and setSoLingerTime() are available it appears.
NOTE: the reason for your timeout feature not to work has to do with the nature of the socket on your operating system. Perhaps even the nature of Jetty (i've read about it somewhere, but cannot remember where it was).
NOTE2: i'm not sure why you try to limit the timeout, perhaps a better approach is limiting the buffer sizes? If you're trying to prevent denial of service...
Yes, this is possible. You could do this using DosFilter of Jetty. This filter is generally used to configure a DOS attack prevention mechanism for your Jetty web server. A property of this filter called 'MaxRequestMs' provides what you are looking for.
For more details, check this.
https://www.eclipse.org/jetty/javadoc/jetty-9/org/eclipse/jetty/servlets/DoSFilter.html