PROJET AUTOBLOG


The Miswritings of Flink

Site original : The Miswritings of Flink

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Ruby idiomatique #2

jeudi 6 novembre 2014 à 00:08

Dans le précédent billet, on était arrivé à un résultat plus efficace (et plus élégant !) en utilisant #map au lieu de #each. Pour rappel cela donnait ça :

def values_to_strings(array)  
  array.map do |value|
      value.to_s
  end
end  

On peut faire mieux, plus concis et tout aussi expressif. On pourrait d’abord imaginer utiliser l’écriture suivante :

def values_to_strings(array)  
  array.map { |value| value.to_s }
end  

C’est effectivement mieux mais lorsque tout ce que fait notre itérateur est d’appeler une méthode sur l’objet sur lequel on itère, on peut alors utiliser ce raccourci :

def values_to_strings(array)  
  array.map(&:to_s)
end  

Pas mal non ? ;)

L’astuce réside encore une fois dans la connaissance et la compréhension de Ruby. La méthode #map prend comme tout itérateur un bloc en entrée. Il faut savoir qu’on peut très bien définir un Proc et le passer directement à notre itérateur. En mettant un & devant, on indique que l’argument derrière est un bloc et qu’il répondra donc à #call.

On peut le vérifier de cette manière :

array = [1, 2, 3, 4, 5]  
multiplier = -> (number) { number * 2 }  
multiplier.call(3) # => 6  
array.map(&multiplier) # => [2, 4, 6, 8, 10]  

Tout ça c’est très bien mais on va me répondre que l’exemple plus haut n’utilise pas un Proc ni un lambda mais un Symbol ! Et en effet, il y a une dernière subtilité qui permet de faire fonctionner tout ça. En passant un Symbol en tant que bloc, une conversion implicite aura lieu qui va appeler la méthode #to_proc sur notre Symbol.
Un Symbol converti en Proc prendra comme argument un objet, n’importe lequel, et appellera dessus la méthode ayant pour nom le Symbol défini. Petit exemple :

array = [1, 2, 3, 4, 5]  
size_proc = :size.to_proc  
size_proc.call(array) # => 5  

Et voilà ! C’est comme si on avait directement appelé #size sur array. Pratique non ? :)

Ruby idiomatique #1

mardi 4 novembre 2014 à 00:31

Un truc vraiment bien avec le pair-programming c’est l’échange entre les deux pairs. J’en fais depuis peu mais cela m’a permis de me rendre compte que tout un tas de choses qui me semblent naturelles en Ruby ne le sont pas forcément pour tout le monde. Cela a surtout à voir avec le fait que cela fait maintenant quelques années (huit ans déjà !) que je programme dans ce langage et que je lis pas mal de littérature sur le sujet.

Du coup ça m’a donné envie d’essayer de partager quelques petits trucs et astuces simples qui permettent d’écrire du code Ruby ressemblant à du Ruby et pas du C ou un autre langage ;)

Je vais tenter d’écrire un billet pour chaque petite chose de ce style que je vois et qui pourrait donc profiter à tout le monde.

Utiliser #map

Quand on découvre les itérateurs et les blocks Ruby pour la première fois c’est un peu magique et pour peu qu’on s’arrête à #each (le premier qu’on apprend), on passe à côté de tout un tas de choses intéressantes et efficaces.

Par exemple j’ai vu ce genre de code à plusieurs reprise :

def values_to_strings(array)  
  new_array = []
  array.each do |value|
    new_array << value.to_s
  end
  new_array
end  

On a ici une méthode qui convertit les objets contenus dans un tableau en chaines de caractères dans un nouveau tableau et qui renvoie ce dernier.

Bien que cela fonctionne, ce n’est absolument pas efficace et c’est trop long !
On peut réécrire la même chose de manière très simple comme ceci :

def values_to_strings(array)  
  array.map do |value|
    value.to_s
  end
end  

La méthode #map va itérer tout comme #each mais elle va utiliser chaque valeur renvoyée pour en faire un nouveau tableau. On verra dans un prochain billet comment écrire de manière encore plus efficace cette méthode #values_to_strings.

Des couleurs dans le terminal gnome

dimanche 2 novembre 2014 à 23:58

