Effroyable lenteurs avec role_assign && role_unassign

Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Nombre de réponses : 19
Bonjour les moodleurs,

Je suis entrain de faire des tests sur la version 1.9 de moodle, et, je m'aperçoit qu'ajouter ou supprimer des roles a des utilisateurs est effroyablement lent...

Par exemple, inscrire 186 utilisateurs (mon jeu de tests) en même temps en tant que "student" dans un cours donné prend 213 secondes en moyenne, pour moins de 10 sur la version 1.6.

Suis-je seul à avoir ces problèmes?

Avez-vous des réponses?
Moyenne des évaluations  -
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Nicolas Martignoni,
Avatar Développeurs Avatar Développeurs de plugins Avatar Documentation writers Avatar Moodleurs particulièrement utiles Avatar Testeurs Avatar Traducteurs

C'est très bizarre, et certainement dû à un problème de configuration.

Les rôles ont justement été considérablement optimisés dans la 1.9 pour de vraiment gros gros sites Moodle et cela va effectivement vite. Aucune de mes instances 1.9 ne manifeste ce problème.

En réponse à Nicolas Martignoni

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Salut, et merci de répondre vite...

Est-ce configurable? Et comment, si oui... rouge
Je t'explique ma situation, et ce que j'observe :
Config de mon serveur :
4 coeurs à 3.06 GHz,
4 GB de RAM,
200Go HDD,
Et voilà...
Mes services installés :
Apache (moodle)
mysql (& phpmyadmin pour moodle)
slapd (car mes comptes utilisateurs sont dans l'annuaire)

Lors de l'inscription de mon jeu de tests (toujours en tant que students), j'observe avec "htop" que seul un coeur des 4 est à 100%, le site moodle est "bloqué" car mysql ne répond plus, ou très lentement.

Voilà, je sais pas trop quoi faire....
Merci,
Simon
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Nicolas Martignoni,
Avatar Développeurs Avatar Développeurs de plugins Avatar Documentation writers Avatar Moodleurs particulièrement utiles Avatar Testeurs Avatar Traducteurs

Quelles sont les versions de Apache, PHP et MySQL ?

As-tu fait des modifications au Moodle ou est-il "tout neuf" ?

En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Étienne Rozé,
Manque le système d'exploitation aussi ... enfin je devine clin d’oeil mais je peux me tromper !
Problème intéressant pensif
Les lenteurs sont générales ou seulement dans la circonstance évoquée ? A l'installation c'était rapide ?
N'y aurait-il pas des fonctions de log ou de débogage activées dans MySQL ? Ou ailleurs...
Peut-être un problème de corruption d'index ou de table dans MySQL => tenter de réparer les tables.
Tenter de faire une grosse requête dans MySQL... Il semble me souvenir qu'il y a un outil de benchmark
Pourquoi ne pas installer PostgreSQL et tenter une installation avec.
Si c'est pareil, cela réorienterait vers Moodle ou l'installation de php...

Voilà un peu près tout ce qui m'est passé par la tête !
Je suis avec intérêt !


En réponse à Étienne Rozé

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Salut,

Merci de suivre avec tant d'intérêt...

Apache2 :
Version : 2.2.8-3
PHP :
Version : 5.2.5-3
MySQL :
Version : 5.0.51a
Système :
résultat de la commande "uname -a" :
Linux debian-test2 2.6.22-3-686 #1 SMP Mon Nov 12 08:32:57 UTC 2007 i686 GNU/Linux

Lorsque je lance "ps -aux | grep log" , je vois :
root 1907 0.0 0.0 1656 596 ? Ss Apr11 11:14 /sbin/syslogd
root 1914 0.0 0.0 1608 392 ? Ss Apr11 0:00 /sbin/klogd -x
root 4325 0.0 0.0 2848 600 ? S 10:49 0:00 logger -p daemon.err -t mysqld_safe -i -t mysqld
melix 5337 0.0 0.0 2992 768 pts/0 S+ 20:56 0:00 grep log

L'installation n'était pas super rapide, mais j'ai fait un import d'une base d'une "grosse" bdd de la version 1.6.
Je pense que mon moodle est "tout neuf" je n'ai fait que des "développements connexes" que vous verrez au moodlemoot... ^^

Merci de suivre tout ça, je suis un peu "newbie" ^^ même si ça commence à faire un petit moment que je bosse sur moodle... C'est ma première install/config...
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Valery Fremaux,
Tout à l'air OK pourtant côté système. Il est vrai que l'inscription d'un utilisateur dans la 1.9 brasse beaucoup de capacités pour construire le profil de l'utilisateur dans le cours, et c'est forcément plus long que dans la 1.6, mais pas à ce point...
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Zied ALAYA,
Bonjour,
il est possible d'améliorer nettement les performances en utilisant un accélérateur php afin d'éviter la ré-compilation (totalement inutile tant que le fichier n'a pas changé).

j'ai installé l'extension php xcache sur notre serveur Ubuntu et on a remarqué un meilleur temp de réponse. ce qui m'a impressionné le plus c'est le paramètre xcache.count : tu donne le nombre de processeur et il divise le cache en ce nombre pour avoir un traitement en parallèle (2 pour notre cas) !

penser aussi à passer à la version 1.9.1, si ce n'est pas déjà fait bien sûr, les performances de plusieurs modules ont été améliorées.
En réponse à Zied ALAYA

Re: Effroyable lenteurs avec role_assign && role_unassign

par Étienne Rozé,
Bonjour,

Je suis d'accord que ces conseils ne peuvent qu'améliorer les choses, mais vu la description de la machine dont la puissance est sans comparaison avec mon serveur de prod (c'est aussi une debian , + de 400 utilisateurs et une centaine de cours et Moodle 1.8 -censé être moins optimisé que 1.9 , du moins au niveau des rôles et il y a d'autres services dessus), je n'imagine pas qu'une "lenteur effroyable" puisse être expliquée par autre chose qu'une erreur de configuration ou quelque chose comme cela.

Il faudrait peut-être, si ce n'est fait, activer les "informations de performance" (Administration Serveur  Débogage ) de Moodle qui permettrait d'objectiver les choses et d'orienter le diagnostic.

Le serveur est-il installé récemment et a-t-il servi à autre chose ?
En réponse à Zied ALAYA

Re: Effroyable lenteurs avec role_assign && role_unassign

par Valery Fremaux,
Et peut-on imaginer associer phpaccelerator, memcached et xcache ensemble, ou est-ce redondant ?
En réponse à Valery Fremaux

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Ce serveur est une install toute fraiche.
Je viens d'installer le paquet php5-xdebug pour voir ce qui ralentit mon bazard...
Je sais que ça vient du role_assign, mais d'où exactement là dedans, well see...
Je vous tient au courant.

Au fait, je ne pense pas qu'un accélérateur php soit vraiment utile dans mon cas, c'est bien mysql qui a un problème... à moins qu'un accélérateur php soit aussi un accélérateur mysql?
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Séverin Terrier,
Avatar Documentation writers Avatar Moodleurs particulièrement utiles Avatar Testeurs Avatar Traducteurs
Bonjour,

L'accélérateur PHP est vraiment le moyen logiciel de gagner le plus en performance, assez simplement qui plus est sourire

A propos, une nouvelle version mineure de eAccelerator est sortie avant hier clin d’œil
En réponse à Séverin Terrier

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Très bien, mais je vous annonce que je n'aurai pas besoin d'en installer un.

Le problème dans mon développement (conjointement avec Olivier CATTEAU), c'était le role_assign qui, exécuté dans une boucle, ralentissait considérablement les perfs de mysql.

PROBLEME RESOLU :
j'ai simplement redéfini la fonction role assign qui était :

function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $timeend=0, $hidden=0, $enrol='manual',$timemodified='') {
global $USER, $CFG;

/// Do some data validation

if (empty($roleid)) {
debugging('Role ID not provided');
return false;
}

if (empty($userid) && empty($groupid)) {
debugging('Either userid or groupid must be provided');
return false;
}

if ($userid && !record_exists('user', 'id', $userid)) {
debugging('User ID '.intval($userid).' does not exist!');
return false;
}

if ($groupid && !groups_group_exists($groupid)) {
debugging('Group ID '.intval($groupid).' does not exist!');
return false;
}

if (!$context = get_context_instance_by_id($contextid)) {
debugging('Context ID '.intval($contextid).' does not exist!');
return false;
}

if (($timestart and $timeend) and ($timestart > $timeend)) {
debugging('The end time can not be earlier than the start time');
return false;
}

if (!$timemodified) {
$timemodified = time();
}

/// Check for existing entry
if ($userid) {
$ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $context->id, 'userid', $userid);
} else {
$ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $context->id, 'groupid', $groupid);
}

