Un système simple de stockage basé sur les fichiers

En attendant le portage entièrement en go de bases de données fichier populaires telles que berkeley db ou SQLite, il faut se contenter de système de stockage clé/valeur comme leveldb ou diskv que je vous présenterai dans cet article.

On pourrait qualifier Diskv de base de données nosql basée sur un système clé/valeur.

Principe de fonctionnement

Le principe de diskv est d'utiliser le système de fichier comme espace de stockage avec les principes suivants :

  • Le nom de la base de données est un répertoire.
  • Les clés sont des fichiers stockés dans ce répertoire.
  • Les valeurs sont des données arbitraires (via un tableau d'octet []byte) stockées dans ces fichiers.

On comprend donc une première limite : les clés ne peuvent avoir pour valeur que ce qui est autorisé par le système d'exploitation comme étant un nom de fichier.

Avantages

  • Assez simple d’utilisation.
  • On peut exploiter les informations indépendamment du programme golang à l’aide des fonctions et utilitaires du système (édition, recherche…). À la condition que le contenu soit de type texte.

Inconvénients

  • Les clés ne peuvent pas contenir de caractères qui sont interdits par le système d’exploitation sous-jacent dans les noms de fichiers. Par exemple, Windows interdit les caractères tels que « \ » ou « ? » dans les noms de fichiers.
  • Il peut devenir assez compliqué de faire des requêtes. En tout cas, c’est vous qui les codez, car il n’y a pas de langage de requête contenant des expressions telles que « eq », « neq », « lt », « gt »… (égalité, différence, comparaison…) sur les clés ou le contenu.

Exemple de code

Cas d'usage : valider l'IP Spoffing

Note : Le code d'exemple commenté dans cet article ne nécessite pas de logiciel tiers. On peut en utiliser toutes les fonctionnalités sans les logiciels HP cités ci-après. La citation de ces logiciels permet d'illustrer le propos.

Il m'arrive de faire des tests de performance avec le logiciel HP Preformance Center (logiciel de la société HP qui se base sur la technologie LoadRunner). Une des fonctionnalités de l'outil est l'IP Spoofing. C'est une technique avec laquelle on fait croire à un système sous test que plusieurs machines différentes se connectent, alors qu'il n'y a parfois qu'un seul injecteur impliqué dans le test de charge. Ce qui est utile pour tester l'efficacité de certains systèmes à répartition de charge.

Ce subterfuge est possible en utilisant plusieurs adresses IP avec une configuration matérielle (plusieurs cartes Ethernet connectées au réseau) ou logicielle (faire croire au réseau que l'injecteur est un routeur donnant accès à un sous-réseau) ou un mix des deux.

  • Principe de fonctionnement de l'IP Spoofing

J'ai récemment reçu deux serveurs dans le parc que j'administre et je voulais vérifier ma configuration (c.-à-d. savoir si ma configuration était capable de faire un tir avec de l'IP spoofing). Une des nombreuses solutions est de tester un site web et de regarder dans les fichiers de log si l'adresse IP d'origine est variée (les adresses IP doivent correspondre à ce que l'on a configuré côté Performance Center et/ou avec l'équipe réseau de l'entreprise). Seulement, il n'y aurait pas eu matière à rédiger cet article :).

Fonctionnement de mon application

Ma webapp de test a deux points d'accès :

      / Qui sera la page d'accueil. On visualisera les entrées de la base (adresses IP et dernière heure d'accès), classées par ordre alphabétique (selon le critère "Adresse IP"). Par exemple :
    Key : 11.204.220.91 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.204.220.92 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.204.220.93 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.204.220.94 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.204.220.95 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.189.18.206 ==> Nov 22, 2013 at 4:55pm (PM)
    Key : 11.160.164.219 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.160.164.220 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.160.164.221 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.160.164.222 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 11.160.164.223 ==> Nov 22, 2013 at 5:02pm (PM)
    Key : 127.0.0.1 ==> Nov 22, 2013 at 4:42pm (PM)
    
      /targetAdresse sur laquelle pointera mon script VUGen (le logiciel qui permet de développer des scripts de test de charge).

Installation

Récupérer et installer le paquet golang de diskv à l'aide des commandes suivantes :

go get github.com/peterbourgon/diskv
go install github.com/peterbourgon/diskv

Note: Le paquet contient une dépendance à github.com/petar/GoLLRB, un package d'arbre de recherche binaire que nous utiliserons dans le but de classer les résultats de notre requête à la base.

import (
	"github.com/peterbourgon/diskv"
)

Fonction de transformation

On commence par écrire la fonction qui décrit la manière dont les clés seront stockées. Ici, on indique de stocker tous les fichiers (dont le contenu stockera nos valeurs) seront stockés dans le même répertoire (dans notre cas, le répertoire clients).

flatTransform := func(string) []string { return []string{} }

Fonction de tri

Puis on crée une fonction qui décrit la manière dont les informations seront triées (bien sûr, cette étape est optionnelle si vous ne souhaitez pas trier les informations ou déléguer le tri au client par exemple avec la bibliothèque Javascript DataTable) :

func strLess(a, b string) bool { return a < b }

initialisation du gestionnaire de BDD

On initialise ensuite le gestionnaire de la base de données qui la crée si elle n'existe pas (c.-à-d. la création du répertoire).

var db *diskv.Diskv

    db = diskv.New(diskv.Options{
        BasePath:     "clients",
		Transform:    flatTransform,
        CacheSizeMax: 1024 * 1024,
		Index:        &diskv.LLRBIndex{},
        IndexLess:    strLess,
    })

Les handlers HTTP

Le code de nos contrôleurs sera assez simple. Vous remarquerez une petite astuce. Si vous souhaitez passer un contenu HTML à une vue sans que le filtre de sécurité du paquet html/template ne le filtre en l'échappant, il faut utiliser un champ template.HTML au lieu d'un champ string.

type Page struct {
	Title		string
	Content		template.HTML
}

Contrôleur de la page d'accueil

Le contrôleur de la page d'accueil itère sur toutes les clés présentes dans la base de données (range db.Keys()) et pour chacune des clés trouvées, il lit la valeur associée (en l'occurrence le contenu du fichier qui a pour nom la clé) à l'aide de l'instruction db.Read(k). Enfin, on passe la liste des informations trouvées à la vue.