Je me suis aperçu très récemment (suite à du pair-programming) que le terminal gnome n’était pas configuré pour afficher 256 couleurs par défaut mais seulement 8 !

Il exporte en effet TERM=xterm au lieu de TERM=xterm-256color. Et le plus triste dans tout ça c’est qu’il n’y a aucune option de configuration disponible (dans sa version 3.14.1 en tout cas).

Les autres émulateurs de terminal n’ayant pas le souci, l’astuce réside dans le fait de ne pas écraser bêtement la variable d’environnement TERM pour y mettre xterm-256color mais simplement rajouter la partie -256color au terminal annoncé.

Ce n’est pas compliqué, il suffit de mettre ceci dans votre ~/.profile :

if ! [[ $TERM =~ 256color ]]; then  
  export TERM="$TERM-256color"
fi  

Si vous utilisez un shell tel que zsh, ce fichier ne sera pas lu par défaut. Deux solutions, soit vous mettez ce code dans ~/.zprofile soit vous faites exécuter ~/.profile par votre ~/.zprofile comme suit :

if [[ -f $HOME/.profile ]]; then  
  emulate sh -c ". $HOME/.profile"
fi  

Et voilà ! Pour illustrer la différence, deux images de vim dans le terminal en mode avant/après :

Avant

Après

C’est quand même mieux non ? :)

Lectures Ruby

jeudi 30 octobre 2014 à 23:34
Lectures Ruby

Voici une petite liste de livres que je recommande à toute personne voulant se lancer dans la programmation en Ruby ou qui en fait déjà mais qui cherche à s’améliorer.

C’est typiquement le genre de chose que j’aurais aimé qu’on me recommande il y a quelques années. Cela ne m’empêche pas de continuellement apprendre cela dit (j’ai lu certains de ces livres très récemment) et de toute manière une chose importante à comprendre, je pense, est qu’on peut toujours s’améliorer et apprendre de nouvelles choses et façons de faire.

Autre petit conseil : avant d’apprendre un framework (tel que Rails), il est nécessaire de commencer par le commencement, c’est-à-dire apprendre le langage. Une bonne compréhension de Ruby permet une bien meilleure compréhension de Rails et évite le côté « c’est cool mais c’est de la magie ».

Photo d’entête sous licence CC-BY-NC-ND 2.0 par opacity

Administration ZFS, partie I — les VDEV

samedi 19 juillet 2014 à 19:33

Article d’origine : « ZFS Administration, Part I- VDEVs » publié le 04/12/2012. Licence : CC BY-NC-SA 3.0 US.

Ceci est le premier billet d’une longue série sur comment administrer vos système de fichiers et pools ZFS (zpool). Vous devriez commencer par lire comment installer ZFS sur votre système GNU/Linux pour revenir ensuite à ce billet.

Introduction aux périphériques virtuels

Pour commencer, il faut comprendre le concept des périphériques virtuels (ou VDEV) du fait que ZFS les utilise considérablement en interne. Si vous êtes déjà familier avec RAID, alors ce concept n’est pas nouveau pour vous bien que vous ne vous y référiez pas forcément en tant que « VDEV ». En gros, c’est un meta-périphérique qui représente un ou plusieurs périphériques physiques. Avec du RAID logiciel sous Linux, vous pourriez avoir un périphérique « /dev/md0 » qui représente une grappe RAID-5 de quatre disques. Dans ce cas, « /dev/md0 » serait votre « VDEV ».

Il y a sept types de VDEV dans ZFS :

  1. disk (par défaut) — les disques physiques de votre système ;
  2. file — un chemin absolu vers des fichiers/images pré-alloués ;
  3. mirror — miroir RAID-1 logiciel standard ;
  4. raidz1/2/3 — niveaux de RAID logiciel non standards à base de parité distribuée ;
  5. spare — disques durs marqués comme « remplacement à chaud » (hot spare) pour le RAID logiciel ZFS ;
  6. cache — périphérique utilisé pour un cache de lecture adaptatif de niveau deux (L2ARC) ;
  7. log — un journal séparé (SLOG) appelé « ZFS Intent Log » ou ZIL.