$newra = new object;

if (empty($ra)) { // Create a new entry
$newra->roleid = $roleid;
$newra->contextid = $context->id;
$newra->userid = $userid;
$newra->hidden = $hidden;
$newra->enrol = $enrol;
/// Always round timestart downto 100 secs to help DBs to use their own caching algorithms
/// by repeating queries with the same exact parameters in a 100 secs time window
$newra->timestart = round($timestart, -2);
$newra->timeend = $timeend;
$newra->timemodified = $timemodified;
$newra->modifierid = empty($USER->id) ? 0 : $USER->id;

$success = insert_record('role_assignments', $newra);

} else { // We already have one, just update it

$newra->id = $ra->id;
$newra->hidden = $hidden;
$newra->enrol = $enrol;
/// Always round timestart downto 100 secs to help DBs to use their own caching algorithms
/// by repeating queries with the same exact parameters in a 100 secs time window
$newra->timestart = round($timestart, -2);
$newra->timeend = $timeend;
$newra->timemodified = $timemodified;
$newra->modifierid = empty($USER->id) ? 0 : $USER->id;

$success = update_record('role_assignments', $newra);
}

if ($success) { /// Role was assigned, so do some other things

/// mark context as dirty - modules might use has_capability() in xxx_role_assing()
/// again expensive, but needed
mark_context_dirty($context->path);

if (!empty($USER->id) && $USER->id == $userid) {
/// If the user is the current user, then do full reload of capabilities too.
load_all_capabilities();
}

/// Ask all the modules if anything needs to be done for this user
if ($mods = get_list_of_plugins('mod')) {
foreach ($mods as $mod) {
include_once($CFG->dirroot.'/mod/'.$mod.'/lib.php');
$functionname = $mod.'_role_assign';
if (function_exists($functionname)) {
$functionname($userid, $context, $roleid);
}
}
}
}

