Supprimer les freezes des connexions WiFi sous Ubuntu

Je viens de tomber sur un article intéressant, qui m’a permis de me débarrasser de mes vilains freezes de connexion WiFi sur mon portable : [wifi] Réduire les lags sous linux ( Network Manager ) » Le Blog du grand loup Zeur.

Pour résumer, si votre connexion freeze toutes les 2 minutes environ, ce peut être à cause de la recherche automatique de réseau du Network Manager d’Ubuntu. Cela a été corrigé dans la dernière version (10.10), et il suffit d’ajouter un BSSID sur la connexion WiFi pour la désactiver.

Ce BSSID correspond en général à l’adresse MAC du point d’accès, et peut être obtenue avec la commande suivante :

$ iwlist scanning
lo        Interface doesn't support scanning.

eth0      Interface doesn't support scanning.

wlan0     Scan completed :
 Cell 01 - Address: 00:14:BF:A5:B7:FB
 Channel:5

Gentoo : téléchargements impossibles avec emerge

Récemment, toutes mes mises à jour système se sont mise à planter lors du téléchargement des sources par portage, quel que soit le miroir utilisé :

web ~ # emerge gdb
Calculating dependencies... done!

>>> Verifying ebuild manifests

>>> Emerging (1 of 1) sys-devel/gdb-7.0.1
>>> Downloading 'http://distfiles.gentoo.org/distfiles/gdb-7.0.1.tar.bz2'
>>> Downloading 'ftp://sources.redhat.com/pub/gdb/releases/gdb-7.0.1.tar.bz2'
>>> Downloading 'http://ftp.gnu.org/gnu/gdb/gdb-7.0.1.tar.bz2'
!!! Couldn't download 'gdb-7.0.1.tar.bz2'. Aborting.
 * Fetch failed for 'sys-devel/gdb-7.0.1', Log file:
 *  '/var/tmp/portage/sys-devel/gdb-7.0.1/temp/build.log'

>>> Failed to emerge sys-devel/gdb-7.0.1, Log file:

>>>  '/var/tmp/portage/sys-devel/gdb-7.0.1/temp/build.log'

 * Messages for package sys-devel/gdb-7.0.1:

 * Fetch failed for 'sys-devel/gdb-7.0.1', Log file:
 *  '/var/tmp/portage/sys-devel/gdb-7.0.1/temp/build.log'

Rien d'intéressant dans les logs, et le mode debug d'emerge n'apporte aucune information supplémentaire sur l'erreur de téléchargement. De plus, un wget manuel fonctionne parfaitement :

web ~ # wget http://distfiles.gentoo.org/distfiles/gdb-7.0.1.tar.bz2
--2010-10-13 18:47:22--  http://distfiles.gentoo.org/distfiles/gdb-7.0.1.tar.bz2
Resolving distfiles.gentoo.org... 130.239.17.6, 137.226.34.42
Connecting to distfiles.gentoo.org|130.239.17.6|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://mirrors.kernel.org/gentoo/distfiles/gdb-7.0.1.tar.bz2 [following]
--2010-10-13 18:47:22--  http://mirrors.kernel.org/gentoo/distfiles/gdb-7.0.1.tar.bz2
Resolving mirrors.kernel.org... 130.239.17.6, 199.6.1.174
Reusing existing connection to distfiles.gentoo.org:80.
HTTP request sent, awaiting response... 200 OK
Length: 17614682 (17M) [application/x-bzip2]
Saving to: `gdb-7.0.1.tar.bz2'

100%[===============================================================================================>] 17,614,682  4.66M/s   in 3.9s

2010-10-13 18:47:27 (4.28 MB/s) - `gdb-7.0.1.tar.bz2' saved [17614682/17614682]

J'ai donc passé quelques heures à mettre des print un peu partout dans le code de portage, pour finalement déterminer que le script s'arrêtait violemment lors de l'appel à la fonction os.setgroups par la méthode _exec de process.py :

