Apprendre à utiliser MySQL comme un moteur NoSQL

Yoav Abrahami

Traducteur

Laethy

Longtemps considéré comme un SGBD typiquement SQL, MySQL présente bien des capacités liées aux spécificités du NoSQL. Dans ce tutoriel, vous allez apprendre à utiliser MySQL comme un moteur NoSQL.

- Titre : Apprendre à utiliser MySQL comme un moteur NoSQL

- Auteur : Yoav Abrahami

- Traducteur : Laethy

- Parution : 13 juin 2016

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2016 Yoav Abrahami. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Pourquoi utiliser MySQL comme un moteur NoSQL ?

- II. Quelques consignes à suivre pour utiliser Mysql comme un moteur NoSQL

- III. Conclusion

I - Pourquoi utiliser MySQL comme un moteur NoSQL ?

Quand quelqu'un clique sur un lien vers un site Wix, son navigateur envoie une requête HTTP à un serveur Wix avec l'adresse du site. Cela se produit si l'adresse est à un site premium Wix avec un domaine personnalisé (par exemple, domain.com) ou d'un site gratuit sur un sous-domaine du domaine Wix (par exemple, user.wix.com/site). Ce serveur doit résoudre le site demandé à l'adresse du site en effectuant une clé/valeur pour la résolution de l'URL vers un site. On note l'URL comme une route pour la discussion suivante.

La table de routage est utilisée pour résoudre l'adresse du site à un objet de site. Parce que les sites peuvent avoir plusieurs routes, la relation est plusieurs à un. Une fois que le site est trouvé, l'application le charge pour utilisation. L'objet site lui-même a une structure complexe qui comprend deux listes d'objets enfants, différents services que le site utilise. Voici un exemple de modèle de nos objets, en supposant une base de données SQL standard et un schéma normalisé :

Lors la mise à jour d'un site avec le modèle normalisé traditionnel, nous avons besoin d'utiliser une transaction pour mettre à jour plusieurs tables pour nous assurer de préserver la cohérence des données. (Notez qu'une transaction utilise un verrou de niveau DB qui empêche simultanément les écritures et parfois la lecture des tables concernées.) En continuant avec ce modèle, nous aurions probablement une série de clés dans chaque table, des clés étrangères, et un index sur le champ URL dans la table des routes.

Cependant, il y a un certain nombre de problèmes avec cette forme de modélisation :

- les verrous limitent l'accès à la table, donc en cas d'une utilisation à haut débit, il peut limiter notre performance ;

- la lecture de l'objet implique soit quelques requêtes SQL (quatre dans ce cas) ou dans un autre cas, se joint avec des implications de latence à nouveau ;

- la série de clés impose des verrous et limite à nouveau la vitesse d'écriture.

Ces questions représentent les limites de vitesse et des accès simultanés que nous pouvons obtenir de MySQL (ou tout autre moteur de SQL). À cause de ces lacunes, et vu le fait que l'utilisation est en mode clé/valeur, de nombreux développeurs choisissent de chercher une solution NoSQL qui offre une meilleure vitesse et une bonne gestion des accès simultanés, au détriment même de la stabilité, de la cohérence, ou de la disponibilité.

Au Wix nous avons constaté que MySQL, lorsqu'il est utilisé de façon créative comme un magasin clé/valeur, peut avoir un meilleur rendement par rapport à MySQL utilisé avec un modèle de données normalisées (comme celui ci-dessus) et à la plupart des moteurs NoSQL. Il suffit d'utiliser MySQL comme moteur NoSQL. Notre système actuel a été monté en puissance au niveau de la vitesse, des accès simultanés et des temps de latence, qui donne des résultats impressionnants comparativement à tout moteur NoSQL. Voilà quelques-unes de nos données :

- une configuration active-active-active dans trois Datacenters ;

- la vitesse est dans l'ordre de 200 000 RPM ;

- la table des routes a plus de 100 000 000 enregistrements, soit une taille de 10 Go ;

- la table des sites a plus de 100 000 000 enregistrements, soit une taille de 200 Go.

- le temps de latence dans la lecture est en moyenne de 1,0-1,5 ms (en fait, 0,2-0,3 ms dans un Datacenter).

Notez que la latence de l'ordre de 1.0 ms est considérée comme impressionnante pour la plupart des moteurs utilisant le mode clé/valeur, et ce, à la fois open source et basé cloud ! Et nous y parvenons avec MySQL (considéré comme le moteur SQL de base).

Voici le schéma actuel que nous utilisons :

1. CREATE TABLE routes (

2. route varchar(255) NOT NULL,

3. site_id varchar(50) NOT NULL,

4. last_update_date bigint NOT NULL,

5. PRIMARY KEY (key),

6. KEY (site_id)

7. )

9. CREATE TABLE sites (

10. site_id varchar(50) NOT NULL,

11. owner_id varchar(50) NOT NULL,

12. schema_version varchar(10) NOT NULL DEFAULT '1.0',

13. site_data text NOT NULL,

14. last_update_date bigint NOT NULL,

15. PRIMARY KEY (site_id)

16. ) /*ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=16*/;

Tous les champs qui ne sont pas utilisés comme condition dans une requête ont été mis dans un champ blob unique (le champ de texte site_data). Cela inclut les tables sous-obj, ainsi que tout champ sur la table d'objet lui-même. Notez également que nous n'utilisons pas des clés en série, en lieu et place, nous utilisons varchar (50), qui stocke les valeurs GUID générées.

Voici la requête que nous utilisons qui a une grande vitesse et un faible temps de latence :

1. select * from sites where site_id = (

2. select site_id from routes where route = ?

3. )

Elle fonctionne en exécutant en premier une requête sur la table routes par un index unique, qui doit retourner un seul résultat. Ensuite, nous recherchons le site par sa clé primaire, qui retournera aussi un seul enregistrement. La syntaxe de requête imbriquée assure que nous faisons un seul aller-retour vers la base de données pour exécuter les requêtes SQL.

Le résultat, illustré ci-dessus, est une moyenne de ~ 1 ms de performance, ce qui donne donne un trafic élevé et un taux de mise à jour élevé. Les mises à jour sont semi-transactionnelles, et même souvent sans transaction. Ceci parce que nous entrons dans le site complet avec une seule instruction d'insertion, et jusqu'à ce que nous entrions dans les routes, il ne sera pas trouvé dans les requêtes. Donc, si nous entrons dans le site en premier, puis les routes, nous sommes assurés d'avoir un état cohérent, même en cas de pointe où nous pouvons avoir des données orphelines dans la table des sites.

II - Quelques consignes à suivre pour utiliser Mysql comme un moteur NoSQL

Pour l'utilisation de l'expérience acquise dans l'exemple ci-dessus (et d'autres cas à Wix), nous avons conçu une courte liste de lignes directrices pour l'utilisation de MySQL comme moteur NoSQL.

