Teiid, unifiez vos données et simplifiez votre architecture

GNU/Linux Magazine HS n° 078 | mai 2015 | Romain Pelisse
  • Actuellement 0 sur 5 étoiles
  • 1
  • 2
  • 3
  • 4
  • 5
En ces années « Big Data », ce n'est pas seulement la taille ou la quantité de données qui représente un nouveau défi, mais aussi leur nature. En effet, que ce soit pour des raisons techniques de tenue de charge ou par souci de simplicité, les données sont sauvegardées dans de plus en plus de systèmes différents. Si l'on pouvait, au début des années 2000, estimer que nos données applicatives seraient stockées, la plupart du temps, dans une base de données relationnelle, ou éventuellement extraites d'un système historique (mainframe), le paysage a assez radicalement changé.

Non seulement les bases de données NoSQL se sont multipliées, mais le rêve de la « portabilité SQL » est loin d'avoir tenu toutes ses promesses; ce qui laisse apparaître, dans beaucoup de systèmes d'informations, un ensemble hétéroclite de systèmes, tous nés fortement non égaux en termes d'interopérabilité, de fonctionnalités et de capacité transactionnelle. Du NoSQL comme MongoDB à la grille de données avec InfiniSpan, ou encore Cassandra, en passant par des bases orientées document ou simplement différents systèmes de gestion de base de données tels que PostgresQL et MariaDB, l'extension du périmètre de la lutte est conséquente.

Désormais, localiser où est la donnée, pour peu qu'elle ne vive que dans un unique système, est devenu une tâche ardue. De même, disposer d'une vision globale de ces dernières, et obtenir, par exemple, un rapport donnant l'âge moyen du client « Web », inscrit il y a moins de 3 mois, qui a acheté le dernier Madonna - tâche qu'une simple requête SQL aurait pu faire à l'époque de la centralisation des données - est, de nos jours, un travail complexe et difficile.

Or, que faisons-nous, nous ingénieurs des systèmes d'informations quand les choses deviennent trop complexes ? Nous cherchons le salut dans une providentielle couche d'abstraction. Et si nous avons abstrait, à l'aide d'API, les systèmes, les services, et même le matériel, pourquoi ne pourrions-nous pas aussi, à notre tour, abstraire nos sources de données pour en faciliter leur utilisation ?

1. Introduction

Si l'introduction mentionne spécifiquement la création d'un « rapport », ce n'est pas innocent. En effet, les concepts fondamentaux de la virtualisation de données viennent directement du monde du reporting et de la Business Intelligence (BI), chez qui ces besoins sont apparus très tôt. Car, pour construire des rapports issus de multiples bases de données d'une entreprise – comme, par exemple, fournir une vision unifiée des ventes, après le rachat d'un concurrent qui utilise un autre standard de base de données que la société mère, il fallait déjà accéder, de manière uniforme, à différentes sources de données.

Bref, cette problématique était déjà identifiée et des solutions comme celle que nous allons utiliser pour illustrer cet article, Teiid, sont apparues. Néanmoins, leur application dépasse de loin les cas d'utilisation du BI et du reporting, comme nous allons le voir. Mais ces solutions profitent déjà des années d'expérience et de travail réalisées dans ce domaine. Pour résumer, comme disent nos grand-mères, c'est dans les vieux pots qu'on fait les meilleures confitures !

Et c'est aussi dans cet esprit, qui est aussi celui très « pratique » de GNU/Linux Magazine, que nous allons d'abord commencer par la mise en place de cas concrets, qui permettront au lecteur de bien comprendre les mécanismes de Teiid, avant de synthétiser sur ses avantages, dans un contexte « Big Data » (ou pour aider un Data Scientist dans son travail).

2. Étude de cas

Plutôt que d'expliciter la ou les théories derrière la fédération de données, nous allons décrire un cas d'étude concret et inspiré par des situations réelles. Une fois ceci fait, nous verrons comment la mise en place d'une virtualisation de données - avec les fonctionnalités de Teiid, va permettre de simplifier grandement le problème et de répondre aux besoins de manière efficace.

2.1 La société GrosseFusion, son métier, son plan marketing et ses rachats

La société GrosseFusion vient de racheter un de ses concurrents directs, PetiteBoite, mais aussi une société de distribution, Distributeur (vous me pardonnerez de nommer ces acteurs, comme des variables de programmation, mais ces noms ont l'avantage d'être descriptifs). Forte de ces deux acquisitions, la société souhaite mettre à profit les atouts et parts de marché de ses différents composants pour augmenter ses revenus et se diversifier (rien de bien original, jusque-là !).

Un grand « plan maître » a été décidé au niveau de la direction de la société et l'un de ses composants est l'analyse des clients de PetiteBoite, associée aux réseaux de distribution de Distributeur. Pour faire très simple, l'objectif est d'identifier une catégorie de consommateurs, sensibles aux produits de PetiteBoite et de les fidéliser, pour les inciter - à l'aide de la marque de la société - à s'intéresser aux produits de GrosseFusion, à condition qu'elle dispose de distributeurs près de chez eux.

La demande semble simple : générer un rapport, puis exploiter les données. Mais le pendant technique est beaucoup plus complexe qu'il n'y paraît, car chaque structure dispose de son propre système d'informations. Et bien évidemment, de nombreuses technologies doivent être utilisées pour arriver à ses fins.

