← More Software Startup Field Notes

Field Note · Software startup · Japan · 2023–2026 · Case study

Stabilizing a Multi-Tenant Platform Without Risking Its Business Logic

A multi-tenant platform serving hundreds of companies and approximately 200,000 users began experiencing serious performance problems after its initial production release.

Individual users could accumulate large datasets. Under load, the application would slow down, become unresponsive, and occasionally experience outages.

The challenge was not simply to make the system faster. We needed to restore stability while protecting complex business logic already being used in production.

Stabilize first, then investigate

We reviewed application logs alongside service and database CPU, memory, and workload metrics. The evidence pointed to several interacting performance bottlenecks rather than one isolated failure.

Issues were prioritized according to their effect on users. At this stage, restoring availability mattered more than minimizing infrastructure costs.

Service and database capacity were therefore increased temporarily. This created operating headroom while permanent improvements were developed; it was not treated as the final solution.

Start where change carried less business risk

Optimization began at the database layer because application-level changes carried a greater risk of altering business behaviour.

MongoDB Atlas Performance Advisor and Performance Insights helped identify expensive query patterns, slow aggregations, and potential indexes.

AI tools were also used to interpret selected query plans and propose index candidates. These suggestions were treated as hypotheses—not production decisions. Engineers reviewed them against the real workload and considered their read, write, and storage costs before applying them.

Some heavy aggregation pipelines were simplified or replaced with indexed queries. Where appropriate, complex processing was moved to the service layer instead of making the database perform every transformation.

Protect the application before refactoring it

Before changing sensitive service code, we profiled the slow operations and strengthened the relevant unit-test coverage.

The investigation uncovered several recurring problems:

  • Repeated retrieval and processing of the same data
  • Unbounded reads instead of pagination or cursors
  • Database calls inside loops
  • Quadratic loops that could be reduced to linear processing
  • Duplicate resource-intensive method calls
  • Blocking operations on request paths
  • Thread configurations that did not match available resources
  • Objects retained longer than necessary, contributing to memory growth
  • Multiple database-client instances instead of controlled reuse

The fixes included reusing already-loaded data, introducing carefully bounded caching, paginating large reads, moving database calls out of loops, removing duplicate work, and improving algorithmic complexity.

Suitable non-critical operations were moved to asynchronous processing. Threading was adjusted according to the workload and available CPU. Virtual threads were considered for blocking I/O rather than CPU-intensive work.

Database clients were consolidated so the driver’s built-in connection pools could be configured and reused correctly.

Improve in phases—and prove each change

The changes were released incrementally rather than as one large performance rewrite.

Before-and-after metrics were recorded for each phase and shared with the client as evidence of the work. This made it possible to confirm whether an optimization improved the targeted operation, detect regressions earlier, and decide what to address next.

The practical lesson is that production performance work is rarely a search for one clever fix.

Stabilize the service, follow the evidence, protect business behaviour with tests, make bounded changes, and reassess using comparable measurements.