
ZOPE / CPS / CPSSkins - HIGH PERFORMANCE (v0.3)

Author: Jean-Marc Orliaguet
Last modified : 03-10-25
Acknowledgements: Thanks to Sbastien Georget for suggesting the 
RAM-cache improvements on CPSSkins.


Description:
This document describes how to achieve high performance content 
delivery on a Zope / CPS / CPSSkins installation.


References:  
High Performance Zope ( 
http://matthardy.us/mywiki/HighPerformanceZope )
Nuxeo CPS ( http://www.nuxeo.org/cps )
CPSSkins ( http://www.ita.chalmers.se/~jmo/CPS )


Background:
Advanced content management systems like CPS provide a lot of 
functionality but they also consume a lot of computer power in 
terms of CPU and memory usage. Each page being displayed requires 
a new computation. Using a theme management system  like CPSSkins 
on top of CPS adds a lot of flexibility to it but it also 
increases computation requirements. 

The typical number of requests per second that can be achieved by 
communicating directly to a Zope server are represented in this 
table:

Platform
Zope / CMF1.3
CPS2
CPS2 + CPSSkins
Requests per second
20
3
1.8


The tests were run on a Mobile Intel(R) Pentium(R) III CPU - M  
1333MHz
on Linux using ApacheBench: 
 

# ab -n 20 http://localhost:8080/...


The same page served statically on the Apache web server could 
easily reach 1000 to 2000 requests / second.


One solution to achieve comparable high performance results on a 
CPS site is: 
to let Apache cache some of the documents delivered by the Zope 
server.
To let the Zope server cache often served objects in the RAM. 

This solution involves the use of 4 main components:

Zope + CMF Caching Policy Manager + Apache mod_proxy (with cache) 
+ Zope RAM-Cache manager.


Software used:
Zope 2.6.1 ( http://www.zope.org ) 
Apache 1.3.28 ( http://www.apache.org )
CPS 2.2b2 ( http://www.nuxeo.org ) 
CPSSkins >= 1.8o ( http://www.ita.chalmers.se/~jmo/CPS )


A. Proxy-caching 

The caching proxy stores documents on the Apache server.

a) Install and configure Apache with mod_proxy enabled
b) Install Zope + CPS + CPSSkins
c) In the Apache main configuration section add the following 
lines:


ProxyRequests On
CacheRoot "/var/www/proxy"
CacheSize 5
CacheGcInterval 4
CacheMaxExpire 24
CacheLastModifiedFactor 0.1
CacheDefaultExpire 1
CacheForceCompletion 100


The cache root directory must be writable by the Apache process 
(usually 'nobody' or 'apache' )

d) In the Apache virtual host configuration section add the 
following lines to the Virtual Host configuration section.


ProxyPass /cps 
http://localhost:8080/VirtualHostBase/http/localhost:80/cps/Virtua
lHostRoot/_vh_cps

ProxyPassReverse 
http://localhost:8080/VirtualHostBase/http/localhost:80/cps/Virtua
lHostRoot/_vh_cps  /cps


... provided that the CPS instance is running on 
http://localhost:8080/cps and that the Apache server runs on 
http://localhost:80 
Replace localhost with the actual  server name. 
Remove _vh_... if the site's initial URL is /  

  
e) Add a "Virtual Host Monster" (VHM) at the root of the CPS 
instance

f) Add a "CMF Caching Policy Manager" at the root of the CPS 
instance
. with the following values:



Policy ID : 		authenticated
Predicate: 		python:member!=None
Mod. Time: 		content/modified
Max age (secs): 	0
No-cache?: 		[x]
No-store?: 		[ ]
Must-revalidate?: 	[ ]

Policy ID : 		anonymous
Predicate: 		python:member==None
Mod. Time: 		content/modified
Max age (secs): 	300
No-cache?: 		[ ]
No-store?: 		[ ]
Must-revalidate?: 	[ ]


This will tell Apache to cache anonymous pages with a lifetime of 
300 seconds (5 minutes) and to never cache authenticated pages 
(which would otherwise constitute a potential security issue)



B. RAM-Caching 

The RAM-cache stores objects in memory on the Zope server.
Objects that are often called can be cached (e.g. Python scripts, 
DMTL, ... ).
The method that is most often called in CPSSkins is the 
'render()' method. It is used to render all UI elements, and the 
dynamic stylesheets.

Installation.

a) At the site root of the CPS instance add a 'RAM Cache Manager'.
b) Call it 'ramcache'
c) Customize* the python script called 
'portal_skins/CPSSkins/cpsskins_render' 


