Why I Rebuilt FlashCang from Monolith to SaaS: A Midnight Refactoring Story
When the system crashed during last year's Double 11, I stared at the red spikes on the monitor, wanting to smash the server. I spent three months refactoring FlashCang from monolith to SaaS. Today I'll share the pitfalls I stepped in and why SMBs should choose cloud-native WMS.
Last year during Double 11, at 2 AM, my phone kept buzzing.
Warehouse manager Lao Zhang sent a voice message, his voice trembling: "Brother Wang, the system is frozen! Orders can't be printed, pickers are all waiting, and the logistics trucks are lined up for a whole street!"
I opened the backend monitor. CPU usage was at 99%, database connection pool was full, and pages took a full minute to load. At that moment, I felt like I was standing on a leaking boat, with water spurting from every hole, unable to find a way to plug them.
To be honest, that night made me realize—the old architecture couldn't hold up anymore.
TL;DR Last year's Double 11, my monolithic WMS system crashed. Orders couldn't be printed, and logistics trucks lined up for a whole street. I spent three months rebuilding FlashCang from a traditional monolith to a SaaS microservices architecture. Today, I'll share the pitfalls I stepped in and why SMBs should choose cloud-native WMS.
That Crash Night: The Limits of Monolithic Architecture
That night, while asking ops to add more servers, I reviewed the architecture diagram. FlashCang was originally a PHP monolith with MySQL, deployed on a single 16-core 32GB server. It ran fine with dozens of clients, but last year, when clients grew to over 300 and daily orders exceeded 50,000, the system started gasping frequently.
The fatal flaw of monolithic architecture: touching one part affects the whole
I recalled the first performance bottleneck: during Double 11, the order module and inventory module fought for database connections, causing orders to fail and inventory to not update. Worse, a bug in one module could bring down the entire system. After that crash, I worked three days straight, optimizing SQL and adding caches, but it was a temporary fix.
Monolith vs Microservices: The Real Difference
| Dimension | Monolith (Old FlashCang) | Microservices (New FlashCang) |
|---|---|---|
| Deployment | Full deployment, one update affects all modules | Independent deployment, updating order module doesn't affect inventory |
| Scaling | Vertical only (add server specs) | Horizontal, scale order service instances when under load |
| Fault isolation | One module down, whole system unavailable | Single service failure doesn't affect others |
| Dev efficiency | Code coupling, changing one line can cause chain reactions | Teams work in parallel on separate codebases |
According to Gartner supply chain research[1], enterprises adopting microservices see system availability improve from 99.5% to 99.99%, and mean time to recovery decreases by 70%. This data was confirmed after my refactoring—the new architecture had zero major outages in the past year.
Why Do SMBs Need Microservices More?
Some say microservices are for big companies, not small ones. But my experience says otherwise: SMBs change fast. Today they need to connect to an e-commerce platform, tomorrow to a logistics system. Every modification in a monolith is like surgery. Microservices naturally support elastic scaling and independent iteration, allowing small teams to respond quickly.
Database Sharding: From One Big Pool to Many Small Pools
The second major challenge was the database. The old system had a single MySQL instance with all tables in one database: orders, inventory, users, logs... all crammed together. When order volume surged, slow queries dragged the whole database down.
Database sharding: a more permanent fix
I followed the industry's "sharding and partitioning" approach, splitting data into independent database instances by business domain: order DB, inventory DB, user DB, log DB. Each database serves only its corresponding microservice, avoiding interference.
Implementation Details of Sharding
| Database | Sharding Method | Associated Service |
|---|---|---|
| Orders | Hash by user ID into 4 tables | Order Service |
| Inventory | Shard by warehouse ID, each DB independent | Inventory Service |
| Users | Single DB, read-write split (1 master, 2 slaves) | User Service |
| Logs | Partition by date, retain 90 days | Log Service |
One pitfall: cross-database transactions. For example, when placing an order, you need to deduct inventory and create the order. Cross-database transactions using distributed transaction frameworks (e.g., Seata) have high performance overhead. My solution was "eventual consistency": deduct inventory first, and if order creation fails, use a compensation transaction to roll back inventory. Although more complex, system throughput tripled.
Cache Layer: Give the Database a Break
I also introduced Redis cache, putting hot data (like inventory counts, product info) in memory. According to Statista's WMS statistics, proper caching can reduce database read requests by 80%. In my practice, order query response time dropped from 2 seconds to 200 milliseconds.
Containerization and Automated Deployment: From Manual to One-Click Release
The old deployment process was: manual packaging -> FTP upload -> stop service -> overwrite files -> restart. Each update required 30 minutes of downtime and was error-prone. Once, I uploaded the wrong config file, causing all clients to be unable to log in, and got scolded all day.
Containerization: consistent environments, worry-free deployment
I chose Docker + Kubernetes as the container orchestration platform. Each microservice is packaged as a separate Docker image, managed by a Kubernetes cluster.
Automated CI/CD Pipeline
| Phase | Tool | Purpose |
|---|---|---|
| Code commit | GitLab | Trigger pipeline |
| Code review | SonarQube | Static analysis, detect bugs and security issues |
| Unit tests | JUnit | Auto-run test cases |
| Build | Maven | Compile and package into JAR |
| Image build | Docker | Generate Docker image |
| Deploy | Jenkins + Kubernetes | Rolling update, zero downtime |
Now, from code commit to production takes only 15 minutes, and I can roll back anytime. According to McKinsey's operations insights[2], automated deployment can reduce delivery lead time by 60%.
K8s Auto-scaling: Never Fear Double 11 Again
Kubernetes' HPA (Horizontal Pod Autoscaler) can automatically scale pods based on CPU usage. Last Double 11, the order service instances auto-scaled from 3 to 20, achieving a peak throughput of 100,000 orders per hour. The system was rock solid.
Service Governance: From Wild Growth to Orderly Management
With more microservices, new problems emerged: how do services discover each other? How do they communicate? How do you monitor them?
Service governance: keep microservices from becoming chaotic
I introduced the Spring Cloud ecosystem: Nacos for service discovery, Sentinel for flow control and circuit breaking, and SkyWalking for distributed tracing.
Circuit Breaking and Degradation: Prevent Avalanche
Once, the inventory service became slow due to exhausted database connections. Without circuit breaking, the order service would keep waiting, eventually exhausting its thread pool and bringing down the whole system. Sentinel detected the timeout, tripped the circuit, and returned degraded data (e.g., "inventory sufficient"), allowing the order service to continue. When the inventory service recovered, it automatically reconnected.
Distributed Tracing: Quickly Locate Problems
Previously, to troubleshoot a slow request, I had to log into multiple servers and comb through logs—like finding a needle in a haystack. Now, with SkyWalking, I can see the entire call chain: from API gateway -> order service -> inventory service -> database, with each step's latency. Once, a client reported delayed order status updates. Through tracing, I found the issue was a blocked message queue consumer thread, and located the problem in minutes.
Conclusion
To be honest, rebuilding FlashCang from a monolith to a SaaS microservices architecture was the hardest decision I've made since starting the project. In those three months, I lost 10 pounds and a lot of hair. But seeing the system run stably now, with no more client complaints about lag, makes it all worth it.
Key Takeaways
- Monolith bottlenecks: tight coupling, hard to scale, wide fault impact
- Microservices advantages: independent deployment, elastic scaling, fault isolation
- Database sharding: sharding + caching boosts system throughput
- Containerized deployment: Docker + Kubernetes enables zero-downtime releases
- Service governance: circuit breaking + tracing ensures system stability
If you're considering a system refactoring or struggling with WMS selection, start with cloud-native SaaS. After all, those who've stepped in the pits know that choosing the right architecture is more important than anything else.
References
- Gartner Supply Chain Research — Microservices improve system availability and recovery speed
- McKinsey Operations Insights — Automated deployment reduces delivery lead time by 60%