##// END OF EJS Templates
middleware: drop gzipper middleware...
Mads Kiilerich -
r6338:692dddf2 default
parent child Browse files
Show More
@@ -1,112 +1,118 b''
1 1 .. _performance:
2 2
3 3 ================================
4 4 Optimizing Kallithea performance
5 5 ================================
6 6
7 7 When serving a large amount of big repositories, Kallithea can start performing
8 8 slower than expected. Because of the demanding nature of handling large amounts
9 9 of data from version control systems, here are some tips on how to get the best
10 10 performance.
11 11
12 12
13 13 Fast storage
14 14 ------------
15 15
16 16 Kallithea is often I/O bound, and hence a fast disk (SSD/SAN) and plenty of RAM
17 17 is usually more important than a fast CPU.
18 18
19 19
20 20 Caching
21 21 -------
22 22
23 23 Tweak beaker cache settings in the ini file. The actual effect of that is
24 24 questionable.
25 25
26 26
27 27 Database
28 28 --------
29 29
30 30 SQLite is a good option when having a small load on the system. But due to
31 31 locking issues with SQLite, it is not recommended to use it for larger
32 32 deployments.
33 33
34 34 Switching to MySQL or PostgreSQL will result in an immediate performance
35 35 increase. A tool like SQLAlchemyGrate_ can be used for migrating to another
36 36 database platform.
37 37
38 38
39 39 Horizontal scaling
40 40 ------------------
41 41
42 42 Scaling horizontally means running several Kallithea instances and let them
43 43 share the load. That can give huge performance benefits when dealing with large
44 44 amounts of traffic (many users, CI servers, etc.). Kallithea can be scaled
45 45 horizontally on one (recommended) or multiple machines.
46 46
47 47 It is generally possible to run WSGI applications multithreaded, so that
48 48 several HTTP requests are served from the same Python process at once. That can
49 49 in principle give better utilization of internal caches and less process
50 50 overhead.
51 51
52 52 One danger of running multithreaded is that program execution becomes much more
53 53 complex; programs must be written to consider all combinations of events and
54 54 problems might depend on timing and be impossible to reproduce.
55 55
56 56 Kallithea can't promise to be thread-safe, just like the embedded Mercurial
57 57 backend doesn't make any strong promises when used as Kallithea uses it.
58 58 Instead, we recommend scaling by using multiple server processes.
59 59
60 60 Web servers with multiple worker processes (such as ``mod_wsgi`` with the
61 61 ``WSGIDaemonProcess`` ``processes`` parameter) will work out of the box.
62 62
63 63 In order to scale horizontally on multiple machines, you need to do the
64 64 following:
65 65
66 66 - Each instance's ``data`` storage needs to be configured to be stored on a
67 67 shared disk storage, preferably together with repositories. This ``data``
68 68 dir contains template caches, sessions, whoosh index and is used for
69 69 task locking (so it is safe across multiple instances). Set the
70 70 ``cache_dir``, ``index_dir``, ``beaker.cache.data_dir``, ``beaker.cache.lock_dir``
71 71 variables in each .ini file to a shared location across Kallithea instances
72 72 - If using several Celery instances,
73 73 the message broker should be common to all of them (e.g., one
74 74 shared RabbitMQ server)
75 75 - Load balance using round robin or IP hash, recommended is writing LB rules
76 76 that will separate regular user traffic from automated processes like CI
77 77 servers or build bots.
78 78
79 79
80 80 Serve static files directly from the web server
81 81 -----------------------------------------------
82 82
83 83 With the default ``static_files`` ini setting, the Kallithea WSGI application
84 will take care of serving the static files found in ``kallithea/public`` from
85 the root of the application URL. While doing that, it will currently also
86 apply buffering and compression of all the responses it is serving.
84 will take care of serving the static files from ``kallithea/public/`` at the
85 root of the application URL.
87 86
88 The actual serving of the static files is unlikely to be a problem in a
89 Kallithea setup. The buffering of responses is more likely to be a problem;
90 large responses (clones or pulls) will have to be fully processed and spooled
91 to disk or memory before the client will see any response.
87 The actual serving of the static files is very fast and unlikely to be a
88 problem in a Kallithea setup - the responses generated by Kallithea from
89 database and repository content will take significantly more time and
90 resources.
92 91
93 92 To serve static files from the web server, use something like this Apache config
94 93 snippet::
95 94
96 95 Alias /images/ /srv/kallithea/kallithea/kallithea/public/images/
97 96 Alias /css/ /srv/kallithea/kallithea/kallithea/public/css/
98 97 Alias /js/ /srv/kallithea/kallithea/kallithea/public/js/
99 98 Alias /codemirror/ /srv/kallithea/kallithea/kallithea/public/codemirror/
100 99 Alias /fontello/ /srv/kallithea/kallithea/kallithea/public/fontello/
101 100
102 101 Then disable serving of static files in the ``.ini`` ``app:main`` section::
103 102
104 103 static_files = false
105 104
106 105 If using Kallithea installed as a package, you should be able to find the files
107 under site-packages/kallithea, either in your Python installation or in your
106 under ``site-packages/kallithea``, either in your Python installation or in your
108 107 virtualenv. When upgrading, make sure to update the web server configuration
109 108 too if necessary.
110 109
110 It might also be possible to improve performance by configuring the web server
111 to compress responses (served from static files or generated by Kallithea) when
112 serving them. That might also imply buffering of responses - that is more
113 likely to be a problem; large responses (clones or pulls) will have to be fully
114 processed and spooled to disk or memory before the client will see any
115 response. See the documentation for your web server.
116
111 117
112 118 .. _SQLAlchemyGrate: https://github.com/shazow/sqlalchemygrate
@@ -1,112 +1,110 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 Pylons middleware initialization
16 16 """
17 17
18 18 from routes.middleware import RoutesMiddleware
19 19 from paste.cascade import Cascade
20 20 from paste.registry import RegistryManager
21 21 from paste.urlparser import StaticURLParser
22 22 from paste.deploy.converters import asbool
23 from paste.gzipper import make_gzip_middleware
24 23
25 24 from pylons.middleware import ErrorHandler, StatusCodeRedirect
26 25 from pylons.wsgiapp import PylonsApp
27 26
28 27 from kallithea.lib.middleware.simplehg import SimpleHg
29 28 from kallithea.lib.middleware.simplegit import SimpleGit
30 29 from kallithea.lib.middleware.https_fixup import HttpsFixup
31 30 from kallithea.lib.middleware.sessionmiddleware import SecureSessionMiddleware
32 31 from kallithea.config.environment import load_environment
33 32 from kallithea.lib.middleware.wrapper import RequestWrapper
34 33
35 34
36 35 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
37 36 """Create a Pylons WSGI application and return it
38 37
39 38 ``global_conf``
40 39 The inherited configuration for this application. Normally from
41 40 the [DEFAULT] section of the Paste ini file.
42 41
43 42 ``full_stack``
44 43 Whether or not this application provides a full WSGI stack (by
45 44 default, meaning it handles its own exceptions and errors).
46 45 Disable full_stack when this application is "managed" by
47 46 another WSGI middleware.
48 47
49 48 ``app_conf``
50 49 The application's local configuration. Normally specified in
51 50 the [app:<name>] section of the Paste ini file (where <name>
52 51 defaults to main).
53 52
54 53 """
55 54 # Configure the Pylons environment
56 55 config = load_environment(global_conf, app_conf)
57 56
58 57 # The Pylons WSGI app
59 58 app = PylonsApp(config=config)
60 59
61 60 # Routing/Session/Cache Middleware
62 61 app = RoutesMiddleware(app, config['routes.map'], use_method_override=False)
63 62 app = SecureSessionMiddleware(app, config)
64 63
65 64 # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
66 65 if asbool(config['pdebug']):
67 66 from kallithea.lib.profiler import ProfilingMiddleware
68 67 app = ProfilingMiddleware(app)
69 68
70 69 if asbool(full_stack):
71 70
72 71 from kallithea.lib.middleware.sentry import Sentry
73 72 from kallithea.lib.middleware.errormator import Errormator
74 73 if Errormator and asbool(config['app_conf'].get('errormator')):
75 74 app = Errormator(app, config)
76 75 elif Sentry:
77 76 app = Sentry(app, config)
78 77
79 78 # Handle Python exceptions
80 79 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
81 80
82 81 # Display error documents for 401, 403, 404 status codes (and
83 82 # 500 when debug is disabled)
84 83 # Note: will buffer the output in memory!
85 84 if asbool(config['debug']):
86 85 app = StatusCodeRedirect(app)
87 86 else:
88 87 app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
89 88
90 89 # we want our low level middleware to get to the request ASAP. We don't
91 90 # need any pylons stack middleware in them - especially no StatusCodeRedirect buffering
92 91 app = SimpleHg(app, config)
93 92 app = SimpleGit(app, config)
94 93
95 94 # Enable https redirects based on HTTP_X_URL_SCHEME set by proxy
96 95 if any(asbool(config.get(x)) for x in ['https_fixup', 'force_https', 'use_htsts']):
97 96 app = HttpsFixup(app, config)
98 97
99 98 app = RequestWrapper(app, config) # logging
100 99
101 100 # Establish the Registry for this application
102 101 app = RegistryManager(app) # thread / request-local module globals / variables
103 102
104 103 if asbool(static_files):
105 104 # Serve static files
106 105 static_app = StaticURLParser(config['pylons.paths']['static_files'])
107 106 app = Cascade([static_app, app])
108 app = make_gzip_middleware(app, global_conf, compress_level=1)
109 107
110 108 app.config = config
111 109
112 110 return app
General Comments 0
You need to be logged in to leave comments. Login now