The Context
yomimanga is a manga reading platform I built and run solo. At peak, it handles over 5 million requests per day. It doesn't have a devops team. It doesn't have a team at all.
This is not a flex — it's a constraint that forced every architectural decision toward simplicity and reliability. Here's what I actually built and why.
Why PHP (and Why I Don't Apologize for It)
The internet runs on PHP. 77% of websites with a known server-side language use it. The ecosystem is mature, battle-tested, and optimized for exactly the kind of request-response workload that a content platform runs.
For yomimanga's use case — reading manga chapters, user authentication, reading history, search — PHP with opcache is genuinely fast. A request that hits cache serves in under 5ms. The "PHP is slow" take comes from people who've never profiled it properly.
The real reasons I stayed with PHP: I know it deeply, the deployment story is simple, and there are no mysteries. When something breaks at 3am with 5M daily users, you want a technology you understand completely, not one that's interesting.
The Cache Layer Is the Product
At this scale, your database is not your performance story. Redis is.
Every chapter list, every metadata response, every user reading position gets a cache key. TTLs are tuned per data type — frequently-updated content gets 60 seconds, static chapter data gets 24 hours. On a normal day, cache hit rate is above 94%. The database sees a fraction of the actual traffic.
The implementation detail that matters: cache warming. When a new chapter is uploaded, I proactively warm the cache rather than waiting for the first user to hit a cold request. At 5M requests/day, "the first user takes a cold hit" means thousands of users hit cold requests simultaneously after a popular update. Warm the cache at upload time.
CDN as the First Defense
Images are the majority of bytes served by any manga platform. I do not serve images from my origin. Every image goes through CDN — cached globally, served from the edge nearest to the user.
This alone eliminates 80%+ of the data transfer load on origin servers. The bandwidth costs are predictable, the latency for users in Asia/Europe is consistent, and origin never sees an image request twice for the same file.
Database Design for Read-Heavy Workloads
Manga is fundamentally read-heavy. 95%+ of requests are reads. This shapes every schema and indexing decision.
My rules: every query that runs more than once a minute has a covering index. Read replicas for anything that doesn't need fresh data. Denormalize aggressively — a chapter list view stores pre-computed metadata rather than joining at query time. Storage is cheap; query time is not.
The query that most surprises people: reading history. You'd think "insert a row when a user reads a chapter" is trivial. At 5M daily requests, that's thousands of writes per minute. I batch reading history writes with a queue — a background worker flushes to MySQL in bulk every few seconds rather than synchronously on each request.
Monitoring Without a Team
I have no team to wake up when something breaks, so the monitoring has to wake me up directly — and only when it matters. My alerting philosophy:
- Alert on user-visible errors, not internal metrics
- Error rate above 1% for more than 2 minutes: wake me up
- Response time p99 above 500ms for more than 5 minutes: wake me up
- Everything else: log it, I'll look at it in the morning
Most monitoring setups alert on too many things. Alert fatigue means you start ignoring alerts. Two alerts that matter are worth more than twenty that might.
What I'd Do Differently
The biggest mistake was not investing in observability earlier. For the first year, I was flying blind — I knew that something was slow but not where. Adding proper query-level timing and request tracing early would have saved dozens of hours of debugging.
The thing I'm glad I didn't do: Kubernetes. I see founders reach for container orchestration at 100k requests/day. At 5M requests/day with a disciplined cache strategy and a good CDN, you don't need it. Simple deployments, well-understood infrastructure, and cache-first design will take you further than complex orchestration with less operational overhead.