Sitemap
CodeToDeploy

Tech Insights | Careers | Jobs

🚀 We Were Tuning the Wrong Things — The Simple Fixes That Made Our Java APIs 10x Faster

3 min readFeb 12, 2026

--

Our Java APIs were slow.

Not “slightly slow.”
Painfully slow.

  • P95 latency: ~900ms 😵
  • CPU spikes under load 🔥
  • Random timeouts ⏳
  • Dev team blaming the database (of course 😅)

We spent months “optimizing.”

Then a senior engineer joined a call, looked at our setup for 20 minutes, and casually said:

“Why are you tuning symptoms instead of fixing the bottlenecks?”

Two days later…

10x faster.

Here’s what actually changed.

⚠️ Act Now or Miss 70% OFF VPN + 1TB FREE Cloud Storage!
This heavy discount won’t last forever — secure your deal today.
✅ 30-Day Money-Back Guarantee — zero risk.

👉 Get 1TB + VPN

⚠️ Mistake #1: We Were Returning Huge Payloads

Our API:

@GetMapping("/users")
public List<User> getUsers() {
return userRepository.findAll();
}

Looks innocent.

But User had:

  • Orders
  • Addresses
  • Roles
  • Audit fields
  • Relationships

Hibernate was loading everything.
We were sending megabytes per request.

✅ Fix: Use DTO + Projection

public interface UserSummary {
Long getId();
String getName();
String getEmail();
}
@Query("SELECT u.id AS id, u.name AS name, u.email AS email FROM User u")
List<UserSummary> findUserSummaries();

Response size dropped by 80%.

Latency dropped instantly. 🚀

⚠️ Mistake #2: N+1 Query Problem

We had this pattern everywhere:

List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
order.getItems().size();
}

Under load, it became:

1 query + 500 extra queries 😳

✅ Fix: Fetch Join

@Query("SELECT o FROM Order o JOIN FETCH o.items")
List<Order> findAllWithItems();

Query count went from 501 → 1.

Database CPU dropped by half.

⚠️ Mistake #3: Thread Pool Bottleneck

We were using default Tomcat threads.

Under load, requests were queuing.

✅ Fix: Tune Thread Pool

server:
tomcat:
threads:
max: 200
min-spare: 20

Throughput improved immediately.

Sometimes defaults aren’t wrong — just not optimized for your traffic.

⚠️ Mistake #4: Blocking External Calls

We were calling another service synchronously:

String result = restTemplate.getForObject(url, String.class);

Each call blocked a thread.

Under load, thread starvation happened.

✅ Fix: Timeout + Pooling

@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(3000);
factory.setReadTimeout(3000);
return new RestTemplate(factory);
}

Even better? Move slow calls async.

⚠️ Mistake #5: No Caching

We were hitting DB for data that changed once a day.

✅ Fix: Add Caching

@EnableCaching
@Cacheable("products")
public List<Product> getAllProducts() {
return productRepository.findAll();
}

API response time:

Get akash’s stories in your inbox

Join Medium for free to get updates from this writer.

450ms → 40ms ⚡

⚠️ Mistake #6: Debug Logging in Production

Yes… we had this:

logging:
level:
root: DEBUG

Under heavy traffic, logging alone was adding latency.

✅ Fix:

logging:
level:
root: INFO

CPU stabilized.

📊 The Result

Before:

  • P95 latency: 900ms
  • Throughput: 300 req/sec
  • CPU: 85%
  • DB overloaded

After:

  • P95 latency: 90ms 🚀
  • Throughput: 2,500+ req/sec
  • CPU: 45%
  • Stable under load

No massive rewrite.
No microservices migration.
No hardware upgrade.

Just fixing architectural mistakes.

🧠 What the Senior Engineer Actually Did

He didn’t tune JVM flags.

He didn’t add more servers.

He asked:

  1. Are you sending too much data?
  2. Are you running too many queries?
  3. Are you blocking threads?
  4. Are you measuring properly?
  5. Are you using defaults blindly?

Performance isn’t magic.

It’s eliminating waste.

🎯 The Real Lesson

We were optimizing at the wrong layer.

We were tuning GC…

While Hibernate was firing 500 queries.

We were tweaking heap size…

While sending 5MB JSON responses.

We were scaling horizontally…

While blocking threads on slow HTTP calls.

🚀 Final Thought

10x performance improvements rarely come from clever tricks.

They come from:

  • Fixing data access
  • Reducing payload size
  • Removing unnecessary work
  • Measuring bottlenecks honestly

Sometimes all it takes is a fresh pair of senior eyes.

And a few uncomfortable questions.

Thank you for being a part of the community

Before you go:

👉 Be sure to clap and follow the writer ️👏️️

👉 Follow us: Linkedin| Medium

👉 CodeToDeploy Tech Community is live on Discord — Join now!

Note: This Post may contain affiliate links.

--

--