web ~ # head -380 /usr/lib/portage/pym/portage/process.py | tail -20
 os.close(fd)
 except OSError:
   pass

 # Set requested process permissions.
 if gid:
   os.setgid(gid)
 if groups:
   os.setgroups(groups)
 if uid:
   os.setuid(uid)
 if umask:
   os.umask(umask)
 if pre_exec:
   pre_exec()

 # And switch to the new process.
 os.execve(binary, myargs, env)

Un simple test permet de constater que la méthode os.setgroups() est en cause :

web ~ # python -c "import os; os.setgroups([250])"
Segmentation fault

Le workaround

Ce problème apparait lorsque emerge change son utlisateur et ses groupes avant le téléchargement. Un workaround simple est donc de désactiver cette fonctionalité, en ajoutant la ligne suivante dans le fichier /etc/make.conf :

FEATURES="-userfetch"

Cause et solution

Toutefois, ce problème est apparu récemment, et ne peut être reproduit sur mes autres installations Gentoo. J'ai donc repensé aux modifications que j'avais apportées récemment, et j'ai eu un déclic : j'ai réduit la taille de la pile pour optimiser la mémoire consommée par Apache !

J'avais donc réduit la taille de la pile de 8Mo à 256 ko. En essayant de l'augmenter un peu :

web ~ # ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 16120
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 256
cpu time               (seconds, -t) unlimited
max user processes              (-u) 16120
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
web ~ # ulimit -s 512
web ~ # python -c "import os; os.setgroups([250])"
web ~ #

C'était donc bien la taille de la pile.

Visiblement ma modification dans le fichier /etc/conf.d/rc n'impactait pas uniquement le lancement des services comme je le pensais… J'ai donc changé la variable RC_ULIMIT :

RC_ULIMIT="-s 512"

Utiliser ccache entre plusieurs VPS OpenVZ Gentoo

J’ai décidé d’utiliser une distribution Gentoo avec un noyau OpenVZ, hébergeant des VPS eux aussi sous Gentoo.

L’utilisation d’une distribution Gentoo sur un serveur animé par un petit Celeron 1.2 GHz pose quelques soucis de temps d’installation / mise à jour des paquets. Ceci est d’autant pire qu’il faut multiplier ce temps par le nombre de VPS…

ccache est un cache de compilateur, qui permet d’accélérer notablement les recompilations futures de sources identiques.  Ceci est déjà fort appréciable pour accélérer les recompilations lors du changement de certains use flags.

Partager le cache entre les VPS

Afin d’éviter de recompiler les même paquets sur chacun des VPS, j’ai décidé de partager le cache de ccache via NFS (comme je le fais pour l’arbre de paquets Gentoo par exemple).

Sur l’hôte

J’utilise donc le serveur NFS déjà configuré sur l’hôte OpenVZ :

mkdir -p /var/tmp/ccache
echo "/var/tmp/ccache 10.0.0.0/255.255.255.0(async,rw,no_subtree_check,insecure,no_root_squash)" >> /etc/exports
exports -r

Sur les VPS

Il suffit d’installer ccache et d’utiliser le partage NFS comme répertoire de cache :

emerge ccache
echo "host:/var/tmp/ccache /var/tmp/ccache nfs rw 0 0" >> /etc/fstab
mkdir /var/tmp/ccache
mount /var/tmp/ccachecd /var/tmp
mkdir ccache
chown portage:portage ccache
chmod 775 ccache
echo "CCACHE_DIR=\"/var/tmp/ccache\"" >> /etc/env.d/99local
env-update
source /etc/profile

Il ne reste alors plus qu’à configurer portage pour utiliser ccache, en ajoutant les lignes suivantes dans le fichier /etc/make.conf :

CCACHE_SIZE="4G"
CCACHE_DIR="/var/tmp/ccache"
CCACHE_COMPILERCHECK="content"
FEATURES="ccache"

La directive CCACHE_COMPILERCHECK permet d’indiquer a ccache d’utiliser le contenu du binaire GCC plutôt que sa date de modification pour identifier la version du compilateur. La configuration par défaut utilise la date de modification du fichier, qui sera forcément différente entre deux VPS utilisant pourtant la même version de GCC.

Contrairement à ce qu’affirme portage à la fin de l’installation de GCC, l’ajout de la variable FEATURES m’a été nécessaire pour qu’il utilise ccache…

