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