Il est important de noter que les VDEV sont toujours entrelacés (striped) dynamiquement. Tout cela aura plus de sens au fur et à mesure des commandes présentées ci-dessous. Cela dit, supposons que nous ayons quatre disques dans un entrelacement ZFS. La taille de l’entrelacement est calculée par le nombre de disques et la taille des disques dans la grappe. Si d’autres disques sont ajoutés, la taille de l’entrelacement peut être ajustée au besoin pour le disque additionnel, d’où la nature dynamique de l’entrelacement.

Quelques avertissements au niveau d’un zpool

Je me sentirais un peu mal de ne pas mentionner ces mises en garde à propos de ZFS :

Pour les exemples suivants, nous partons du principe que nous avons quatre disques : /dev/sde, /dev/sdf, /dev/sdg et /dev/sdh qui sont tous des clés USB de 8 Go. Entre chacune des commandes, si vous les suivez, soyez sûr d’appliquer l’étape de nettoyage entre chaque section.

Un simple pool

Commençons par créer un simple zpool avec les quatre disques. Je peux créer un zpool nommé « tank » avec la commande suivante :

# zpool create tank sde sdf sdg sdh

Ici j’utilise quatre VDEV disk. Notez que je n’utilise pas les chemins complets vers les périphériques bien que je le pourrais. Étant donné que les VDEV sont toujours entrelacés dynamiquement, c’est effectivement un RAID-0 entre quatre disques (sans redondance). Nous devrions aussi vérifier l’état du zpool :

# zpool status tank
  pool: tank
 state: ONLINE
 scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    tank        ONLINE       0     0     0
      sde       ONLINE       0     0     0
      sdf       ONLINE       0     0     0
      sdg       ONLINE       0     0     0
      sdh       ONLINE       0     0     0

errors: No known data errors

Supprimons le zpool et créons-en un nouveau. Lancez cette commande avant de continuer si vous suivez les instructions dans votre propre terminal :

# zpool destroy tank

Un simple miroir zpool

Dans l’exemple suivant, je souhaite faire un miroir avec les quatre disques (/dev/sde, /dev/sdf, /dev/sdg et /dev/sdh). Aussi, plutôt que d’utiliser le VDEV disk, j’utiliserai « mirror ». La commande est la suivante :

# zpool create tank mirror sde sdf sdg sdh
# zpool status tank
  pool: tank
 state: ONLINE
 scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    tank        ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
        sde     ONLINE       0     0     0
        sdf     ONLINE       0     0     0
        sdg     ONLINE       0     0     0
        sdh     ONLINE       0     0     0

errors: No known data errors

Notez que « mirror-0 » est dorénavant le VDEV et qu’il supervise chaque périphérique physique. Comme mentionné plus tôt, ceci est analogue au périphérique « /dev/md0 » en RAID logiciel sous Linux et représentant les quatre périphériques physiques. Nettoyons notre zpool et créons-en un autre.

# zpool destroy tank

VDEV imbriqués

Les VDEV peuvent être imbriqués. Un parfait exemple est un RAID-1+0 standard (communément appelé « RAID-10 »). C’est un entrelacement de miroirs. Afin de spécifier les VDEV imbriqués, je les mets simplement sur la ligne de commande dans l’ordre (l’emphase est de mon fait) :

# zpool create tank mirror sde sdf mirror sdg sdh
# zpool status
  pool: tank
 state: ONLINE
 scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    tank        ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
        sde     ONLINE       0     0     0
        sdf     ONLINE       0     0     0
      mirror-1  ONLINE       0     0     0
        sdg     ONLINE       0     0     0
        sdh     ONLINE       0     0     0

errors: No known data errors

Le premier VDEV est « mirror-0 » et il gère /dev/sde ainsi que /dev/sdf. Cela a été fait en appelant « mirror sde sdf ». Le second VDEV est « mirror-1 » et il gère /dev/sdg ainsi que /dev/sdh. Cela a été fait en appelant « mirror sdg sdh ». Comme les VDEV sont toujours entrelacés dynamiquement, « mirror-0 » et « mirror-1 » sont entrelacés, d’où la création d’une configuration RAID-1+0. N’oubliez pas de nettoyer avant de continuer :

# zpool destroy tank

VDEV fichiers