La principale chose à garder à l'esprit lorsque vous utilisez MySQL comme moteur NoSQL est d'éviter d'utiliser des verrous de DB ou des requêtes complexes :

- n'utilisez pas des transactions, qui introduisent des verrous. Au lieu de cela, utilisez des transactions applicatives ;

- n'utilisez pas les clés en série. Les clés en série introduisent des verrous et compliquent les configurations actives-actives ;

- utilisez les clés uniques générées par le client. Nous utilisons les GUID.

Lors de la conception de votre schéma qui devra être optimisé pour les lectures, voici quelques lignes directrices supplémentaires à suivre :

- ne normalisez pas ;

- les champs existent seulement pour être indexés. Si un champ n'est pas nécessaire pour un index, stockez-le dans un type blob/texte (tel que JSON ou XML) ;

- n'utilisez pas les clés étrangères ;

- concevez votre schéma pour ne permettre que la lecture d'une seule ligne par requête ;

- n'effectuez pas des commandes Alter Table. Les commandes Alter Table introduisent des verrous et des temps d'arrêt. Au lieu de cela, utilisez les migrations en direct.

Lors des requêtes sur les données :

- requête pour les enregistrements par clé primaire ou par index ;

- n'utilisez pas de jointures ;

- n'utilisez pas d'agrégations ;

- exécutez les requêtes de routine de maintenance (BI, exploration de données, etc.) sur un réplicat et non sur la base de données maître.

Nous avons l'intention d'écrire un autre billet de blog avec plus d'informations sur les migrations en direct et les transactions applicatives.

III - Conclusion

Le plus important dans ce tutoriel est de vous inviter à penser différemment. Il est super d'utiliser MySQL comme moteur NoSQL, ce qui n'est pas l'architecture pour laquelle il a été conçu. Comme démontré dans ce tutoriel, un exemple pour cela est d'utiliser MySQL au lieu de moteurs NoSQL dédiés qui sont construits pour un accès clé/valeur. À Wix, MySQL est le moteur de choix pour les cas clé/valeur (entre autres), car il est facile à utiliser, et il a un vaste écosystème. En prime, il fournit des mesures de temps latence, de vitesse et d'accès simultanés qui équivalent, sinon surpassent, la plupart des moteurs NoSQL.