* If the 'Cache' tab is already present (as in CMF1.4), then you 
do need to customize the script. Associate it directly to the 
RAM-cache instead. 

d) associate the (customized) script to the RAM-cache 




e) Make sure that AUTHENTICATED_USER is listed among the "REQUEST 
variables"


IMPORTANT: For Templets whose content depend on the value of the 
current URL (e.g. action boxes) add PATH_TRANSLATED  variable to 
the list of request variables. Add any extra variable passed in 
the URL that may influence the way in which Templets are 
displayed. 

If your site can be accessed through different host addresses 
(e.g. through a rewrite rule) add  SERVER_URL to the list of 
REQUEST variables.

Create RAM-caches with minimal lists of variables to increase the 
number of cache hits.

Cacheable elements
Starting from version 1.8o of CPSSkins,  all UI elements can be 
cached on an individual basis. If an element is not displayed as 
it is expected, then deselect the 'Cacheable' option or decrease 
the cache cleanup interval. The stylesheets (styles) are cached 
by default.



Results:

Proxy-cache:
The typical number of requests per seconds was increased from 2  
to 1000 by using the proxy cache. (see benchmarks below) This is 
effective for anonymous users only.

RAM-cache:
Caching the 'cpsskins_render' method used in CPSSkins greatly 
improves rendering times. This is effective for both anonymous 
and authenticated users.

for the dynamic stylesheets (cpsskins_css/custom.css) 
improvements are by a threefold factor -- from typically 10 rps 
to 30 rps

pages are rendered three to four times faster (see benchmarks 
below). 

The hits to misses ratio is typically 10:1



Benchmarks* :
* these are only approximate benchmarks.

Tools: 
BenchmarkTimer ( http://www.zopelabs.com/cookbook/1019080479 )
ApacheBench ( http://www.apache.org )

A) CPS3 + CPSSkins - Without RAM Cache - without Proxy Cache
     
rendering time : 0.49s  (see appendix 1)


B) CPS3 + CPSSkins - With RAM Cache - without Proxy Cache

rendering time : 0.16s (see appendix 2)


C) CPS2 + CPSSkins - Without RAM Cache - with Proxy Cache
/usr/sbin/ab -n 1000 -c 1000 ...

requests per second : 500 (see appendix 3)


APPENDIX 1 - CPS3 + CPSSkins1.8n - Without RAM Cache - without 
Proxy Cache


 Profiling lvl:-1 cpsskins_main_template:
 t       mark       delta t
 0.0000: Start      + 0.0000
 0.0200: CPSSkins: banner START + 0.0200
 0.0300: CPSSkins: banner END + 0.0100
 0.0400: CPSSkins: welcome box START + 0.0100
 0.0700: CPSSkins: welcome box END + 0.0300
 0.0700: CPSSkins: search box START + 0.0000
 0.0800: CPSSkins: search box END + 0.0100
 0.0900: CPSSkins: flags START + 0.0100
 0.1000: CPSSkins: flags END + 0.0100
 0.1100: CPSSkins: Action bar START + 0.0100
 0.1700: CPSSkins: Action bar END + 0.0600
 0.1800: CPSSkins: level1 START + 0.0100
 0.2100: CPSSkins: level1 END + 0.0300
 0.2100: CPSSkins: level2 START + 0.0000
 0.2300: CPSSkins: level2 END + 0.0200
 0.2500: CPSSkins: Boxes 3 START + 0.0200
 0.2800: CPSSkins: Boxes 3 END + 0.0300
 0.2900: CPSSkins: Admin box START + 0.0100
 0.3300: CPSSkins: Admin box END + 0.0400
 0.3300: CPSSkins: box group 0 START + 0.0000
 0.3700: CPSSkins: box group 0 END + 0.0400
 0.3700: CPSSkins: Breadcrumbs START + 0.0000
 0.3800: CPSSkins: Breadcrumbs END + 0.0100
 0.3900: CPSSkins: Main Content START + 0.0100
 0.3900: CPSSkins: Main Content END + 0.0000
 0.4000: CPSSkins: Last modified START + 0.0100
 0.4100: CPSSkins: Last modified END + 0.0100
 0.4100: CPSSkins: Action box START + 0.0000
 0.4400: CPSSkins: Action box END + 0.0300
 0.4400: CPSSkins: Group 2 START + 0.0000
 0.4800: CPSSkins: Group 2 END + 0.0400
 0.4900: Stop       + 0.0100
