Comme mentionné, des fichiers pré-alloués peuvent être utilisés pour configurer des zpools sur votre système de fichiers ext4 (ou autre). Il est à noter que cela est uniquement destiné à des fins de tests et non pas pour stocker des données de production. Utiliser des fichiers est une très bonne façon d’avoir un bac à sable où vous pouvez tester des ratios de compression, la taille de la table de déduplication ou d’autres choses sans réellement engager des données de production. Quand on crée des VDEV file, on ne peut pas utiliser de chemins relatifs et on doit utiliser des chemins absolus. De plus, les fichiers images doivent être préalloués et non pas partiellement alloués ou avoir une allocation fine et dynamique. Voyons comment ça marche :

# for i in {1..4}; do dd if=/dev/zero of=/tmp/file$i bs=1G count=4 &> /dev/null; done
# zpool create tank /tmp/file1 /tmp/file2 /tmp/file3 /tmp/file4
# zpool status tank
  pool: tank
 state: ONLINE
 scan: none requested
config:

    NAME          STATE     READ WRITE CKSUM
    tank          ONLINE       0     0     0
      /tmp/file1  ONLINE       0     0     0
      /tmp/file2  ONLINE       0     0     0
      /tmp/file3  ONLINE       0     0     0
      /tmp/file4  ONLINE       0     0     0

errors: No known data errors

Ici nous avons créé un RAID-0. Nous avons utilisé des fichiers pré-alloués en utilisant /dev/zero et faisant une taille de 4 Go chacun. De ce fait la taille de notre zpool a un espace utilisable de 16 Go. Chaque fichier, tout comme notre premier exemple utilisant des disques, est un VDEV. Bien sûr, vous pouvez traiter les fichiers comme des disques et les mettre dans une configuration de type miroir, RAID-1+0, RAIDZ-1 (voir ci-dessous), etc.

# zpool destroy tank

Pools hybrides

Ce dernier exemple devrait vous montrer les pools complexes que vous pouvez configurer en utilisant différents VDEV. En utilisant nos quatre VDEV file de l’exemple précédent et nos quatre VDEV disk (/dev/sde jusqu’à /dev/sdh), créons un pool hybride avec des disques pour un cache et un journal. Encore une fois, j’ai mis en gras les VDEV imbriqués pour plus de clarté :

# zpool create tank mirror /tmp/file1 /tmp/file2 mirror /tmp/file3 /tmp/file4 log mirror sde sdf cache sdg sdh
# zpool status tank
  pool: tank
 state: ONLINE
 scan: none requested
config:

    NAME            STATE     READ WRITE CKSUM
    tank            ONLINE       0     0     0
      mirror-0      ONLINE       0     0     0
        /tmp/file1  ONLINE       0     0     0
        /tmp/file2  ONLINE       0     0     0
      mirror-1      ONLINE       0     0     0
        /tmp/file3  ONLINE       0     0     0
        /tmp/file4  ONLINE       0     0     0
    logs
      mirror-2      ONLINE       0     0     0
        sde         ONLINE       0     0     0
        sdf         ONLINE       0     0     0
    cache
      sdg           ONLINE       0     0     0
      sdh           ONLINE       0     0     0

errors: No known data errors

Il se passe beaucoup de choses ici, décortiquons tout ça. Premièrement, nous créons un RAID-1+0 en utilisant nos quatre fichiers images préalloués. Remarquez les VDEV « mirror-0 » et « mirror-1 » et ce qu’ils gèrent. Deuxièmement, nous créons un troisième VDEV nommé « mirror-2 » qui n’est en fait pas utilisé pour stocker des données dans le pool mais qui est utilisé comme ZFS Intent Log ou ZIL. Nous verrons le ZIL plus en détail dans un autre billet. Ensuite nous créons deux VDEV pour cacher les données nommés « sdg » et « sdh ». Ce sont des VDEV disk standards que nous avons déjà vus. Cependant, ils sont aussi gérés par le VDEV de « cache ». Ici nous avons donc utilisé six des septs VDEV listés plus haut, le seul manquant est le « spare ».

