Accelerating Zope
This document is a copy of http://www.nexedi.org/Members/jp/faq/accelerate-zope.stx please check new versions on the original site until we find a way to mirror it automatically
We are currently hosting at Nexedi a couple of CMF based community sites with Zope as well as a commercial online shop based on CMF, MMMShop and ERP5 extensions . All these sites contain many images and files. Some files can be as big as 256 MB.
Until recently, we have had a lot of trouble with Zope performance: memory explosion (leaks?), poor Web performance, unexpected restarts, etc. In order to circumvent those issues, we first created a static directory in Apache to bypass Zope completely for big files. However, that was very unconvenient for a community site.
We probably could finally solve most issues with the setup described bellow.
What is known not to work
The following Apache config, based on the Debian suggested config for Zope, leads to poor performance:
<VirtualHost openbrick.com> DocumentRoot /home/jp/public_html/ ServerName openbrick.com ServerAlias www.openbrick.com RewriteEngine on RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^/(.*) /usr/lib/cgi-bin/Zope/VirtualHostBase/http/www.openbrick.com:80/openbrick/VirtualHostRoot/$1 [e=HTTP_CGI_AUTHORIZATION:%1,t=application/x-httpd-cgi,l] </VirtualHost>
Each time a large file is being retrieved, the Zope process RAM allocation jumps to 200MB, 300MB, 400MB, 500MB, etc... and takes all the swap until it crashes. Downloading a small file (ex. 8MB) takes up to 30 seconds between the first click on the URL in the navigator and the first answer from the Web server. If the file is bigger (ex. 40MB), it becomes simply impossible to download it. Whenever someone tries to download a big file, other users may have to wait for 1 minute to view any single page of the site.
What works better (1)
As recommended here we set up Apache in order to use ProxyPass and caching. The Apache config looks like this:
<VirtualHost openbrick.org> DocumentRoot /home/jp/public_html/ ServerName openbrick.org ServerAlias www.openbrick.org ProxyRequests On ProxyPass / http://localhost:9673/VirtualHostBase/http/www.openbrick.org:80/openbrick/VirtualHostRoot/ ProxyPassReverse / http://localhost:9673/VirtualHostBase/http/www.openbrick.org:80/openbrick/VirtualHostRoot/ </VirtualHost>
We have added to each standard_html_header:
<dtml-call "RESPONSE.setHeader('Expires', _.DateTime(_.DateTime().timeTime() + 3600).toZone('GMT').rfc822())"> <dtml-call "RESPONSE.setHeader('Last-Modified', bobobase_modification_time().toZone('GMT').rfc822())"> <dtml-call "RESPONSE.setHeader('Vary', 'user-Agent; accept-language')">
We also have setup Apache main config with caching:
CacheNegotiatedDocs CacheRoot "/var/cache/apache/proxy" CacheSize 5 CacheGcInterval 4 CacheMaxExpire 24 CacheLastModifiedFactor 0.1 CacheDefaultExpire 1 CacheForceCompletion 100
Results
The best result from this setup is that is (finaly) allows to manage large files with Zope. Clicking on a link to a file provides an instant answer from the server.
Performance if also improved a lot thanks to the caching of Zope pages by Apache. We use a 733 MHz Pentium III system (Asus CUSL2-M motherboard) with 256 MB RAM and Maxtor IDE disks. Here are some benchmarks:
ab -n1000 http://www.openbrick.org/ -> 30 rps (requests per second) ab -n1000 http://www.openbrick.org/logo.png -> 171 rps
With previous setup:
ab -n1000 http://www.openbrick.com/ -> 25 rps ab -n1000 http://www.openbrick.org/logo.png -> 30 rps The main page (http://www.openbrick.com/) is cached with a RAM cache. This explains the performance in both cases. Without RAM cache, the performance is closer to 5 rps. We tried then to use of Zope http_cache instead of ram_cache (for the front page) and removed any dependency on cookies etc. Here is the result:: ab -n1000 http://www.openbrick.org/index2.html -> 153 rps **Conclusion**: good caching strategy leads to static page like performance with Zope. **Conclusion 2**: caching is mostly useless for anything which is cookie dependent (ie. electronic commerce, personalized content, etc.). Only the RAM cache can be used in such case. **Conclusion 3**: multilingual web sites should not be cookie dependent in order to reach appropriate performance.
What works better (2)
In our case, only certain parts of the site should be cached. The use of rewrite rules on certain file extension (ex. .jpg, .tgz) is a possible solution, combined with 2 virtual sites:
- www.openbrick.org (main hub with rewrite rules and access to dynamic content)
- cache.storever.com (cache setup)
Here is an example of config file for Apache to implement this:
<VirtualHost openbrick.org> DocumentRoot /home/jp/public_html/ ServerName openbrick.org ServerAlias www.openbrick.org ServerAdmin [email protected] RewriteEngine On ProxyVia on RewriteRule ^/(.*)jpg$ http://cache.storever.com/openbrick/$1jpg [L,P] RewriteRule ^/(.*)png$ http://cache.storever.com/openbrick/$1png [L,P] RewriteRule ^/(.*)tgz$ http://cache.storever.com/openbrick/$1tgz [L,P] RewriteRule ^/(.*)gif$ http://cache.storever.com/openbrick/$1gif [L,P] RewriteRule ^/(.*)pdf$ http://cache.storever.com/openbrick/$1pdf [L,P] RewriteRule ^/(.*)gz$ http://cache.storever.com/openbrick/$1gz [L,P] RewriteRule ^/(.*)bz2$ http://cache.storever.com/openbrick/$1bz2 [L,P] RewriteRule ^/(.*) http://localhost:9673/VirtualHostBase/http/www.openbrick.org:80/openbrick/VirtualHostRoot/$1 [L,P] ProxyPassReverse ^/(.*) http://www.openbrick.org/$1 </VirtualHost> <VirtualHost cache.storever.com> DocumentRoot /home/jp/public_html/ ServerName cache.storever.com CacheRoot "/var/cache/apache/proxy" CacheSize 50 CacheGcInterval 4 CacheMaxExpire 24 CacheLastModifiedFactor 0.1 CacheDefaultExpire 1 CacheForceCompletion 100 ProxyRequests On ProxyPass / http://localhost:9673/ ProxyPassReverse / http://localhost:9673/ </VirtualHost> <VirtualHost openbrick.com> DocumentRoot /home/jp/public_html/ ServerName openbrick.com ServerAlias www.openbrick.com RewriteEngine on RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^/(.*) http://www.openbrick.org/$1 [L,P] </VirtualHost>
Results
As expected, the results are equivalent to the previous case:
- images and files are served at the speed ofApache only. Doing an ab bench on a large .tgz (ex. ab -n1000 -c100 http://... ) has no impact on Zope CPU usage (Apache jumps close to 100%).
- dynamic content is served at the speed of Zope. Doing an ab bench on a large .tgz (ex. ab -n1000 -c100 http://... ) has no impact on Apache CPU usage (Zope jumps close to 100%)
The typical performance can be summarized as follows:
- Zope 100% dynamic: 5 rps
- Zope RAM Cache: 30 rps
- Apache cached file/page: 100-400 rps
Remaining Issues
This setup still has the following issues:
- image and files are not updated instantly: if an image / file is updated, it will take an hour before it is update by the cache
- dynamic pages can not be cached by Apache: dynamic content which depends on cookies is not cached by Apache because the standard proxy mechanism (Vary header) does not take into account cookies etc.
- problems with Konqueror: page content is not always updated as it should with Konqueror. Sometimes, a document which is edited appears just as it was before. This does not happen with Mozilla.
- Language: cookie-based language selection is expensive. It should be replaced by standard Content negociation built in most browsers and multiple URL access to content. This is mostly in our case a Localizer issue.
Improving this setup
In order to improve this setup, we can think of 2 directions:
1- Better understanding of the Zope HTTP cache manager which should normally allow us to provide same performance and remove
2- Test of the Zope Proxy Cache Manager based on mod_perl which should provide caching of cookie-based dynamic content
References
Configuring Squid as an Accelerator for Zope
Zope Proxy Cache Manager based on mod perl
This document is a copy of http://www.nexedi.org/Members/jp/faq/accelerate-zope.stx please check new versions on the original site until we find a way to mirror it automatically