多虚拟环境下Gunicorn Worker数量计算及多站点场景优化问询
Let's break this down step by step—since the official formula is built for single-site scenarios, we need to adapt it to your setup of 10 small sites each handling 5k UV.
First, Context on the Official Formula
Gunicorn’s recommended
(2 × $num_cores) + 1is a starting point for single, resource-heavy sites. It assumes the site is the server’s primary workload, using an extra worker to absorb traffic spikes. But applying this blindly to each of your 10 sites would give you 90 total workers—this would cripple your server with context-switching overhead and resource starvation, which is the opposite of avoiding waste.
Key Details for Your Scenario
- Your server has 4 physical cores (8 logical threads: note that hyper-threading helps with CPU-bound tasks, but Django/Gunicorn workers are mostly IO-bound, so we’ll prioritize physical cores for our baseline).
- 10 sites × 5k UV = 50k total UV, but most requests will be static assets (CSS, JS, images) handled directly by Nginx. Django only processes dynamic requests (database calls, template rendering, etc.), which make up a smaller portion of traffic.
- You need to reserve CPU for system processes, Nginx, and Supervisor—don’t allocate 100% of cores to Gunicorn.
Practical Calculation & Adjustment Strategy
1. Set a Total Worker Baseline
Start by reserving 1 physical core (~25% CPU) for system overhead. That leaves 3 physical cores for Gunicorn. For IO-bound workloads like Django, a safe total worker count is 2 × available physical cores (since workers spend most of their time waiting, not using CPU). So:Total initial workers = 2 × 3 = 6
This avoids overwhelming the server while giving you enough capacity to handle dynamic requests across all sites.
2. Distribute Workers to Sites
Since all sites have similar UV counts:
- Start with 1 worker per site for your 6 highest-traffic (or most dynamic) sites.
- For the remaining 4 sites, start with 1 worker each only if CPU usage stays below 70-80%. If CPU spikes, reduce workers on low-traffic sites or reallocate extra workers to sites with more dynamic content (e.g., frequent database queries, user interactions).
- Keep the total number of workers across all sites between 6-8 to stay within CPU limits.
3. Optimize to Avoid Waste
- Use Gunicorn’s
--preloadflag: This loads the Django code once before spawning workers, cutting down on memory usage across multiple workers per site—critical for running 10 sites without eating all your RAM. - Tune
worker_connections: The default 100 is more than enough for small sites—no need to increase it unless you see connection queueing. - Let Nginx handle all static assets: Configure Nginx to serve
STATIC_ROOTandMEDIA_ROOTdirectly, so Django/Gunicorn only processes dynamic requests.
4. Monitor & Refine
Keep an eye on these metrics to adjust worker counts over time:
- Server CPU usage: Target 70-80% max—if it’s consistently lower, you can add a few more workers. If it’s higher, reduce workers on low-priority sites.
- Gunicorn request queue: Use tools like
gunicorn --statsdor server monitoring software—if requests are queuing up, add a worker to that specific site. - Django response times: Slow responses might mean not enough workers, but could also signal a bottleneck elsewhere (database, cache)—don’t just add workers without checking the root cause.
Final Takeaway
Forget applying the single-site formula to each site. Instead, start with a total worker count tied to your available physical cores (minus system overhead), distribute them based on site load, and refine with real-world monitoring. For your setup, 6-8 total workers across 10 sites is a safe starting point—you can tweak up or down as you observe traffic patterns.
内容的提问来源于stack exchange,提问作者Peter R.

