I'm not seeing any performance difference between blocking code and non-blocking code


(koz) #1

I’m trying to do a load test on my application using Apache JMeter. I’m firing off 500 requests like this:

http://localhost:9001/person/1
http://localhost:9001/person/2

http://localhost:9001/person/500

The problem is I’m not seeing any performance difference between blocking code and non-blocking code. Both approaches can handle about 100 requests per second.

This is my blocking code:

public Result getPerson(Integer id) {
	ObjectNode result = Json.newObject();
	Person person = null;

	person = jpaApi.withTransaction(entityManager -> {
		Query query = entityManager.createQuery("select p from Person p where id = :id");
		query.setParameter("id", id);
		return (Person) query.getSingleResult();
	});

	return ok(person);
}

And the non-blocking code I got from here https://github.com/playframework/play-java-jpa-example , and I simply added a method to find a person by id.

Both blocking and non-blocking approaches can handle about 100 requests per second. Am I doing something wrong? Could it be a limitation with JMeter? I’m using play 2.6.9 by the way.


(Bwbecker) #2

I think you need to be more explicit about your “non-blocking” code. Which specific files did you change? And “simply added a method” is kinda vague…


(koz) #3

This is the code I added to the JPAPersonRepository

private Person retrieve(EntityManager em, Integer id) {
	Query query = em.createQuery("select p from Person p where id = :id");
	query.setParameter("id", id);
	return (Person) query.getSingleResult();
}
public CompletionStage<Person> find(Integer id) {
	return supplyAsync(() -> wrap(em -> retrieve(em, id)), executionContext);
}

Everything else is the same

edit:

I also addded this code to the controller

public CompletionStage<Result> getPerson(Integer id) {
	return personRepository.find(id).thenApplyAsync(p -> {
		return ok(Json.toJson(p));
	}, ec.current());
}

(Adam Lane) #4

Many years ago I did some load testing when I was new to play and didn’t yet know that dev mode is single threaded. So reminder to anyone new that you have remember to load test in prod mode. If you are blocking in code, your threadpool settings may be compensating…I believe default play does one thread per available core. Also, just because something is technically blocking doesn’t mean it is significantly blocking. I am not really surprised that a primary key index query returning one result on a modern dev server doesn’t show up much…its when you unintentionally start having more long running queries going than you have available threads that you get into trouble.


(Marcos Pereira) #5

Well, that is because of async/non-blocking is not necessarily about performance, but about better usage or resources, resilience, responsiveness, and scalability. See the Reactive Manifesto. Given that, how are other numbers being impacted in each case? For example, CPU & memory usage, 99 percentile latency, etc.?

You should also consider tuning the thread-pool/connection-pool. Consider to make it as small as possible, for example, and see how different sizes and configurations impacts your application. A good read about connection pool size: HikariCP: About Pool Sizing.

Finally, do some profile so that you can see where your application is spending time.

Best.


(koz) #6

Thank you Adam for the info. I suppose it was a bit naive of me to expect a simple test like this to show much difference lol. And also the dev mode thing.

Thank you Marcos, I’ll study this material.