/// now handle metacourse role assignments if in course context
if ($success and $context->contextlevel == CONTEXT_COURSE) {
if ($parents = get_records('course_meta', 'child_course', $context->instanceid)) {
foreach ($parents as $parent) {
sync_metacourse($parent->parent_course);
}
}
}

return $success;
}

par :

function role_assign_iut($roleid, $userid, $groupid, $contextid, $timestart=0, $timeend=0, $hidden=0, $enrol='manual',$timemodified=''){
global $USER, $CFG;

if (!$timemodified) {
$timemodified = time();
}

$newra = new object;
$ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $contextid, 'userid', $userid);

if (empty($ra)) { // Create a new entry
$newra->roleid = $roleid;
$newra->contextid = $contextid;
$newra->userid = $userid;
$newra->hidden = $hidden;
$newra->enrol = $enrol;
/// Always round timestart downto 100 secs to help DBs to use their own caching algorithms
/// by repeating queries with the same exact parameters in a 100 secs time window
$newra->timestart = round($timestart, -2);
$newra->timeend = $timeend;
$newra->timemodified = $timemodified;
$newra->modifierid = empty($USER->id) ? 0 : $USER->id;

$success = insert_record('role_assignments', $newra);
}
else { // We already have one, just update it
$newra->id = $ra->id;
$newra->hidden = $hidden;
$newra->enrol = $enrol;
/// Always round timestart downto 100 secs to help DBs to use their own caching algorithms
/// by repeating queries with the same exact parameters in a 100 secs time window
$newra->timestart = round($timestart, -2);
$newra->timeend = $timeend;
$newra->timemodified = $timemodified;
$newra->modifierid = empty($USER->id) ? 0 : $USER->id;

$success = update_record('role_assignments', $newra);
}

if ($success) { /// Role was assigned, so do some other things

/// mark context as dirty - modules might use has_capability() in xxx_role_assing()
/// again expensive, but needed
mark_context_dirty($context->path);

if (!empty($USER->id) && $USER->id == $userid) {
/// If the user is the current user, then do full reload of capabilities too.
load_all_capabilities();
}

/// Ask all the modules if anything needs to be done for this user
if ($mods = get_list_of_plugins('mod')) {
foreach ($mods as $mod) {
include_once($CFG->dirroot.'/mod/'.$mod.'/lib.php');
$functionname = $mod.'_role_assign';
if (function_exists($functionname)) {
$functionname($userid, $context, $roleid);
}
}
}
}

/// now handle metacourse role assignments if in course context
if ($success and $context->contextlevel == CONTEXT_COURSE) {
if ($parents = get_records('course_meta', 'child_course', $context->instanceid)) {
foreach ($parents as $parent) {
sync_metacourse($parent->parent_course);
}
}
}

return $success;

}

EDIT : Oups, ça fait un post un peu long... ^_^'

Car : J'effectue toutes les vérifications des variables (les 5 ou 6 premiers "if") en dehors de la boucle des role_assign, dans la boucle, le "context" ne change pas, ni le "roleid", ni le "groupid", seulement le userid.

Voilà, problème résolu.

Rendez-vous à la moodlemoot pour vous expliquer tout ça en profondeur...

PS : mon temps d'exécution pour le même jeu de tests qu'avant est passé en dessous des 2 secondes.... soit grâce à cette mofification, mon script est 100 fois plus rapide... que dire?
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Étienne Rozé,
Ah ! grave erreur !
je ne parle non pas de l'erreur de programmation. Pas grave ça...

