Plone 5.2 WSGI deployment

We (at University of Bologna) are working on our first project using Plone 5.2 / Python 3.

The main question is about production deployment. Is there someone with a medium/large installation in the wild that want to share their experience?

Our main questions:

Currently we have the current battle tested deployment: nginx + varnish + haproxy + multiple ZServer processes (ZEO client or RelStorage client) over multiple virtual server, for scaling and fail over.

With Plone 5.2/python3 there is WSGI, currently mandatory.

Any experience with different WSGI server in production? Waitress is enough for production or is it better to choose other options: gunicorn, uwsgi, ... ? pro/cons ?

What about blob file streaming? Is wsgi.file_wrapper the right solution here (https://www.python.org/dev/peps/pep-0333/#optional-platform-specific-file-handling)?
It is performant enough in waitress (https://docs.pylonsproject.org/projects/waitress/en/stable/filewrapper.html) or if needing performance for many/large blob files is better to choose a different wsgi server?

What about balancing?
Better following well-beaten path: multiple wsgi server http and haproxy or varnish http balancer? Or is someone experienced with specific wsgi balancer, automatic scaling, cleaver balancing, like circus or zc.resumelb or others?

What about the small gems that we had before in Plone but really closed to ZServer implementation. Like inspect running threads (kill -USR1 instance.pid) or collective.taskqueue, haufe.requestmonitoring, ... there are ready to work working alternatives?

Asko what about your work in progress on the new python 3 ZServer over Twisted?

Last but non least, what about documentation: https://docs.plone.org/manage/deploying/wsgi.html seems to me too old.

References / follow up of:

2 Likes

You are right, the documentation regarding deployment and performance of Plone 5.2 with WSGI is currently non-existent. We also lack tools like you mentioned (Sentry-integration!). The reason is simple: It is still new and only few people are using it in production.

At the conference there will be a training covering some of these topics (https://2019.ploneconf.org/training/waitress-theres-a-plone-in-my-wsgi-can-i-talk-to-the-supervisor/) by @tschorr. The trainign will yield some documentation to get you started but the bulk of the documentation and tools will only exists when we all share what we learn and write documentation about that.

Missing documentation regarding WSGI deployment is one thing.
But as noticed there are various missing things missing in the deployment pipeline: Sentry integration already mentioned, configurable mail logger integration etc.

Perhaps it would make sense to document the missing parts that require porting work or perhaps a reimplementation. Perhaps there is a chance to pool some money in order to sponsor the work on a particular feature. Speaking as contractor for the University Gent: we will likely face the same issues at the time when we go into production.

Andreas

This is a part of our todo list for the deployment. I need to work at least on the first three issues.

13-08_48_28

I've found other useful hints about wsgi deployment and a great wsgi server comparison here:
https://zope.readthedocs.io/en/latest/wsgi.html (thanks to @dataflake).

I will continue this week with bringing back support for a mail logger under WSGI.

I need haufe.requestmonitoring myself, so I've created a Pull Request. The package uses the IPubStart/IPubSuccess/IPubFailure events, so there's nothing WSGI specific here. But some fixes for Python 3 and Zope 4 compatibility were necessary.

1 Like

Hi, I am running Plone 5.2 under uwsgi and nginx, the instructions are:

Create a wsgi.cfg at the same level where buildout.cfg is located:

cat > wsgi.cfg << 'EOF'
[uwsgi-run]
recipe = collective.recipe.template
output= ${buildout:bin-directory}/uwsgi-run
mode = 755
input = inline:
    uwsgi \
    --socket :3031 \
    --stats :9191 \
    --wsgi-file=${buildout:bin-directory}/${uwsgi-app:interpreter}

[uwsgi-app]
recipe = zc.recipe.egg:script
interpreter = uwsgi-app
eggs = ${instance:eggs}
initialization = from paste.deploy import loadapp; application = loadapp('config:${instance:location}/etc/wsgi.ini')
EOF

Then apply this git patch to buildout.cfg

diff --git a/buildout.cfg b/buildout.cfg
index ca76adf..c2f309d 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -45,6 +45,7 @@ extensions =
 extends =
     base.cfg
     release-5.2.0-versions.cfg
+    wsgi.cfg
 #    http://dist.plone.org/release/5.2.0/versions.cfg

 # If you change your Plone version, you'll also need to update
@@ -157,6 +158,8 @@ parts =
     backup
     zopepy
     unifiedinstaller
+    uwsgi-app
+    uwsgi-run

 ############################################
 # Major Parts

Recreate the files using buildout:

$ buildout

Then test if it works via command line (under plone_buildout user with virtualenv activated):

$ ./bin/uwsgi-run

Then test if it works via command line (under root user with global uwsgi binary ):

# uwsgi --uid plone_buildout --gid plone_buildout --plugins python3 --virtualenv /usr/local/plone/5.2/env37 --socket :3031 --stats :9191 --master --processes 4 --threads 2 --wsgi-file=/usr/local/plone/5.2/myinstance/bin/uwsgi-app

Then create the corresponding file to /etc/uwsgi-emperor/vassals/ for automatic startup .

cat > myinstance.ini << 'EOF'
[uwsgi]
my_vassal_name = %n
uid = plone_buildout
gid = plone_buildout
plugins = python3
virtualenv = /usr/local/plone/5.2/env37
socket = 127.0.0.1:3031
stats = 127.0.0.1:9191
wsgi-file = /usr/local/plone/5.2/myinstance/bin/uwsgi-app
processes = 4
threads = 2
EOF

Fix permissions

$ chown plone_buildout.plone_buildout myinstance.ini

Open a terminal and watch the log (under root user)

# tail -f /var/log/uwsgi/emperor.log

Then under nginx (at 'http' block):

upstream myinstance_cluster {
    server 127.0.0.1:3031;
}

[...] And at 'server' block:

location / {
    rewrite "^(.*)$" "/VirtualHostBase/https/$server_name:$server_port/VirtualHostRoot/_vh_$1" break;
    
    include /etc/nginx/uwsgi_params;
    uwsgi_pass myinstance_cluster;
}

Please format your code segments properly...your posting is unreadable.

Done, tell me if that is ok for you.

@nesiax1 thanks for sharing your experience. I ask to you for some more details:

Do you have this setup running in production?

If yes in the latter point, can you sharing some numbers? (concurrent users, users per day, anonymous site or intranet, number of pages, ...)

I read about multiple processes managed by uwsgi, so I presume that you have zeo or relstorage as persistent server. In my previous experience, balancing multiple clients need stickiness policy for users, ie same user must use same zeoclient process during requests. It is not be the same with uwsgi balancing? Do you have experienced and/or solved that?

Do you have some pros/cons feedbacks about using uwsgi as balancer instead of an HTTP balancer (nginx, haproxy, varnish, ...)

Mauro.

The WSGI training at the Ploneconf in Ferrara will cover uWSGI configuration based on what is already available in the coredev buildout. The training is still WIP, but if you like you can try the solution(s) proposed in the uWSGI chapter. And no, I'm not using this in production yet :-). But I'm looking forward to your feedback.

1 Like