针对单文件服务场景优化Windows平台下Apache 2.4的性能
Background
I run a non-profit charity project's webpage that’s pure HTML/CSS. The HTML is fetched from a backend Tomcat server via Apache's ProxyPass using the AJP protocol. The page has no images, and CSS resources are served from another server—so we only need to handle HTML requests.
Current Apache MPM config uses 1100 threads per child process. It runs fine when requests per second (RPS) is under 50, but performance drops sharply once RPS exceeds that, even though server memory and CPU are still within normal limits.
Questions
- Is it reasonable to deploy a second Apache instance on the same server and set up load balancing? Are there any limitations to running a single Apache instance?
- Would generating static HTML pages and serving them directly from Apache (bypassing the Tomcat proxy) improve performance? (Note: Tomcat runs smoothly under high load.)
- What other typical performance tuning suggestions are suitable for this scenario?
Tomcat runs on port 8080, with AJP communication to Apache. Its Connector config is:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="60000" redirectPort="8443" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
1. Dual Apache Instances + Load Balancing: Is It Worth It?
Running a second Apache instance on the same server for load balancing is technically doable, but it’s probably not the most efficient first move here. Let’s break it down:
- Single Instance Limitations: Apache’s MPM (especially
eventorworker) does have caps on threads/processes, but 1100 threads per child is already extremely high. Your sharp performance drop at 50 RPS suggests the bottleneck isn’t just raw thread count—it’s likely in how Apache handles AJP proxy connections, connection pooling, or misconfigured MPM settings. - Dual Instance Caveats: Spinning up a second instance splits available resources (even if CPU/memory are free) and adds extra complexity for config, monitoring, and maintenance. Unless your single instance is hitting hard limits like insufficient file descriptors (check with
ulimit -n), this is overkill for your current RPS threshold.
I’d recommend tuning your existing Apache instance first before adding a second one.
2. Static HTML Bypass: Will It Help?
Absolutely—even though Tomcat runs smoothly under high load, cutting out the proxy layer entirely for static content will reduce latency and free up Apache’s proxy threads for other requests. Here’s why:
- Every proxy request to Tomcat adds overhead: connection setup (even with pooling), request forwarding, and response retrieval. Serving static HTML directly from Apache skips all that extra work.
- Since your content is pure HTML/CSS (and CSS is already hosted elsewhere), if the HTML doesn’t change frequently, generating static versions is a no-brainer. You could set up a cron job or build process to periodically pull the latest content from Tomcat and save it as static files in Apache’s document root.
- If you need occasional dynamic HTML, use Apache’s
mod_cacheinstead of full static generation—it caches Tomcat’s responses so repeat requests don’t hit the backend.
3. Additional Tuning Suggestions
Here are targeted tweaks for your setup:
Apache Proxy Tuning
- Enable AJP Connection Pooling: By default, Apache might open a new AJP connection for every request, which is inefficient. Use
mod_proxy_ajpwith pooling settings:
Adjust<Proxy ajp://localhost:8009> ProxySet connectiontimeout=5 timeout=30 keepalive=On max=100 </Proxy>maxto match a reasonable number of concurrent connections Tomcat can handle (start with 50-100, aligned with your RPS threshold). - Align Proxy Timeouts: Make sure proxy timeouts match Tomcat’s
connectionTimeout(60s in your config) to avoid unnecessary connection drops.
Apache MPM Tuning
- If using
workeroreventMPM, split threads across multiple child processes instead of cramming 1100 into one. Most OSes struggle with that many threads in a single process—try 4 child processes × 250 threads = 1000 total threads. This improves stability and resource utilization. - Set
MaxConnectionsPerChildto a reasonable number (like 10000) to prevent memory leaks in long-running child processes (avoid setting to 0 for production).
Tomcat AJP Tuning
- Adjust the AJP Connector’s
maxThreadsandacceptCountto handle more concurrent connections:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" maxThreads="200" acceptCount="100" connectionTimeout="60000" tcpNoDelay="true" />maxThreadscontrols concurrent AJP requests Tomcat can handle,acceptCountis the pending request queue length, andtcpNoDelay="true"reduces latency for small HTML responses.
Other Quick Wins
- Enable Apache’s
mod_deflateto compress HTML responses—this cuts bandwidth usage and speeds up load times for end users. - Check Apache’s access/error logs for clues about the performance drop (e.g., long-running requests, connection errors).
- Verify file descriptor limits are sufficient for Apache and Tomcat—use
ulimit -nto check, and increase if needed (most OSes default to 1024, which is too low for 1100 threads).
内容的提问来源于stack exchange,提问作者rosemeyer2

