You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
15 KiB
271 lines
15 KiB
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>Chamilo Optimization Guide</title>
|
|
<link rel="stylesheet" href="../main/css/base.css" type="text/css" media="screen,projection" />
|
|
<link rel="stylesheet" href="default.css" type="text/css" media="screen,projection" />
|
|
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
|
|
</head>
|
|
<body>
|
|
<div class="navbar navbar-fixed-top">
|
|
<div class="navbar-inner">
|
|
<div class="container-fluid">
|
|
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
</a>
|
|
<a class="brand" href="index.html">Chamilo - Documentation</a>
|
|
<div class="nav-collapse">
|
|
<ul class="nav">
|
|
<li><a href="index.html">Home</a></li>
|
|
<li><a href="readme.html">About</a></li>
|
|
<li><a href="license.html">License</a></li>
|
|
<li><a href="credits.html">Credits</a></li>
|
|
<li><a href="dependencies.html">Dependencies</a></li>
|
|
<li><a href="changelog.html">Changelog</a></li>
|
|
</ul>
|
|
</div><!--/.nav-collapse -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="container">
|
|
<h1>Chamilo : Optimization Guide</h1>
|
|
|
|
<a href="index.html">Documentation</a> > Optimization Guide
|
|
|
|
<p>In seldom cases, you will need to start looking into efficiency issues with Chamilo. This guide is a work in progress intended to help administrators optimize their Chamilo installation.</p>
|
|
|
|
|
|
<h2><b>Contents</b></h2>
|
|
|
|
<ol>
|
|
<li><a href="#1.Using-XCache">Using xCache, APC or Memcache</a></li>
|
|
<li><a href="#2.Slow-queries">Slow queries</a></li>
|
|
<li><a href="#3.Indexes-caching">Indexes caching</a></li>
|
|
<li><a href="#4.Sessions-directories">Sessions directories</a></li>
|
|
<li><a href="#5.Users-upload-directories">Users upload directories</a></li>
|
|
<li><a href="#6.Zlib-compression">Zlib compressed output</a></li>
|
|
<li><a href="#7.High-numbers-memory">Memory considerations for high numbers of users</a></li>
|
|
<li><a href="#8.Avoid-non-fixed-values">Avoiding non-fixed values</a></li>
|
|
</ol>
|
|
|
|
<h2><a name="1.Using-XCache"></a>1. Using xCache or APC</h2>
|
|
See <a href="http://xcache.lighttpd.net/">xCache's website</a> for summary documentation.<br />
|
|
<ul>
|
|
<li>On Debian/Ubuntu: sudo apt-get install php5-xcache</li>
|
|
</ul>
|
|
Set your xcache.ini configuration (/etc/php5/conf.d/xcache.ini) to match your system. For example, you *could* have something like this (intentionally hiding comments here):
|
|
<pre>
|
|
xcache.shm_scheme = "mmap"
|
|
xcache.size = 32M
|
|
xcache.count = 2
|
|
xcache.slots = 8K
|
|
xcache.ttl = 0
|
|
xcache.gc_interval = 0
|
|
xcache.var_size = 16M
|
|
xcache.var_count = 16
|
|
xcache.var_slots = 8K
|
|
xcache.var_ttl = 60
|
|
xcache.var_maxttl = 300
|
|
xcache.var_gc_interval = 300
|
|
xcache.test = Off
|
|
</pre>
|
|
xCache will feel useless until you actually start to put some variables in cache. If you're showing the "Who is online" counter, that's one of the best item there is to implement xCache.<br />
|
|
For example, you could implement it this way (in main/inc/lib/banner.lib.php):<br />
|
|
<pre>
|
|
$xc = function_exists('xcache_isset');
|
|
$number = 0;
|
|
if ((api_get_setting('showonline', 'world') == 'true' AND !$user_id) OR (api_get_setting('showonline', 'users') == 'true' AND $user_id) OR (api_get_setting('showonline', 'course') == 'true' AND $user_id AND $course_id)) {
|
|
if ($xc && xcache_isset('campus_chamilo_org_whoisonline_count_simple')) {
|
|
$number = xcache_get('campus_chamilo_org_whoisonline_count_simple');
|
|
} else {
|
|
$number = who_is_online_count(api_get_setting('time_limit_whosonline'));
|
|
xcache_set('campus_chamilo_org_whoisonline_count_simple',$number);
|
|
}
|
|
}
|
|
$number_online_in_course = 0;
|
|
if(!empty($_course['id'])) {
|
|
if ($xc && xcache_isset('campus_chamilo_org_whoisonline_count_simple_'.$_course['id'])) {
|
|
$number_online_in_course = xcache_get('campus_chamilo_org_whoisonline_count_simple_'.$_course['id']);
|
|
} else {
|
|
$number_online_in_course = who_is_online_in_this_course_count(api_get_user_id(), api_get_setting('time_limit_whosonline'), $_course['id']);
|
|
xcache_set('campus_chamilo_org_whoisonline_count_simple_'.$_course['id'],$number_online_in_course);
|
|
}
|
|
}
|
|
</pre>
|
|
Note that, as xCache is a shared caching system, it is very important to prefix your variables with a domain name or some kind of identifier, otherwise it would end up in disaster if you use a shared server for several portals.<br />
|
|
If you use php5-memcache, then this piece of code would look like this (you need to adjust depending on your settings):
|
|
<pre>
|
|
global $_configuration;
|
|
$_course = api_get_course_info();
|
|
$course_id = api_get_course_id();
|
|
$user_id = api_get_user_id();
|
|
|
|
$html = '';
|
|
$xc = method_exists('Memcache','add');
|
|
if ($xc) {
|
|
// Make sure the server is available
|
|
$xm = new Memcache;
|
|
$xm->addServer('localhost', 11211);
|
|
$xc = $xc && ($xm->getServerStatus('localhost',11211)!=0);
|
|
// The following concatenates the name of the database + the id of the
|
|
// access url to make it a unique variable prefix for the variables to
|
|
// be stored
|
|
$xs = $_configuration['main_database'].'_'.$_configuration['access_url'].'_';
|
|
}
|
|
$number = 0;
|
|
if ((api_get_setting('showonline', 'world') == 'true' AND !$user_id) OR (api_get_setting('showonline', 'users') == 'true' AND $user_id) OR (api_get_setting('showonline', 'course') == 'true' AND $user_id AND $course_id)) {
|
|
if ($xc && $xm->get($xs.'wio_count_simple')) {
|
|
$number = $xm->get($xs.'wio_count_simple');
|
|
} else {
|
|
$number = who_is_online_count(api_get_setting('time_limit_whosonline'));
|
|
$xm->set($xs.'wio_count_simple',$number,0,30);
|
|
}
|
|
|
|
$number_online_in_course = 0;
|
|
if(!empty($_course['id'])) {
|
|
if ($xc && $xm->get($xs.'wio_count_simple_'.$_course['id'])) {
|
|
$number_online_in_course = $xm->get($xs.'wio_count_simple_'.$_course['id']);
|
|
} else {
|
|
$number_online_in_course = who_is_online_in_this_course_count($user_id, api_get_setting('time_limit_whosonline'), $_course['id']);
|
|
$xm->set($xs.'wio_count_simple_'.$_course['id'],$number_online_in_course,0,30);
|
|
}
|
|
}
|
|
</pre>
|
|
<br />
|
|
An optional additional caching mechanism you may use is the realpath_cache_size and realpath_cache_ttl php.ini parameters. See <a href="http://php.net/manual/en/ini.core.php">the PHP documentation</a> for more details.
|
|
<br />
|
|
<br />
|
|
If you prefer using <a href="http://php.net/manual/en/book.apc.php">APC</a>, you can use the same kind of trick as above, just changing the code a little:
|
|
<pre>
|
|
$xc = function_exists('apc_exists');
|
|
$number = 0;
|
|
if ((api_get_setting('showonline', 'world') == 'true' AND !$user_id) OR (api_get_setting('showonline', 'users') == 'true' AND $user_id) OR (api_get_setting('showonline', 'course') == 'true' AND $user_id AND $course_id)) {
|
|
if ($xc) {
|
|
$apc = apc_cache_info(null,true);
|
|
$apc_end = $apc['start_time']+$apc['ttl'];
|
|
if (apc_exists('my_campus_whoisonline_count_simple') AND (time() < $apc_end) AND apc_fetch('my_campus_whoisonline_count_simple') > 0 ) {
|
|
$number = apc_fetch('my_campus_whoisonline_count_simple');
|
|
} else {
|
|
$number = who_is_online_count(api_get_setting('time_limit_whosonline'));
|
|
apc_clear_cache();
|
|
apc_store('my_campus_whoisonline_count_simple',$number,15);
|
|
}
|
|
} else {
|
|
$number = who_is_online_count(api_get_setting('time_limit_whosonline'));
|
|
}
|
|
$number_online_in_course = 0;
|
|
if (!empty($_course['id'])) {
|
|
if ($xc) {
|
|
$apc = apc_cache_info(null,true);
|
|
$apc_end = $apc['start_time']+$apc['ttl'];
|
|
if (apc_exists('my_campus_whoisonline_count_simple_'.$_course['id']) AND (time() < $apc_end) AND apc_fetch('my_campus_whoisonline_count_simple_'.$_course['id']) > 0) {
|
|
$number_online_in_course = apc_fetch('my_campus_whoisonline_count_simple_'.$_course['id']);
|
|
} else {
|
|
$number_online_in_course = who_is_online_in_this_course_count($user_id, api_get_setting('time_limit_whosonline'), $_course['id']);
|
|
apc_store('my_campus_whoisonline_count_simple_'.$_course['id'],$number_online_in_course,15);
|
|
}
|
|
} else {
|
|
$number_online_in_course = who_is_online_in_this_course_count($user_id, api_get_setting('time_limit_whosonline'), $_course['id']);
|
|
}
|
|
}
|
|
...
|
|
</pre>
|
|
<hr />
|
|
<h2><a name="2.Slow-queries"></a>2. Slow queries</h2>
|
|
Enable slow_queries in /etc/mysqld/my.cnf, restart MySQL then follow using sudo tail -f /var/log/mysql/mysql-slow.log
|
|
<br /><br />
|
|
In Chamilo 1.9 in particular, due to the merge of all databases into one, you might experience performance issue if you have many learning paths with many items in them.<br />
|
|
To solve this performance issue, you can execute the following queries manually in your database:<br />
|
|
<pre>
|
|
ALTER TABLE lp_item ADD INDEX idx_c_lp_item_cid_lp_id (c_id, lp_id);
|
|
ALTER TABLE lp_item_view ADD INDEX idx_c_lp_item_view_cid_lp_view_id_lp_item_id (c_id, lp_view_id, lp_item_id);
|
|
</pre>
|
|
These will be available in Chamilo 1.10 directly, but we cannot put them into Chamilo 1.9 from now on for organizational reasons.<br />
|
|
<hr />
|
|
<h2><a name="3.Indexes-caching"></a>3. Indexes caching</h2>
|
|
One good reference: <a href="http://dev.mysql.com/doc/refman/5.1/en/multiple-key-caches.html">MySQL documentation on multiple key caches</a><br />
|
|
|
|
<hr />
|
|
|
|
<h2><a name="4.Sessions-directories"></a>4. Sessions directories</h2>
|
|
php_admin_value session.save_path 1;/var/www/test.chamilo.org/sessions/
|
|
<hr />
|
|
<h2><a name="5.Users-upload-directories"></a>5. Users upload directories</h2>
|
|
Create 10 directories inside the main/upload/users directory (from 0 to 9) and update your admin settings. This has to be done at install & configuration time, otherwise you might loose user data (or have to write a script for data distribution).
|
|
<hr />
|
|
<h2><a name="6.Zlib-compression"></a>6. Zlib compressed output</h2>
|
|
Although this will not make your server faster, compressing the pages you are sending to the users will definitely make them feel like your website's responses are a lot faster, and thus increase their well-being when using Chamilo.<br /><br />
|
|
Zlib output compression has to be set at two levels: PHP configuration for PHP pages and Apache for images and CSS.<br /><br />
|
|
To update the PHP configuration (either in php.ini or in your VirtualHost), use the <a href="http://php.net/manual/en/zlib.configuration.php">zlib.output_compression</a>. If you set this inside your Apache's VirtualHost, you should use the following syntax.
|
|
<pre>
|
|
php_value zlib.output_compression 1
|
|
</pre>
|
|
<br />
|
|
Configuring your Apache server to use output compression is a bit trickier. You have to use <a href="http://httpd.apache.org/docs/2.2/mod/mod_deflate.html">the mod_deflate module</a> to do it. Your configuration should look like something like this (please read the corresponding documentation before implementing in production).<br />
|
|
Easy mode:
|
|
<pre>
|
|
AddOutputFilterByType DEFLATE text/html text/plain text/xml
|
|
</pre> or, for every content type (dangerous) you can put the following inside a location or directory block:<pre>SetOutputFilter DEFLATE</pre>
|
|
<br />
|
|
Advanced mode:
|
|
<pre>
|
|
<Location />
|
|
# Insert filter
|
|
SetOutputFilter DEFLATE
|
|
|
|
# Netscape 4.x has some problems...
|
|
BrowserMatch ^Mozilla/4 gzip-only-text/html
|
|
|
|
# Netscape 4.06-4.08 have some more problems
|
|
BrowserMatch ^Mozilla/4\.0[678] no-gzip
|
|
|
|
# MSIE masquerades as Netscape, but it is fine
|
|
# BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
|
|
|
|
# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
|
|
# the above regex won't work. You can use the following
|
|
# workaround to get the desired effect:
|
|
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
|
|
|
|
# Don't compress images
|
|
SetEnvIfNoCase Request_URI \
|
|
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
|
|
|
|
# Make sure proxies don't deliver the wrong content
|
|
Header append Vary User-Agent env=!dont-vary
|
|
</Location>
|
|
</pre>
|
|
<hr />
|
|
Don't have time or resources to optimize your Chamilo installation yourself? Hire an <a href="http://www.chamilo.org/en/providers">official Chamilo provider</a> and get it sorted out professionally by specialists.
|
|
<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Transitional" style="margin: 1em; float: right;" height="31" width="88" /></a>
|
|
<a href="http://jigsaw.w3.org/css-validator/">
|
|
<img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" style="margin: 1em; float: right;" alt="Valid CSS" />
|
|
</a>
|
|
<hr />
|
|
<h2><a name="7.High-numbers-memory"></a>Memory considerations for high numbers of users</h2>
|
|
Some administration scripts *have to* handle lists of all users, and this might have a considerable impact on portals with very high numbers of users. For example, the main/admin/add_users_to_session.php script that handles the registration of users into a specific session, if used with the (non-default) full list of users, will devour about 3KB per user, which, for 100,000 users, translates into the need for around 300MB of RAM just to show this page, and to around 3GB for 1,000,000 users.<br />
|
|
This mode is not loaded by default, but could still be selected, leading to a "Fatal error: Allowed memory size ... exhausted" message.<br />
|
|
The only non-scripted solution here is to allow for the corresponding amount of RAM for your PHP configuration (<em>memory_limit = 300M</em>) or your specific VirtualHost if you use mod-php5 (<em>php_value memory_limit 300M</em>).<br/>
|
|
<hr />
|
|
<h2><a name="#8.Avoid-non-fixed-values"></a>Avoiding non-fixed values</h2>
|
|
Many things in Chamilo are written focusing on the ease of use, even for the administrator. Sometimes, these settings are weighing a little bit more on the system. This is the case, between others, of the mail.conf.php file (being loaded unconditionally) and its CONSTANT "IS_WINDOWS_OS", which is defined by a function call (api_is_windows_os()) at the beginning of main_api.lib.php.
|
|
|
|
The definition of this constant (which is executed at *every* page load) can easily be avoided, and the only place where it is used inconditionally (mail.conf.php) can be modified to set the line as you expect it (depending on whether you use sendmail/exim or smtp).
|
|
<pre>
|
|
$platform_email['SMTP_MAILER'] = 'smtp';
|
|
</pre>
|
|
or
|
|
<pre>
|
|
$platform_email['SMTP_MAILER'] = 'mail';
|
|
</pre>
|
|
In fact, the complete loading of mail.conf.php can also be avoided if loaded conditionally (with <i>require_once</i>) when sending an e-mail (which is the only case where it is useful).
|
|
<hr />
|
|
<h2>Authors</h2>
|
|
<ul>
|
|
<li>Yannick Warnier, Zend Certified PHP Engineer, BeezNest Belgium SPRL, <a href="mailto:ywarnier@beeznest.net">ywarnier@beeznest.net</a></li>
|
|
</ul>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
|