func handlerHome(w http.ResponseWriter, r *http.Request) {
	var content = ` 
` for k := range db.Keys() { v, err := db.Read(k) checkHttpError(err, w) content += `Key : ` + k + ` ==> ` + string(v) + `
` } var p = Page{Title: "Home", Content: template.HTML(content)} err := templates.ExecuteTemplate(w, "base.html", p) checkHttpError(err, w) }

Contrôleur de la page cible

Le contrôleur de la page cible vous permet de faire la connaissance de quelques fonctionnalités de la bibliothèque standard de golang :

  1. Récupération de l'adresse IP du client avec r.RemoteAddr
  2. Utilisation du formatage des dates à l'aide d'un modèle (la chaîne de caractères "Jan 2, 2006 at 3:04pm (MST)")
  3. Comment convertir une chaîne de caractères en un tableau d'octets (à l'aide de l'instruction []byte(timeNow))
func handlerTarget(w http.ResponseWriter, r *http.Request) {
	ip := strings.Split(r.RemoteAddr,":")[0]
	const layout = "Jan 2, 2006 at 3:04pm (MST)"
	t := time.Now()
	timeNow := t.Format(layout)
	err := db.Write(ip, []byte(timeNow))
	checkHttpError(err, w)
	content := `
` + ip + ` => ` + timeNow + `
` p := Page{Title: "Home", Content: template.HTML(content)} err = templates.ExecuteTemplate(w, "base.html", p) checkHttpError(err, w) }

Code du template de base

Le code du template de base est très simple :

<!DOCTYPE html>
<html class="no-js" lang="en">
  <head>
    <meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title></title>
  </head>
  <body>
		
  </body>
</html>

Autres fonctionnalités

Mon code final est un peu plus complet, il contient également de quoi charger un fichier de configuration et la compression des retours HTTP. On peut aussi ajouter un handler HTTP pour effacer le contenu de la base de données à l'aide du code suivant :
  err:=db.EraseAll()

Aller plus loin

Cet article est assez complet quand aux possibilités de cette base de données, cependant il n'est pas exhaustif et ne couvre pas les cas plus simples ou la compression des données.
Vous pouvez vous rendre sur la page officielle du projet et consulter la documentation. Et, comme pour la plupart des paquets, vous pouvez consulter les fichiers de test (par exemple, compression_test.go) qui illustrent différents cas de figure et les différentes possibilités d'utilisation de l'API de Diskv.

Étiquettes :   diskv   keyvalue   nosql   thirdparty 
Portrait de Benjamin BALET
Benjamin BALET
Consultant APM

Retrouvez mes cooordonées

Benjamin BALET sur viadeo






Vous aimerez aussi

Les lois de la réflexion

Une traduction du blog officiel de golang expliquant le mécanisme de la réflexion en Go.   Lire »

Gobs le format natif d'échange de données en Go

Traduction d'un article du blog officiel expliquant comment échanger des données entre deux programmes golang grâce à un format natif   Lire »

Comment écrire du code Go ?

Traduction d'une partie des spécifications officielles du langage Go, cet article explique comment développer en Go.   Lire »

Gérer les informations de session avec Gorilla

La bibliothèque standard de go ne gère pas les variables de session d'une application. Il existe une solution avec le toolkit Gorilla   Lire »

Comment gérer efficacement les erreurs en golang ?

Préconisations officielles pour la gestion des erreurs dans un programme golang. Cet article complète les explications sur panic, defer et recover   Lire »

Commentaires

Soyez le premier à commenter cet article

Publier un commentaires

Tous les commentaires sont soumis à modération. Les balises HTML sont pour la plupart autorisées. Les liens contextuels et intéressants sont en follow.

(requis)
(requis)
(requis, mais non publié)
(recommandé si vous souhaitez être publié)