Vérification

Il suffit maintenant de compiler le même paquet successivement sur deux VPS et de vérifier que ccache est bien utilisé sur le second.

Après la compilation sur le premier VPS :

web tmp # ccache -s
cache directory                     /var/tmp/ccache
cache hit                              0
cache miss                            31
called for link                        1
autoconf compile/link                 15
no input file                          4
files in cache                        62
cache size                           168 Kbytes
max cache size                       4.0 Gbytes

Après la compilation sur le second VPS (qui a du être beaucoup plus rapide) :

web tmp # ccache -s
cache directory                     /var/tmp/ccache
cache hit                             31
cache miss                            31
called for link                        5
not a C/C++ file                      64
autoconf compile/link                 45
unsupported compiler option           56
no input file                         13
files in cache                        62
cache size                           168 Kbytes
max cache size                       4.0 Gbytes

Référence

Réduire l’utilisation mémoire du MPM Worker d’Apache

Selon la documentation d’Apache, le MPM worker nécessite moins de ressources que l’historique pre-fork. Cherchant à économiser les ressources de mon petit Kimsufi, j’ai voulu essayer ce mode :

echo 'www-servers/apache threads' >> /etc/portage/package.use
echo 'APACHE2_MPMS="worker"' >> /etc/make.conf
emerge apache

Cependant, je fus assez déçu du résultat, car avec les paramètres par défaut plus de RAM était consommée qu’avec le MPM prefork (pour un faible trafic).

apache   27556  0.0  0.7  24352 15448 ?        S    00:54   0:00 /usr/sbin/apache2
apache   27557  0.0  0.7  24984 15312 ?        S    00:54   0:00 /usr/sbin/apache2
apache   27558  0.0  0.8 246632 16252 ?        Sl   00:54   0:00 /usr/sbin/apache2
apache   27561  0.0  0.8 246632 16252 ?        Sl   00:54   0:00 /usr/sbin/apache2

La solution : diminuer la taille de la pile

Après quelques recherche, je suis tombé sur ce post, où un utilisateur avait le même problème, et la solution :

Stack size is counted towards virtual memory
Default stack size is very high on Linux (8MB)
Every thread uses separate stack
=> multi threaded application will use at least number_of_threads * 8MB virtual memory!

Par défaut le MPM worker crée 25 threads par processus, utilisant chacun au moins 8 Mo pour la pile ! En réduisant la taille par défaut de la pile, on peut largement diminuer la mémoire consommée par Apache :

web apache2 # ulimit -s
8192
web apache2 # ulimit -s 256
/etc/init.d/apache2 restart

On constate alors que la mémoire virtuelle utilisée par chacun des processus apache a diminuée drastiquement :

apache   28029  0.0  0.7  24352 15444 ?        S    00:56   0:00 /usr/sbin/apache2
apache   28031  0.0  0.7  24984 15460 ?        S    00:56   0:00 /usr/sbin/apache2
apache   28032  0.0  0.8  32660 17340 ?        Sl   00:56   0:00 /usr/sbin/apache2
apache   28035  0.0  0.8  32500 17320 ?        Sl   00:56   0:00 /usr/sbin/apache2

De plus, ceci est valable pour tous les processus multi-threads, comme fail2ban ou mysqld !

Limiter la taille de la pile au boot

L’appel précédent à ulimit n’est valable que dans le shell courant.

Afin d’appliquer automatiquement cette limite pour tous les services sur Gentoo, il faut ajouter la ligne suivante dans le fichier /etc/conf.d/rc :

RC_ULIMIT="-s 256"

Remarques

J’ai ici utilisé la taille recommandée dans le post cité. J’ai tout de même une légère crainte que le passage de 8192 à 256 ne soit un peu excessif. Je verrai à l’usage s’il est nécessaire d’augmenter cette valeur.

Edit : en effet, il ne m’aura fallu que quelques jours pour détecter un problème… Impossible pour portage de télécharger quoi que soit lors d’un emerge. J’ai donc ré-augmenté un peu la taille de la pile en la passant à 512k.