Pour corser un peu les choses, l'objectif n'est pas de réaliser un rapport à usage unique, mais de mettre en place un service en ligne, acceptant quelques paramètres (comme l'âge de la cible, le type de produit, etc.) et pouvant générer des rapports à la demande.

2.2 Les données de PetiteBoite

Tout d'abord, regardons les données de fidélisation client de PetiteBoite. La société étant jeune et très innovante, elle a choisi de persister les données relatives à la fidélisation dans une instance de MariaDB. Elle ne dispose pas de système en interne, ces données sont hébergées par un fournisseur de base de données à la demande.

L'application de fidélisation a été conçue par une société externe, et donc il n'y a aucune compétence spécifique à MariaDB en interne de PetiteBoite. GrosseFusion a bien évidemment des compétences SGDBR, mais uniquement - et sans surprise - sur Oracle.

2.3 Les données de GrosseFusion

Pour établir la liste des clients potentiels de PetiteBoite, il est aussi nécessaire d'extraire des données de « profil de clients » depuis les sources de données de GrosseFusion. En clair, pour prendre un exemple très simple, il n'est nécessaire d'identifier que les clients de 14 à 35 ans de GrosseFusion qui apprécient beaucoup un de leurs produits, proche (en terme, disons, marketing) de produits proposés par PetiteBoite.

Là encore, techniquement, les choses sont très différentes ; les données clients sont hébergées par une solution CRM propriétaire qui les sauvegarde dans une base de données SGDR, la célèbre base de données Oracle. À côté de ceci, les données produits de GrosseFusion vivent également dans une autre base de données SQL, elle aussi hébergée sur Oracle.

2.4 Les données de Distributeur

Distributeur a un métier très différent et surtout beaucoup plus « mobile ». Après quelques projets qui ont tourné au fiasco, la société s'est débarrassée de son système de gestion de base de données relationnelle pour passer à du pur NoSQL avec MongoDB. C'est grâce aux performances de ce dernier, très adapté à son modèle de données simples - et le fait que leurs cas d'utilisation ne nécessitent aucune forme de transaction, qu'elle a réussi à devenir leader sur son marché et à attirer l'attention de GrosseFusion.

Malheureusement pour cette dernière, ceci complique beaucoup la construction du rapport, car la base de données ne dispose d'aucun des moteurs usuels de recherche des sources de données SQL. En outre, là encore, les seules compétences en NoSQL dans les équipes de Distributeur sont les équipes de développement qui ont conçu l'application mobile utilisée par la flotte de la compagnie.

Donc si ces derniers comprennent bien les problématiques de leur compagnie et les usages de MongoDB qui en sont faits, ils ne sont pas les parfaits intervenants pour répondre aux besoins du marketing, qui sont très éloignés des considérations « mobile » et orientées performance et latence minimum qui sont leur pain quotidien. Quand le marketing leur demande de fournir une liste de clients de plusieurs milliers de lignes, ces développeurs crient à la mort qu'une telle requête, exécutée à intervalle régulier, va mettre leur système à genoux et menacer leur propre business !

2.5 État des lieux et virtualisation de données

En première analyse, la construction du rapport est un projet technique complexe, qui requiert des compétences sur deux bases de données relationnelles (Oracle, MariaDB) et une base de données de type NoSQL (MongoDB). En outre, les équipes n'ont pas toutes les compétences requises pour exploiter ces différentes sources de données et les développeurs de Distributeur sont très inquiets des impacts, en termes de performance, sur leur propre système.

Maintenant, imaginons qu'un système se charge de fédérer ces données, et les expose sous forme d'un schéma de données SQL classique, comme si, presque par magie, une base de données unique contenait toutes les informations. Et que, en outre, ce système se charge non seulement d'optimiser les requêtes SQL, pour exploiter les forces de chaque SGDBR, mais aussi de mettre en cache les données - dans notre cas, celles de Distributeur, pour éviter d'effectuer trop souvent des requêtes sur le système source. Plutôt intéressant, n'est-ce pas ?

La solution ETL

C'est un autre sujet, mais on a, par le passé, adressé ce genre de problématique par la mise en place d'une solution de type ETL (Extract Transform Load[1]. L'outil effectuant les extractions, puis transformations de type nécessaires avant de charger les données produites dans une base de données dédiée.

Pour faire bref, ce genre de solution a plusieurs limitations. La première est bien évidemment le fait que les données sont dupliquées, mais aussi leur manque de « fraîcheur ». En effet, le système cible est constamment « en retard » avec la « réalité ».

C'est justement à cause de ces nombreuses limites que des solutions de virtualisation de données comme Teiid ont émergé.

Assumons un instant que nous disposions de cette couche d'abstraction, et donc d'un schéma fédérateur unifiant les données issues des divers systèmes sources et que ce dernier puisse être interrogé par l'intermédiaire de simples requêtes SQL. L'implémentation du rapport évoqué plus haut devient une tâche relativement simple, voire triviale. En effet, il suffit de produire les requêtes SQL nécessaires, et de construire une simple application Web pour configurer ces dernières et fournir les rapports appropriés.

En essence, ce système magique est une virtualisation (ou fédérationde données. Le système, que nous implémenterons à l'aide de Teiid, se charge de :

- retrouver, de manière performante, les données sur les différentes sources de données ;

- d'exposer un modèle de données unifiées, de manière transparente ;

- d'effectuer les transformations de types nécessaires sur les données.

En outre ceci permettra d'implémenter le service souhaité sans coût d'infrastructure supplémentaire. N'importe quelles données ou requêtes effectuées sur le schéma de données virtuel peuvent être exposées (par Teiid) sous forme de WebServices ReST au format Odata [2]. À partir d'ici, la conception d'une simple interface Web, pour interagir avec le service, sera presque triviale (ou en tout cas relativement simple).

Il est aussi important de souligner que le moteur de construction de requêtes de Teiid, qui se charge d'aller récupérer les données dans les systèmes sources, est très performant et sait construire des requêtes optimisées pour les systèmes cibles. De plus, Teiid dispose d'un système de cache interne (utilisant Infinispan [3][4]) pour conserver les données récupérées.

Ainsi, il est souvent plus performant d'effectuer une requête unique sur Teiid et de le laisser effectuer les requêtes sur les systèmes sources et la fusion des données, que de faire directement les requêtes non optimisées sur chacun des systèmes.

On notera aussi que le cache de Teiid permet de répondre aux angoisses des développeurs de Distributeur. Les données extraites de leur instance MongoDB seront massivement placées en cache, limitant grandement les accès supplémentaires à leur système.

2.6 Conclusion de l'étude de cas

Arrivé à ce stade, l'avantage de la fédération de données (ou, encore une fois, de la virtualisation des données) devrait apparaître assez clairement. Comme la mise en place de toute forme de virtualisation, celle-ci permet de simplifier et d'unifier les processus, en effectuant l'abstraction de l'hétérogénéité des systèmes sous-jacents.

Dans un projet de virtualisation de systèmes physiques, on distribue un ensemble de ressources hétérogènes (différents types de processeurs, utilisant différents types de mémoires, parfois sur différents sites) de manière abstraite, sous la forme de ressources virtuelles, qui, vues de l'extérieur, sont toutes « égales entre elles ». On utilise ici la même approche. On virtualise les systèmes de gestion de données, avec leurs contraintes d'intégrité, leur conformité (ou non) à un modèle de transaction, pour extraire et unifier les données sous une forme standard et unifiée (SQL).

Le SQL de Teiid

Tout le monde sait que si SQL est un standard, dans les faits, tous les fournisseurs de bases de données relationnelles ont chacun leur « dialecte » - comme le nomme assez justement le projet Hibernate [5]. Teiid n'échappe malheureusement pas à la règle, et si n'importe quel client SQL peut discuter avec Teiid, il est possible de construire des requêtes très performantes, mais spécifiques à Teiid.

De plus, on peut utiliser des « conseils » (hints) dans les commentaires associés à la requête pour indiquer au système si un résultat doit être mis en cache. Cette technique est peu intrusive, mais elle est, là encore, spécifique à Teiid. De la même manière, il existe aussi des mots clés, et des techniques d'optimisation propres à Teiid.

Néanmoins, comme pour les autres systèmes de gestion de bases de données, ce n'est pas réellement un problème, car il est tout à fait possible d'utiliser un outil de object-relationship mapping (ou ORM [6]), tel qu'Hibernate justement, pour disposer d'une simple interface de programmation, et abstraire son traitement métier des spécificités du dialecte de Teiid.

Par souci de concision néanmoins, cette approche ne sera pas démontrée ou utilisée dans cet article.

Voilà, en espérant que l'exposé a été jusqu'ici clair, nous allons maintenant voir, dans les grandes lignes, mais de manière pratique, comment implémenter une telle solution à l'aide de Teiid.

3. Mise en place de Teiid

Concrètement, Teiid est une application Java qui s'exécute au-dessus d'un serveur d'application JEE, en l'occurrence Wildfly (anciennement connu sous le nom de JBoss AS). Il est donc nécessaire d'installer d'abord ce serveur d'application. Tout cela n'est pas très compliqué et nous allons rapidement décrire comment faire.

En essence, la mise en place de Teiid, se compose des parties suivantes :

1. l'installation d'une machine virtuelle Java (JVM) et de son compilateur (JDK) - ceci est trivial, et ne sera pas détaillé dans cet article ;

2. l'installation d'un serveur d'applications JEE, dans notre cas le serveur Open Source Wildfly [7] - seules les parties spécifiques à Teiid seront détaillées ci-après ;

3. l'ajout des pilotes JDBC (JDBC drivers) nécessaires au serveur applicatif - l'installation d'un seul pilote sera exposée, à titre d'exemple ;

4. le déploiement des applicatifs liés à Teiid - couvert de manière exhaustive ci-dessous ;

5. le déploiement du Teiid Designer, un environnement de développement intégré pour Teiid, livré sous forme d'un greffon Eclipse, qui ne sera pas explicité dans cet article, mais il sera utilisé pour mettre en place la virtualisation de données.

Produit Red Hat et projet Open Source

Si le lecteur n'est pas familiarisé avec le modèle business de Red Hat, il peut être tout naturellement confus face à tous ces produits qui ont « deux noms » (JBoss EAP [8] et Wildfly [7], Teiid [9] et DataVirt [10]). En fait, la logique derrière ces différents noms de produits est très simple.

Il faut juste retenir que Red Hat choisit une version du projet communautaire, dans notre cas Wildfly ou Teiid, que la compagnie s'engage à supporter auprès de ses clients. De cette version est donc dérivé un produit Red Hat, soit dans notre cas JBoss EAP ou DataVirt. Notez bien ici que le code du produit n'est que peu altéré - il ne s'agit pas d'un fork propriétaire du projet open source. Red Hat associe juste un nouveau nom et une version spécifique au produit, pour bien le distinguer du produit communautaire auprès de ses clients.

DataVirt est donc juste une version de Teiid, sur laquelle Red Hat a effectué de nombreux tests de vérification, sur de nombreuses plateformes et est donc en mesure de fournir du support et avoir des engagements contractuels.

3.1 Installation de Widlfy

Anciennement connu sous le nom de JBoss AS (ou JBoss EAP pour les clients de Red Hat), le serveur d'application Wildfly est un conteneur d'exécution pour applicatif JEE. Il permet d'exécuter, entre autres, des applications Web Java, mais met aussi à disposition de ces dernières de nombreux services définis dans les spécifications associées à JEE [11].

Les versions les plus récentes de Teiid (lors de l'écriture de cet article) utilisent la version 6.1.0 de JBoss EAP (elle-même construite à partir de la branche 7.2 de JBoss AS). Bien que ce serveur porte un nom différent, il s'agit toujours du serveur Wildfly et on peut le télécharger depuis la page de téléchargement de la communauté JBoss.

En outre, comme tout ceci est codé en Java, il est relativement simple d'installer Wildfly. Une fois votre poste équipé d'une machine virtuelle Java, il suffit de décompresser l'archive fournie sur le site de Wildfly, et d'exécuter le script de démarrage :

$ ./bin/standalone.sh -c standalone.xml -b 127.0.0.1

=========================================================================

 

  JBoss Bootstrap Environment

 

  JBOSS_HOME: /home/rpelisse/Téléchargements/jboss-eap-6.1

 

  JAVA: /usr/java/jdk1.7.0_71//bin/java

 

  JAVA_OPTS:  -server -XX:+UseCompressedOops -Xms1303m -Xmx1303m -XX:MaxPermSize=256m

-Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman

-Djava.awt.headless=true

 

=========================================================================

 

16:06:54,378 INFO  [org.jboss.modules] (main) JBoss Modules version 1.2.0.Final-redhat-1

16:06:54,562 INFO  [org.jboss.msc] (main) JBoss MSC version 1.0.4.GA-redhat-1

16:06:54,677 INFO  [org.jboss.as] (MSC service thread 1-8) JBAS015899: JBoss EAP 6.1.0.GA (AS 7.2.0.Final-redhat-8) démarre

16:06:55,552 INFO  [org.xnio] (MSC service thread 1-2) XNIO Version 3.0.7.GA-redhat-1

16:06:55,556 INFO  [org.jboss.as.server] (Controller Boot Thread) JBAS015888: Création d'un service de gestion http à l'aide de socket-binding (management-http)

16:06:55,558 INFO  [org.xnio.nio] (MSC service thread 1-2) XNIO NIO Implementation Version 3.0.7.GA-redhat-1

 

...

16:06:56,318 INFO  [org.jboss.as.remoting] (MSC service thread 1-4) JBAS017100: Écoute sur 127.0.0.1:9999

16:06:56,319 INFO  [org.jboss.as.remoting] (MSC service thread 1-7) JBAS017100: Écoute sur 127.0.0.1:4447

16:06:57,094 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-8)

JBAS010400: Source de données liée [java:jboss/datasources/ExampleDS]

16:06:57,260 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: L'interface de gestion http écoute sur http://127.0.0.1:9990/management

16:06:57,261 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: La console d'administration écoute sur http://127.0.0.1:9990

16:06:57,262 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss EAP 6.1.0.GA (AS 7.2.0.Final-redhat-8) a démarré en 3243ms - 123 sur 177 services ont démarré (53 services sont passifs ou à la demande)

Si la sortie écran que vous obtenez est similaire à celle ci-dessus, vous avez réussi à installer proprement Wildfly. Si ce n'est pas le cas, n'allez pas plus loin, il n'est bien évidemment pas recommandé d'installer Teiid sur un serveur dysfonctionnel.

Pour respecter l'usage, mais aussi pour faciliter la suite des opérations, n'oubliez pas de définir une variable d'environnement, nommée WILDFLY_HOME, contenant le chemin absolu vers le répertoire d'installation de Wildfly :

$ export WILDFLY_HOME='/opt/wildfly/'

Pour bien suivre les changements que nous allons effectuer par la suite sur cette configuration par défaut de Widlfy, nous allons placer les révisions de ce répertoire sous le contrôle de Git :

$ cd "${WILDFLY_HOME}"

$ git init

$ git add * # cette opération peut prendre un peu de temps

$ git commit -m "initial import"

3.2 Installation de Teiid

Assumant que tout s'est bien déroulé dans l'étape précédente, il est maintenant possible d'installer Teiid au sein du serveur d'application. Pour faciliter autant que possible cette étape, la communauté de Teiid met à disposition une archive imitant l'arborescence de Widlfly. Ainsi, il suffit d'extraire cette archive dans le répertoire d'installation de Widlfy pour déployer Teiid :

$ unzip teiid-8.9.1-jboss-dist.zip -d /tmp/teiid/ > /dev/null

$ tree -L 2 /tmp/teiid/

/tmp/teiid/

├── bin

│   └── scripts

├── docs

│   ├── schema

│   └── teiid

├── modules

│   └── system

└── standalone

    └── configuration

 

9 directories, 0 files

$ rm -rf /tmp/teiid/

$ unzip teiid-8.9.1-jboss-dist.zip -d "${WILDFLY_HOME}"

$ cd "${WILDFLY_HOME}"

$ git status

Comme nous avons placé le répertoire d'installation du serveur sous le contrôle de Git, on peut aisément voir que les fichiers déployés ne modifient aucun des fichiers existants, et se contentent de rajouter les éléments spécifiques à Teiid :

$ git status

Sur la branche master

Fichiers non suivis:

(utilisez "git add <fichier>..." pour les inclure dans ce qui sera validé)

 

      bin/scripts/

      docs/schema/jboss-teiid.xsd

      docs/teiid/

      modules/system/layers/base/com/datastax/

      modules/system/layers/base/com/fasterxml/

      modules/system/layers/base/dom4j/

      modules/system/layers/base/javax/ws/rs/api/2.0/

      modules/system/layers/base/org/antlr/4.1/

      modules/system/layers/base/org/apache/accumulo/

      modules/system/layers/base/org/apache/commons/lang/3.3.2/

      modules/system/layers/base/org/apache/cxf/impl/frontend-jaxrs/

      modules/system/layers/base/org/apache/hadoop/

      modules/system/layers/base/org/apache/olingo/

      modules/system/layers/base/org/apache/poi/

      modules/system/layers/base/org/apache/solr/

      modules/system/layers/base/org/apache/thrift/

      modules/system/layers/base/org/apache/xmlbeans/

      modules/system/layers/base/org/apache/zookeeper/

      modules/system/layers/base/org/jboss/teiid/

      modules/system/layers/base/org/odata4j/

      modules/system/layers/base/org/olap4j/

      modules/system/layers/base/org/springframework/

      standalone/configuration/standalone-teiid.xml

 

aucune modification n'est ajoutée à la validation, mais des fichiers non suivis sont présents (utilisez "git add" pour les suivre)

3.3 Ajout d'un pilote JDBC

3.3.1 Notes préliminaires sur le déploiement des pilotes

Il est important de noter que si Teiid se déploie sur un serveur d'application JEE comme Wildfly, c'est justement pour exploiter les nombreux services techniques que ce dernier propose. Ainsi, Teiid délègue à ce dernier la gestion des pools de connexions aux bases de données - Teiid utilise seulement le nom JNDI pour y accéder, comme nous le verrons plus loin. Teiid se sert également du moniteur transactionnel du serveur d'applications pour s'assurer de rester conforme aux attentes de ACID [12] et aux besoins liés au two phase commit [13].

Si c'est bien la tâche du serveur d'applications Wildfly de s'occuper de ces pools de connexions, le produit n'est pas livré avec les pilotes JDBC nécessaires à toutes les sources de données possibles et imaginables ; autant pour des raisons légales - certains de ces pilotes ne sont simplement pas disponibles en open source - que pour des raisons plus pragmatiques, telles que ne pas déployer, par défaut, des versions incompatibles avec celles utilisées par les applicatifs déployés sur le serveur.

Pour toutes ces raisons, il est donc nécessaire de déployer manuellement ces pilotes JDBC, sur lesquels Teiid va s'appuyer pour communiquer avec les bases de données SQL. Comme nous allons l'illustrer rapidement, l'installation de ces pilotes est non seulement assez facile, mais aussi largement documentée [14].

Nous allons simplement décrire l'opération de l'installation du pilote JDBC associé à MySQL. Pour les autres pilotes nécessaires pour notre étude de cas, la méthode est essentiellement la même.

3.3.2 Installation du pilote JDBC

Sans rentrer dans les détails de l'architecture de Wildfly, il est important de comprendre - au moins de manière sommaire - la notion de module Jboss [15]. Un module JBoss est, en effet, un répertoire doté d'un fichier module.xml, et la plupart du temps d'archives Jar. Le code contenu dans ces derniers sera donc accessible, à l'exécution, pour le serveur d'application ou même les applicatifs qu'il héberge.

Ce fichier module.xml indique d'une part la version du module, car en effet plusieurs versions peuvent coexister pour répondre aux besoins des applicatifs déployés sur le serveur d'applications. Ceci implique aussi que l'on peut déployer différentes versions d'un même pilote JDBC pour se connecter, par exemple, à différentes instances d'une même base de données (ex. : MySQL 4 et MySQL5), sans interférence entre ces dernières.

D'autre part, le descripteur du module indique les dépendances vers d'autres modules du serveur d'application. Là encore, dans le cas de l'installation d'un pilote JDBC, nous allons donc indiquer une dépendance vers le moteur transactionnel du serveur.

Enfin, et c'est le point le plus important, le répertoire du module contient un ensemble de bibliothèques Java, sous forme de Jar, embarquées par ce dernier. Le fichier module.xml fait l'inventaire de ces fichiers Jar. Ainsi, pour ajouter le connecteur MySQL 5 à notre système, le descripteur XML du module est le suivant :

<?xml version="1.0" ?>

<module xmlns="urn:jboss:module:1.1" name="com.mysql.jdbc">

    <resources>

        <resource-root path="mysql-connector-java-5.1.31-bin.jar"/>

    </resources>

 

    <dependencies>

        <module name="javax.api"/>

        <module name="javax.transaction.api"/>

    </dependencies>

</module>

Au sein du répertoire d'installation de notre serveur d'applications, l'arborescence résultante est la suivante :

$ tree modules/

modules/

└── com

    └── mysql

        └── main

            └── module.xml

            └── mysql-connector-java-5.1.31-bin.jar

3 directories, 1 file

Il suffit ensuite de redémarrer le serveur d'applications pour que le pilote soit déployé. Une fois l'ensemble des pilotes requis mis en place, nous pouvons alors attaquer la conception de notre fédération de sources de données.

3.3.3 Une dernière vérification (plus graphique)

Si la ligne de commandes et les extraits de code sont souvent plus didactiques pour les articles papier, il ne faut pas s'imaginer qu'ils sont les seuls outils à votre disposition. Si vous trouvez plus clair, ou plus simple d'utiliser des interfaces graphiques (« web » en l'occurrence), vous pouvez vérifier l'ajout de votre source de données à l'aide de la console d'administration de Wildfly, comme illustré sur ces captures d'écrans :

4. Fédération des sources de données

4.1 Virtual Databases (VDB)

Si vous fabriquez une application Java, vous l'empaquetez dans une archive JAR, si vous fabriquez une application Web, c'est un WAR que vous construisez et si vous faites une application JEE, vous construisez et déployez un EAR. Dans le cas de la mise en place de la virtualisation de données, c'est dans une archive similaire, suffixée par .vdb - pour Virtual Databases (VDB) que vous allez construire.

De la même manière qu'une archive WAR dispose d'un descripteur, le célèbre web.xml, le fichier principal d'une archive VDB est un fichier XML décrivant les différentes sources de données. Il suffit de suffixer par -vdb.xml un fichier placé à la racine de l'archive (.vdb) pour que Teiid analyse son contenu et effectue les déploiements et configurations nécessaires.

Comme évoqué plus haut, il existe un éditeur, sous forme de plugin Eclipse, qui permet de facilement créer cette archive. Nous allons donc voir maintenant comment l'utiliser pour créer notre première couche d'abstraction, encapsulant juste la base de données de PetiteBoite.

4.2 Première couche d'abstraction - les sources de données

Teiid n'est pas un projet récent et l'expérience autour de ce dernier a permis déjà depuis longtemps d'établir certaines bonnes pratiques et usages pour assurer une configuration claire, simple et extensible du produit. Ainsi, comme nous allons le voir, il est important de bien découper la configuration en plusieurs couches d'abstraction, dont la première est juste une déclaration, au sein de Teiid, d'une nouvelle source de données.

Après avoir ajouté le driver nécessaire à MySQL, on utilise le Teiid Designer pour se connecter à la base de données de PetiteBoite. À l'aide des seules données de connexion (identifiant et nom de la table), Teiid utilise les métadonnées à sa disposition pour construire un schéma exhaustif des données présentes.

La première étape consiste donc à créer un projet Teiid, qui n'est en fait qu'un simple répertoire contenant, par défaut, quatre sous-répertoires :

$ tree -L 3 TeiidFederationDS/

TeiidFederationDS/

├── schemas

├── sources

├── views

└── web_services

 

4 directories, 3 files

L'organisation des sous-répertoires n'est qu'une convention, vous pouvez les renommer comme vous le désirez. Bien évidemment, cela reste toujours une bonne idée de suivre les usages établis...

Une fois le projet créé, il suffit de faire un clic droit sur le répertoire sources et de sélectionner l'option Import. Là, parmi les options proposées, il faut sélectionner JDBC, ce qui ouvrira le formulaire de la figure 1.

Figure 1

Sans surprise, la première étape consiste à définir le type de connexion (dans notre cas, MySQL). Selon la distribution Eclipse que vous utilisez, il n'est pas sûr qu'elle embarque le pilote JDBC. Pas de problème, on peut facilement en ajouter un (et comme nous l'avons déjà téléchargé plus haut pour l'installer dans Wildfly, il est déjà sur notre machine). Tout cela est visible dans les figures 2, 3 et 4.

Figure 2

Figure 3

Figure 4

Une fois le pilote ajouté et les données de connexion renseignées, on peut déjà, avant d'aller plus loin, vérifier s’il n'y a pas d'erreur de paramétrage en cliquant sur le bouton Test Connection. Le résultat de cette action est visible en figure 5.

Figure 5

Ce n'est qu'un détail, mais ce genre d'approche est très appréciable. En effet, dans ce genre d'intégration complexe, où l'on tente de connecter de nombreux systèmes entre eux, il est vraiment très pratique de pouvoir effectuer des tests à mi-parcours, pour éviter de passer, par la suite, de nombreuses heures à essayer de déterminer d'où vient le problème.

Une fois la connexion établie, on peut sélectionner la base de données et les tables associées à importer. Dans notre cas, on souhaite juste importer la table des données de fidélisation comme le montrent les figures 6, 7 et 8.

Figure 6

Figure 7

Figure 8

Voilà, en quelques clics, nous avons configuré l'accès, par la couche d'abstraction de Teiid, à la table des données de fidélisation. Si l'on regarde de nouveau l'organisation du répertoire du projet, on peut voir que des fichiers .vdb ont d'ailleurs été créés :

$ tree -L 3

.

├── PREVIEW_17178b85-2697-496a-9532-218856f7eb94_TeiidFederationDS_project.vdb

├── schemas

├── sources

│   ├── PetiteBoite_Fidelisation.xmi

│   └── PREVIEW_17178b85-2697-496a-9532-218856f7eb94_TeiidFederationDS_sources_PetiteBoite_Fidelisation.vdb

├── views

└── web_services

 

4 directories, 3 files

En fait, fidèle à son habitude - parfois détestable - Eclipse génère à chaque modification du projet une archive prête à déployer. Bien qu'il soit possible de déployer cette dernière directement sur Wildfly, il n'est pas recommandé de le faire. À ce stade, l'archive n'est pas complète et sert essentiellement à répondre aux besoins internes du Teiid Designer.

4.3 Deuxième couche d'abstraction - abstraction de la source

Si on peut accéder désormais aux données de la table de fidélisation, on reste très adhérent à son schéma de données. Avant d'aller plus loin, il est bon, dans le domaine de la virtualisation de données, de construire, au-dessus des sources de données physiques, une première couche d'abstraction, assurant un découplage entre notre modèle de fédération et les données sources.

Pour ce faire, nous allons définir une nouvelle « vue » de la table Fidélisation. À l'aide d'un clic droit sur le répertoire views, nous allons ajouter un nouveau Teiid MetadataModel, que l'on construira à partir de notre précédente source de données comme le montrent les figures 9, 10 et 11.

Figure 9

Figure 10

Figure 11

Quel est l'intérêt de cette couche d'abstraction me direz-vous ? C'est simple, regardez bien les types des champs de la table. Ce qui était, côté MySQL, un VARCHAR(255) est devenu, par exemple, un champ chaîne de caractères (String). En fait, nous venons d'abstraire ces données de leur représentation physique dans le schéma de données sources.

Ainsi, si le schéma de données source vient à changer ou, simplement si sa représentation interne n'est pas compatible avec le modèle que nous souhaitons avoir à disposition pour notre nouvelle application, ceci peut être ainsi abordé. Par souci de concision, nous n'allons pas le démontrer ici, mais notez que Teiid propose de très nombreux mécanismes de transformation de données et qu'il est donc possible, par exemple, d'associer plusieurs champs et d'effectuer de complexes opérations sur leurs données pour construire une colonne supplémentaire (et virtuelle).

Rapide exemple : imaginons que pour notre application « marketing » nous ayons besoin d'un simple champ booléen (pour des raisons de performance) indiquant si le client fidélisé est majeur ou non. On peut simplement ajouter une colonne virtuelle (qui ne sera donc pas enregistrée sur disque) nommée isTarget et indiquant si l'âge du client moins 18 est supérieur à zéro (voir figure 12).

Figure 12

Le SQL côté client devient alors très simple :

SELECT * FROM FidelisationView WHERE isTarget = 'true';

Le calcul, pour chaque colonne, sera réalisé par Teiid, qui saura en plus l'optimiser et pourra, si on le souhaite, placer le résultat dans un cache, à des fins d'optimisation.

4.4 Intégrer MongoDB

Intégrer les données depuis la base de données MongoDB va suivre le même chemin, à l'exception près - mais elle est de taille - que cette source de données n'est pas SQL. Alors, comment faire pour l'ajouter ?

Déjà, regardons la sortie JSON des données contenues dans la table DonneesMobile de Distributeur :

Customer

{

  _id: 1,

  FirstName: "John",

  LastName: "Doe"

}

C'est simple, nous allons ajouter - cette fois-ci directement à l'aide d'un fichier XML - une nouvelle source de données, où nous indiquerons à Teiid comment associer les valeurs contenues dans la ou les collections disponibles dans MongoDB en une table SQL (virtuelle) :

<vdb name="Distributeur" version="1">

<model name="DonneesMobile">

<source name="local" translator-name="mongodb" connection-jndi-name="java:/mongoDS"/>

<metadata type="DDL"><![CDATA[

CREATE FOREIGN TABLE CustomerMobileData (

customer_id integer,

FirstName varchar(25),

LastName varchar(25),

...

);

]]> </metadata>

</model>

<vdb>

Et le tour est joué ! En effet, nous disposons désormais d'une table SQL sur laquelle nous pourrons effectuer toutes les opérations usuelles au SGDBR, même si cette dernière est en fait une source de données NoSQL (voir figure 13) !

Figure 13

Bien évidemment, il est essentiel dans la conception de ne pas oublier que la source de données est justement de type NoSQL et que donc, même si Teiid permet d'effectuer des opérations de recherche de type SELECT ... FROM ... WHERE, celles-ci aboutiront à des itérations de l'ensemble des données et peuvent se révéler désastreuses en termes de performance.

Heureusement, Teiid propose de nombreux mécanismes de cache ou d'optimisation de requête - qui dépassent le cadre de ce simple article d'introduction - pour s'assurer que l'extraction des données se fasse de manière optimale et réponde à la plupart des problématiques de performance qui pourraient apparaître par la suite.

Avant d'aller plus loin, comme pour la table des données de fidélisation, on crée une vue virtuelle de cette nouvelle source de données, faisant l'abstraction du schéma physique des données dans MongoDB (voir figure 14).

Figure 14

4.5 Troisième couche de virtualisation - Schéma de données applicatif

Maintenant que nous avons importé les deux tables et créé des vues pour chacune, nous allons enfin pouvoir construire le schéma de données qui sera utilisé par notre nouvelle application de reporting. Pour ce faire, il suffit de faire un clic droit sur le répertoire schémas et définir un nouveau modèle de données virtuelles, intitulé ReportingApp.

À l'inverse des précédentes étapes, on ne choisit pas un moteur de transformation, ce qui aboutit à la création d'une table vide. Pour la remplir, il suffit d'effectuer un drag'n'drop d'une de nos vues dans la zone « source » de la transformation comme le montre la figure 15.

Figure 15

Même opération pour ajouter l'autre table comme source à notre schéma (voir figure 16).

Figure 16

Par défaut, Teiid effectue déjà une fédération de données, regroupant tous les champs disponibles dans l'ensemble des sources ajoutées dans la table. Ce n'est pas très élégant, mais c'est un point de départ. Maintenant, à l'aide d'un clic droit sur le symbole de transformation, on peut faire apparaître un éditeur SQL explicitant comment Teiid exécute la transformation (voir figure 17).

Figure 17

À partir de là, comme on peut le voir sur la figure 18, il suffit d'adapter la requête SQL pour construire le schéma de données désiré.

Figure 18

4.6 Déploiement

À l'aide du précédent schéma, nous venons de réaliser une fédération de données qu'il ne reste plus qu'à exposer comme une source de données SQL « classique » à la future application de reporting. Pour ceci, il suffit de packager le schéma - et les vues et sources qu'il utilise - sous forme d'une archive VDB décrite plus haut.

Là encore, le Teiid Designer permet de réaliser l'opération à l'aide d'une série de formulaires. Pour démarrer cette dernière, il faut faire un clic droit sur le projet et choisir l'option New, suivi de Teid VDB (voir figure 19).

Figure 19

Une fois les schémas à embarquer dans l'archive VDB choisis, le fichier est créé et exposé, sous forme d'un nouvel onglet, dans la fenêtre principale d'Eclipse. Cet onglet permet de modifier son contenu - en ajoutant d'autres schémas ou en définissant des droits d'accès par utilisateur - ou encore de redéfinir les translators utilisés, si nécessaire (voir figure 20).

Figure 20

Teiid et droit d'accès

Ceci nécessiterait probablement un article à part entière, mais il est important de retenir que Teiid dispose de très puissants mécanismes de gestion d'accès aux données. Il est possible en effet de définir des droits très, très fins sur les données accédées par les utilisateurs.

On peut, par exemple, indiquer qu'un utilisateur n'a accès qu'à une seule colonne dans une table, ou même seulement qu'à certaines lignes. Il est aussi possible de masquer les contenus de certains champs - par exemple des mots de passe ou des données confidentielles.

En outre, Teiid peut bien évidemment associer ces droits à des utilisateurs authentifiés par un serveur LDAP, ce qui permet d'externaliser la gestion de ces derniers.

Enfin, on peut déployer l'archive générée comme n'importe quel applicatif JEE ou webapp, utilisant, par exemple, le JBoss CLI (outil de gestion de Wildfly en ligne de commandes) :

$ cd "${JBOSS_HOME}"

$ ./bin/jboss-cli.sh --connect

[standalone@localhost:9999 /] deploy /.../TeiidFederationDS/ReportingSchema.vdb

5. Considérations de mise en production et de passage à l'échelle

La mise en production d'applicatifs, que ce soit du point de vue déploiement, sécurité ou encore de la bonne tenue de la charge, est un sujet complexe (qui, là encore, pourrait justifier un article dédié). Nous allons donc nous contenter de quelques remarques d'ordre général, surtout centrées sur les problématiques de mise à l'échelle.

5.1 Optimisation des requêtes

Tout d'abord, il est essentiel de comprendre que cet article n'a fait que présenter, de manière très sommaire, la conception d'un schéma de données virtuelles, déployé sous forme de VDB. Ce schéma est loin d'être optimisé, et il serait nécessaire, avant toute mise en production, d'effectuer un travail d'optimisation et de réglages fins pour s'assurer que les requêtes générées par Teiid, pour les besoins du nouvel applicatif, ne soient pas contre-productives, quand exécutées sur les sources de données origines.

Ce n'est pas forcément un travail aisé, et il nécessite souvent l'intervention de non seulement un expert du fonctionnement de Teiid, mais aussi des administrateurs des bases de données concernées, et voire même des développeurs. Néanmoins, le fruit de ce labeur commun peut changer du tout au tout les performances lors de l'exécution.

Pour faire court, si, après la mise en place de votre fédération de données vous avez des problèmes de performance, prenez le temps de bien en identifier les causes, et vérifiez que ces derniers ne peuvent pas être simplement réglés en « resserrant quelques boulons », du côté de Teiid, de l'applicatif ou même simplement de la base de données.

5.2 Mise en place du cache

En outre, une politique de cache devrait être sérieusement envisagée, pour éviter à Teiid de constamment solliciter les sources données, et assurer la conservation en mémoire des résultats les plus fréquents. Bien évidemment, si les données sont conséquentes (plusieurs dizaines de Gb), le cache, pour être un tant soit peu efficace, devra nécessairement être très large.

Heureusement, Teiid utilise Infinispan pour placer ces données en cache, et ce produit est justement conçu pour gérer, sous forme de grilles de données, de très larges quantités de données. On peut donc aisément élargir la taille de ce dernier, en ajoutant juste des instances Teiid à notre environnement de production (voir le précédent article sur Infinispan).

Comme évoqué plus haut, il est très aisé d'indiquer à Teiid que le résultat d'une requête doit être placé dans le cache. En effet, il suffit d'ajouter, sous forme de commentaire, un « hint » :

/*+ cache(ttl:3600000) */ select username, password from users where allowed == true ;

En outre, comme le montre bien l'exemple ci-dessus, on peut aussi configurer le comportement du cache « in situ », et donc, par l'exemple, lui indiquer combien de temps la ou les données récupérées doivent être conservées dans le cache de Teiid.

5.3 Mise à l'échelle

Un dernier point essentiel : si on omet le cache, on réalise qu'une instance Teiid, hébergeant une ou plusieurs VDB, est au final sans état (stateless). Ceci signifie qu'il est aisé de la faire monter en charge puisqu'on peut, de manière presque transparente, ajouter ou retirer des instances. Aucun état n'étant préservé sur les instances en tant que telles (à l'exception du cache), ce genre d'opération n'aura aucun (ou presque) impact sur les applicatifs.

Bien évidemment, et comme toujours, c'est rapidement les bases de données sources qui formeront le goulot d'étranglement du système. C'est pour ça qu'il est crucial, comme évoqué un peu plus haut, de bien vérifier le plan d'exécution des requêtes - et la bonne conception du schéma de données virtuelles, ainsi que le placement en cache des données les plus consultées, pour s'assurer des bonnes performances des bases de données virtuelles, et ainsi minimiser au maximum les accès aux sources de données.

Conclusion

Cette rapide présentation aura, nous l'espérons, eu l'effet de faire réaliser au lecteur le grand potentiel de la mise en place d'une solution de virtualisation de données. En effet, le déploiement d'un tel outil peut non seulement simplifier largement la conception d'applicatifs accédant à différentes sources de données, retirer un lourd travail, peu réutilisable, de conversion de données aux développeurs, mais aussi assurer un découplage très utile, en terme opérationnel, entre les sources de données et les schémas utilisés par les applicatifs du système d'information.

Références

[1] Extract Transform and Load : http://fr.wikipedia.org/wiki/Extract_Transform_Load

[2] OData, un protocole ReST d'accès aux données : http://www.odata.org/

[3] Voir l'article précédent du présent magazine !

[4] Infinispan : http://infinispan.org

[5] Hibernate ORM est une implémentation open source très prisée du « patron » ORM : http://hibernate.org/

[6] Object-Relational Mapping est un « patron » de développement : http://fr.wikipedia.org/wiki/Mapping_objet-relationnel

[7] Wildfly, un serveur JEE Open Source : http://wildfly.org/

[8] JBoss EAP, version supportée par Red Hat du serveur Wildfly : http://www.jboss.org/products/eap/overview/

[9] Site officiel du projet Teiid : http://teiid.jboss.org/

[10] Le produit DataVirt – version supportée de Teiid : http://www.jboss.org/products/datavirt/overview/

[11] Java Enterprise Edition : http://www.oracle.com/technetwork/java/javaee/tech/index-jsp-142185.html

[12] Les propriétés ACID : http://fr.wikipedia.org/wiki/Propri%C3%A9t%C3%A9s_ACID

[13] Le commit à deux phases : http://en.wikipedia.org/wiki/Two-phase_commit_protocol

[14] Documentation sur l'installation d'un pilote JDBC dans Wildfly : https://docs.jboss.org/author/display/WFLY8/DataSource+configuration

[15] Le projet JBoss Module : https://docs.jboss.org/author/display/MODULES/Home

[16] Guide à l'installation de Teiid: https://docs.jboss.org/author/display/teiid87final/Installation+Guide