Mais de ne pas avoir préciser que les tests était ceux d'un développement... d'où la recherche de tout le monde du côté MySQL et autre optimisation système !

Si il y test d'un développement et ce genre de problème, cela vient automatiquement, forcément du développement en cours... (c'est ma petite expérience qui le dit (et la logique aussi !) ) à 99,9% des cas (le 0,1 % qui reste est le cas où la loi de Murphy intervient... mais alors là, généralement, c'est une combinaison de différents facteurs : il ne vaut mieux pas y penser !!!)

Il aurait mieux fallu le dire.... et en particulier répondre à Nicolas qui posait explicitement la question : "As-tu fait des modifications au Moodle ou est-il "tout neuf" ?"

Ceci dit, il sera surement intéressant de voir ce que tout cela cache !
A bientôt à Nantes !
Moyenne des évaluations Utile (2)
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Séverin Terrier,
Avatar Documentation writers Avatar Moodleurs particulièrement utiles Avatar Testeurs Avatar Traducteurs
PS : mon temps d'exécution pour le même jeu de tests qu'avant est passé en dessous des 2 secondes.... que dire?

Tout d'abord, je confirme ce que dit Etienne sourire

Et donc, d'après les chiffres que tu avais fourni dans ton premier message, il semblerait que la manipulation soit donc 5 fois plus rapide avec Moodle 1.9 qu'avec 1.6 (moins de 2s au lieu de moins de 10s) clin d’œil
En réponse à Séverin Terrier

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Correct, la manip est bien plus rapide sous 1.9 que sous 1.6, ça fait plaisir, mais c'est à relativiser car mon serveur de test 1.9 est un peu plus puissant que mon serveur de prod 1.6. A suivre...

Désolé de na pas avoir précisé que c'était un développement externe, mais le problème existe toutefois sur l'attribution ou dés-attribution de role dans l'onglet "gestion des utilisateurs" de la partie "admin" (j'ai plus de 8000 comptes sur la plateforme).

Le problème ne vient pas de mon développement, mais de la fonction role_assign dans ce cas là. Je me permet de le dire. La véfification de l'état des variables passées en paramètres de la fonction role_assign prend trop de temps (est-ce dû a mon trop grand nombre d'utilisateurs?). A suivre également...
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Bonjour à tous,

Après un post sur le forum anglophone, j'ai posté mon problème sur le Tracker.
Pouvez-vous voter pour mon problème (pour le faire remonter plus vite?)
http://tracker.moodle.org/browse/MDL-15143

Merci,
Simon
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Thirot Jean-Luc,
Bonjour,

Why these params verifications takes so long?
"
if (!$context = get_context_instance_by_id($contextid)) {
debugging('Context ID '.intval($contextid).' does not exist!');
return false;
}
" est-ce lui le coupable ?
Mes propres requêtes SQL sur les tables rôles prennent toujours bcp de temps,
Donc ça ne me surprend pas si les requêtes sur les contextes et les rôles prennent du temps.
Why are these verifications here?
la fonction est au singulier il me semble donc que le calcul du contexte doit être dans la fonction. Une solution serait de sauter des requêtes si elle sont fournies en paramètre ou refaire des fonctions plus spécifiques.

Donc sauf si l'on peut optimiser une requête, je ne vois pas le bug ?


Jean-Luc
En réponse à Thirot Jean-Luc

Re: Effroyable lenteurs avec role_assign && role_unassign

par Simon MELIX,
Bonjour,

Je ne peux pas dire que c'est lui le coupable, en fait, la question n'est pas tout à fait celle là, mais plutôt :

Pourquoi vérifie-t-on les paramètres à l'intérieur de cette fonction (et pas avant l'appel)?
ou
Les développeurs de moodle ne sont-ils pas assez sûr de leur code?
ou
Ces vérifications (car il n'y a pas que le get_context_instance_by_id) sont-elles faites uniquement pour les développeurs tiers?

Comme je pense coder "proprement", je vérifie mes paramètres AVANT l'appel de role_assign(), ces vérifications font double emploi, et surchargent l'appel de cette fonction, à mon avis, ce n'est pas là qu'il faut faire cela.

Preuve à l'appui, en commentant ces paramètres (dans mon cas), l'exécution d'un role_assign 186 fois passe de 213 à 2 secondes.... 100 fois moins de temps, c'est pas rien quand même...

Simon
En réponse à Simon MELIX

Re: Effroyable lenteurs avec role_assign && role_unassign

par Thirot Jean-Luc,
Bonjour,
"Pourquoi vérifie-t-on les paramètres à l'intérieur de cette fonction (et pas avant l'appel)?"
Personnellement j'apprécie les contrôles et le principe du "defensiv coding".

"Preuve à l'appui"
comme quoi le code est correct puisqu'il est facile de l'optimiser !

Jean-Luc