APPENDIX 2 - CPS3 + CPSSkins1.8n - With RAM Cache - without Proxy 
Cache


 Profiling lvl:-1 cpsskins_main_template:
 t       mark       delta t
 0.0000: Start      + 0.0000
 0.0200: CPSSkins: banner START + 0.0200
 0.0200: CPSSkins: banner END + 0.0000
 0.0300: CPSSkins: welcome box START + 0.0100
 0.0300: CPSSkins: welcome box END + 0.0000
 0.0400: CPSSkins: search box START + 0.0100
 0.0400: CPSSkins: search box END + 0.0000
 0.0500: CPSSkins: flags START + 0.0100
 0.0500: CPSSkins: flags END + 0.0000
 0.0600: CPSSkins: Action bar START + 0.0100
 0.0600: CPSSkins: Action bar END + 0.0000
 0.0700: CPSSkins: level1 START + 0.0100
 0.0700: CPSSkins: level1 END + 0.0000
 0.0700: CPSSkins: level2 START + 0.0000
 0.0800: CPSSkins: level2 END + 0.0100
 0.0900: CPSSkins: Boxes 3 START + 0.0100
 0.0900: CPSSkins: Boxes 3 END + 0.0000
 0.1000: CPSSkins: Admin box START + 0.0100
 0.1000: CPSSkins: Admin box END + 0.0000
 0.1000: CPSSkins: box group 0 START + 0.0000
 0.1000: CPSSkins: box group 0 END + 0.0000
 0.1100: CPSSkins: Breadcrumbs START + 0.0100
 0.1100: CPSSkins: Breadcrumbs END + 0.0000
 0.1200: CPSSkins: Main Content START + 0.0100
 0.1200: CPSSkins: Main Content END + 0.0000
 0.1300: CPSSkins: Last modified START + 0.0100
 0.1300: CPSSkins: Last modified END + 0.0000
 0.1400: CPSSkins: Action box START + 0.0100
 0.1400: CPSSkins: Action box END + 0.0000
 0.1500: CPSSkins: Group 2 START + 0.0100
 0.1500: CPSSkins: Group 2 END + 0.0000
 0.1600: Stop       + 0.0100
APPENDIX 3 - CPS2 + CPSSkins - Without RAM Cache - with Proxy 
Cache
This is ApacheBench, Version 1.3d <$Revision: 1.1.1.1 $> apache-1.3
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, 
http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, 
http://www.apache.org/

Benchmarking bell.ita.chalmers.se (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Finished 1000 requests
Server Software:        Zope/(Zope                                
         
Server Hostname:        bell.ita.chalmers.se
Server Port:            80

Document Path:          
/lanksida/webapplicationdocument_list?sortby=category
Document Length:        34666 bytes

Concurrency Level:      1000
Time taken for tests:   1.689 seconds
Complete requests:      1000
Failed requests:        0
Broken pipe errors:     0
Total transferred:      35159779 bytes
HTML transferred:       34773239 bytes
Requests per second:    592.07 [#/sec] (mean)
Time per request:       1689.00 [ms] (mean)
Time per request:       1.69 [ms] (mean, across all concurrent 
requests)
Transfer rate:          20816.92 [Kbytes/sec] received

Connnection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0     4    6.5      1    22
Processing:    29   204   42.6    214   425
Waiting:        8   203   42.6    213   424
Total:         29   208   37.8    215   445

Percentage of the requests served within a certain time (ms)
  50%    215
  66%    217
  75%    218
  80%    219
  90%    222
  95%    234
  98%    239
  99%    245
 100%    445 (last request)