<div dir="ltr">Thanks Adi.  I'll try it out.</div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 27, 2015 at 4:25 AM, Adi Kriegisch <span dir="ltr"><<a href="mailto:adi@cg.tuwien.ac.at" target="_blank">adi@cg.tuwien.ac.at</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hey!<br>
<span class=""><br>
> >I'm running a Kallithea instance with about 100 repositories and<br>
> >healthy amount of CI activity across several branches on each<br>
> >repository.  I'm looking for some tips on tuning performance.  I'm<br>
> >running using waitress (at least I think I am) and see what look<br>
> >like several knobs in the production.ini file that can be turned,<br>
> >but I'm not really sure what I'm looking at.<br>
</span>[...]<br>
<span class="">> I am a relatively happy user of apache + mod_wsgi. It scales nicely<br>
> with multiple single-threaded worker processes but might require<br>
> more memory. (I might however investigate uwsgi.)<br>
</span>We're using uwsgi. Performance and management is great; there are --<br>
however -- some caveates:<br>
* you'll need uwsgi >=1.9 (or your git pushes will fail due to some methods<br>
  not implemented in earlier versions[1])<br>
* you should do 'lazy' initialization; in case you're using a remote<br>
  database server you need 'lazy' initialization or you'll get SSL errors<br>
  when connecting to the database server:<br>
  'lazy' will first fork the required number of processes and then start<br>
  them. If you don't do that, the initialization of kallithea (including<br>
  establishing a database connection with SSL context) will take place and<br>
  then get forked. The error message you'll get is:<br>
  'sqlalchemy.exc.OperationalError: (OperationalError) SSL error:<br>
                                    decryption failed or bad record mac'<br>
* to allow larger mercurial commits (those may contain large to huge headers),<br>
  increase the buffer size default.<br>
* letting kallithea run as its own user is a good idea and can easily be<br>
  done in uwsgi by setting uid and gid; do not forget to allow the web<br>
  server user (www-data in most cases) to connect to the socket.<br>
* do not forget to 'calculate' your resource requirements<br>
  (reload-on-rss * processes); also leave some RAM for celery/rabbitmq, the<br>
  web server and the linux file system cache.<br>
<br>
The config itself is pretty simple --<br>
/etc/uwsgi/apps-enabled/kallithea.yaml:<br>
  | uwsgi:<br>
  |   plugins: python<br>
  |   chdir: /venvs/kallithea<br>
  |   virtualenv: /venvs/kallithea<br>
  |   pythonpath: = /venvs/kallithea<br>
  |   mount: /=/venvs/kallithea/dispatch.wsgi<br>
  |   uid: kallithea<br>
  |   gid: repos<br>
  |   umask: 007<br>
  |   memory-report: 1<br>
  |   processes: 4<br>
  |   reload-on-rss: 256<br>
  |   lazy: true<br>
  |   post-buffering: 4096<br>
  |   # set the buffer for headers<br>
  |   buffer-size: 16384<br>
  |   chown-socket: www-data<br>
  |   socket-timeout: 3600<br>
<br>
I personally prefer nginx as a frontend; that may be configured like this:<br>
/etc/nginx/sites-enabled/kallithea:<br>
  | upstream kallithea {<br>
  |     server unix:///run/uwsgi/app/kallithea/socket;<br>
  | }<br>
  | server {<br>
  | (...)<br>
  |     # maximum transfer size<br>
  |     client_max_body_size 256m;<br>
  |<br>
  |     # deliver static file from nginx<br>
  |     root /srv/virtualenv/kallithea/public;<br>
  |<br>
  |     location / {<br>
  |<br>
  |         try_files $uri @uwsgi;<br>
  |<br>
  |     }<br>
  |     location @uwsgi {<br>
  |         uwsgi_pass      kallithea;<br>
  |         uwsgi_param     HTTPS on;<br>
  |         uwsgi_param     SCRIPT_NAME "";<br>
  |         include         uwsgi_params;<br>
  |         uwsgi_read_timeout  3600;<br>
  |     }<br>
  | }<br>
but apache may also be able to connect to uwsgi either via socket<br>
(mod_uwsgi) or via http.<br>
<br>
Some random notes:<br>
* nginx currently has an issue with post buffering[2]: a post will be kept<br>
  in memory until it is complete; then it gets forwarded. This will be<br>
  fixed in 1.7/1.8 tree at some point; for nginx 1.2 and 1.4 patches exist.<br>
* keep in mind that Mercurial is based on python 2.7 that only has inferior<br>
  SSL support and is unable to do SNI[3]; your kallithea instance needs to be<br>
  the default virtual host for SSL. Finally, after 6 years of discussion,<br>
  python 2.7.9 might fix some of the more dangerous issues[4].<br>
* get some guide for securing your SSL config like bettercrypto[5] or<br>
  ssllabs[6].<br>
* for Debian, backporting uwsgi from unstable (2.0.7) is pretty simple.<br>
* running Apache is no option to me, because the current stable version of<br>
  Apache in Debian (2.2) does not support DH params > 1024bit (and that is<br>
  no reasonable key size). Debian maintainers backported EC-Support (the<br>
  NIST curves), so you may choose for yourself. Nginx from backports<br>
  has probably the best crypto support one could get out of OpenSSL atm.<br>
<br>
-- Adi<br>
<br>
[1] "IOError: seeking wsgi.input without post_buffering is IMPOSSIBLE !!!"<br>
    The changelog of v1.9 list a generic implementation of seek, read and<br>
    readlines: <a href="https://github.com/unbit/uwsgi-docs/blob/master/Changelog-1.9.rst" target="_blank">https://github.com/unbit/uwsgi-docs/blob/master/Changelog-1.9.rst</a><br>
[2] <a href="http://trac.nginx.org/nginx/ticket/251" target="_blank">http://trac.nginx.org/nginx/ticket/251</a><br>
[3] <a href="http://bugs.python.org/issue5639" target="_blank">http://bugs.python.org/issue5639</a><br>
[4] <a href="https://www.python.org/dev/peps/pep-0466/" target="_blank">https://www.python.org/dev/peps/pep-0466/</a><br>
[5] <a href="https://bettercrypto.org" target="_blank">https://bettercrypto.org</a><br>
[6] <a href="http://ssllabs.com" target="_blank">http://ssllabs.com</a><br>
</blockquote></div><br></div>