Prendre en compte l’indentation vous aidera à voir quel VDEV gère quoi. Le pool « tank » est composé des VDEV « mirror-0 » et « mirror-1 » pour du stockage persistant à long terme. Le ZIL est géré par « mirror-2 » qui est composé de /dev/sde et /dev/sdf. Le VDEV de cache en lecture seule est géré par deux disques, /dev/sdg et /dev/sdh. Ni les « logs » ni le « cache » ne sont du stockage à long terme pour le pool, d’où la création d’une configuration de type « pool hybride ».

# zpool destroy tank

Un exemple de la vraie vie

En production, les fichiers seraient des disques physiques et le ZIL ainsi que le cache seraient de rapides SSD. Voilà ma configuration zpool actuelle qui stocke ce blog (NdT : celui de l’auteur de l’article d’origine), entre autres choses :

# zpool status pool
  pool: pool
 state: ONLINE
 scan: scrub repaired 0 in 2h23m with 0 errors on Sun Dec  2 02:23:44 2012
config:

        NAME                  STATE     READ WRITE CKSUM
        pool                  ONLINE       0     0     0
          raidz1-0            ONLINE       0     0     0
            sdd               ONLINE       0     0     0
            sde               ONLINE       0     0     0
            sdf               ONLINE       0     0     0
            sdg               ONLINE       0     0     0
        logs
          mirror-1            ONLINE       0     0     0
            ata-OCZ-REVODRIVE_OCZ-33W9WE11E9X73Y41-part1    ONLINE       0     0     0
            ata-OCZ-REVODRIVE_OCZ-X5RG0EIY7MN7676K-part1  ONLINE       0     0     0
        cache
          ata-OCZ-REVODRIVE_OCZ-33W9WE11E9X73Y41-part2    ONLINE       0     0     0
          ata-OCZ-REVODRIVE_OCZ-X5RG0EIY7MN7676K-part2    ONLINE       0     0     0

errors: No known data errors

Remarquez que mes VDEV « logs » et « cache » sont des SSD OCZ Revodrive tandis que les quatre disques à plateaux sont dans un VDEV RAIDZ-1 (nous traiterons de RAIDZ dans le prochain billet). Quoi qu’il en soit, il faut remarquer que le nom des SSD est « ata-OCZ-REVODRIVE_OCZ-33W9WE11E9X73Y41-part1 », etc. Ils se trouvent dans /dev/disk/by-id/. La raison pour laquelle je les ai choisis à la place de « sdb » et « sdc » est que les périphériques de cache et de log ne stockent pas nécessairement les mêmes métadonnées ZFS. Ainsi, quand le pool est créé au démarrage, il se peut qu’ils ne soient pas intégrés dedans et qu’ils soient manquants. Ou la carte mère peut assigner les lettres des lecteurs dans un ordre différent. Cela n’est pas un problème avec le pool principal mais c’en est un gros sous GNU/Linux avec des périphériques de cache et de logs. En utilisant le nom du périphérique sous /dev/disk/by-id/, cela assure une plus grande persistence et unicité.

On peut remarquer aussi la simplicité de l’implémentation. Pour faire quelque chose de similaire avec LVM, RAID et ext4, il faudrait faire ce qui suit :

# mdadm -C /dev/md0 -l 0 -n 4 /dev/sde /dev/sdf /dev/sdg /dev/sdh
# pvcreate /dev/md0
# vgcreate /dev/md0 tank
# lvcreate -l 100%FREE -n videos tank
# mkfs.ext4 /dev/tank/videos
# mkdir -p /tank/videos
# mount -t ext4 /dev/tank/videos /tank/videos

Ce qui est fait ci-dessus a été fait avec ZFS en une seule commande (moins la création du volume logique, que nous verrons plus tard) au lieu de sept.

Conclusion

Ce billet devrait être un bon point de départ pour avoir une compréhension de base des zpool et VDEV. Tout le reste en découlera. Vous avez maintenant franchi le plus gros obstacle qui est de comprendre comment ZFS gère le stockage groupé. Nous devons encore voir les niveaux RAIDZ et nous devons approfondir les périphériques de cache et de log ainsi que les options de pool tels que la déduplication et la compression. Mais nous verrons tout cela dans d’autres billets. Ensuite nous pourrons nous intéresser aux jeux de données du système de fichiers ZFS, leurs options, leurs avantages et leurs défauts. Mais vous avez maintenant une longueur d’avance sur la partie essentielle des pools ZFS.