Genweb: 5 years
Today the Genweb project turns 5. I’m aware that I should have done this write up much more earlier because a formal introduction of the project to the community was never done due to a lot of reasons. I really think I’m in debt with the Plone community and I want to return some of the vast amount of knowledge the community provided to me. Now I think that the better way to do it is to share the knowledge from this 5 years with Genweb.
Genweb (as its name hints) is a institutional web generator. The project was born as an initiative from the Communication and Promotion Service at the BarcelonaTech University (UPC) and sponsored by the university itself. Genweb was created with two goals in mind: Provide the university community a content management tool suitable to all audiences (speaking in terms of usability) and unify the look and feel of the university web sites.
Genweb, “the infrastructure”
I will talk in later posts about Genweb “the application”, suffice it to say that through the years it was Plone 2 and 3 based and now it’s Plone 4.1 based coupled with some the most popular Plone add-ons (Dexterity, PloneFormGen, Collage, etc…) and some additional tweaks for further improve the already awesome Plone usability.
Today I want to focus in Genweb “the infrastructure” which I think is by far our best accomplishment. During the project’s 5 years of life you could say it’s been quite a success. The project is currently hosting almost 400 Plone sites, which it’s a growth rate of 80 site per year. Design the infrastructure for hosting 400 plone sites is a big challenge, so we had to make it evolve constantly and adapt it to its constant growing requirements. It started from a single physical server to the six physical server architecture that host the full system at present.
This is the actual hardware architecture of the system today:

It’s a six physical machine based system. The system specs of each server are different, depending on their role. For example, each frontend has 32GB RAM and dual quad-core CPUs. With such horse power we’ve designed an architecture that is capable to take full advantage of the machines. We have split the service in 12 twin environments.
These are the components of each environment:

Requests for each environment has the same entry point at the Pre-frontend machine which host the HTTP cache accelerators (Varnish) processes and the routing and load balancing (HAProxy) to the Frontend servers (A, B and C).
The request is processed (if not cached) by one of the tree Zope Clients. Each environment has three Zope clients each of them assigned to one Frontend machine. With this setup we have the pipeline balanced and fault tolerant at the frontend level.
The Zope clients attack a ZEO server located in one of the Backend servers. This ZEO has 35 Plone sites (Genwebs instances) at most. Each instance has its own ZODB mountpoint in its ZEO server for easy management (backup and restore procedures), easy file size handling and mental sanity. This ends up in having a ZODB database for each instance.
Design decisions, drawbacks and solutions
As I said, we had to adapt the system architecture through the years. We wanted to keep it bleeding edge, by implementing some of the most recent additions and features as they emerged from the community. Genweb implemented the first beta versions of plone.app.blob, this helped us to lower the sites database size by storing the images and files out of the ZODB.
Having a ZODB for each instance was a good decision, but we’ve had to face an important drawback. The system begun to lost connections due to reach the file descriptor (FD) limit of the backend because each ZODB mountpoint uses 4 sockets to connect with each Zope client. We had three clients accessing to each mountpoint, so this means that the limit of 1024 FDs by process was easily reached. After changing the libc6 hard limit, a recompilation of Python and Zope and change the default system FD limit the problem was solved. However, this was only valid for a short space of time, because we found that the ZEO server process have a lot of trouble in handling great numbers of open sockets. After some testing we found that staying arround 35 mountpoints for each ZEO server was the safest and best performance setup.
So we split the whole setup in 12 twin enviroments with 35 instances each at most.
Tools
We used buildout since the very beginning. We used a script to equally distribute the instances between enviroments. Since the split, we formalized this script converting it to a buildout recipe.
The recipe basically extends the zope.conf and zeo.conf files of each Zope client and ZEO server with a list of instances for each of them. This list can be a remote endpoint via http or a file in the filesystem.
These are the production buildouts of the project:
Probably, each of these tools itself won’t be useful for direct use for you because they are very specific for our use case, but you can extract some pieces of them for your own profit.
Summary and some numbers
As a conclusion, we are currently serving more than 3M pages/month with a transfer of 200GB/month. There are 12 ZEO servers distributed between our two Backends servers (6 each) with 400 ZODB mountpoints with its corresponding blobs, 36 Zope clients (12 Zope clients each Frontend) and 12 Varnish and HAProxy pairs in the Pre-frontends serving requests for 400 Plone sites.
Happy 5th anniversary Genweb!!!