MicroStream est une approche très intéressante et même audacieuse de la persistance des données dans les applications Java. Il propose d’éviter entièrement la complexité du serveur et du magasin de données et de fournir à la place une couche de persistance des objets qui s’exécute à l’intérieur de l’application elle-même. Oracle a intégré MicroStream dans son framework de microservices Helidon, qui peut être considéré comme rien de moins qu’une approbation majeure de l’approche.
Lisez la suite pour en savoir plus sur MicroStream et sa couche de persistance de graphe d’objets open source.
La sérialisation Java reconsidérée
Dans un sens, vous pourriez considérer MicroStream comme une refonte à partir de zéro de l’idée de sérialisation.
La sérialisation Java traditionnelle présente plusieurs limitations désagréables (y compris des vulnérabilités de sécurité) qui ont incité Oracle à l’appeler une “horrible erreur” en 2018. Mais l’idée inhérente, de pouvoir simplement stocker et récupérer le graphique d’objets au moment de l’exécution, est toujours viable .
Ce qu’il faut, c’est une implémentation largement supérieure. C’est là qu’intervient MicroStream.
Implémentation de la mise en cache MicroStream
MicroStream implémente également JSR-107 (la spécification JCache). Cela signifie que vous pouvez utiliser MicroStream comme couche de mise en cache (par exemple avec Hibernate/JPA) avec ou sans la partie persistance et stockage de MicroStream activée.
Il est donc tentant d’utiliser MicroStream comme solution unique de mise en cache et de persistance, en particulier dans le contexte des microservices.
Améliorations de la sérialisation MicroStream
L’amélioration la plus importante apportée par MicroStream à la sérialisation traditionnelle est peut-être la possibilité de conserver uniquement des parties du graphe d’objets. Sans cela, aucune solution ne peut répondre aux besoins des applications du monde réel.
MicroStream traite également de la modification des structures de classe (une réalité dans toutes les applications) avec une modélisation automatique ou une configuration définie par le développeur.
De plus, MicroStream est capable de gérer toutes les structures Java persistantes, contrairement à la sérialisation traditionnelle.
La racine de données MicroStream
Dans MicroStream, le graphe d’objets qui sera géré par le moteur de persistance commence par un nœud racine connu sous le nom de DataRoot
.
La DataRoot
objet peut être de n’importe quel type, et il est défini sur le StorageManager
instance comme on le voit dans la liste 1. Notez que chaque fois que le gestionnaire de stockage est démarré, il réhydrate automatiquement le graphique de la dernière session persistante, ce qui se produit avec le storeRoot()
appel.
Listing 1. Démarrage du gestionnaire de stockage et attribution d’une racine
public class MyDataRoot {
private String stuff;
public DataRoot() {
super();
}
public String getContent() {
return this.stuff;
}
public void setContent(Object myWonderfulStuff) {
this.stuff = myWonderfulStuff ;
}
@Override
public String toString() {
return "Root: " + this.stuff;
}
}
// ...
final EmbeddedStorageManager storageManager = EmbeddedStorage.start();
System.out.println(storageManager.root());
storageManager.setRoot(MyDataRoot);
storageManager.storeRoot(); // Saves the state
Dans le Listing 1, la classe a un membre, qui peut être n’importe quel objet. Dans une application du monde réel, vous pouvez créer un modèle commercial. Vous pouvez utiliser une carte comme modèle de données et tout stocker sous forme de paires clé-valeur. MicroStream peut gérer tout ce que vous lui lancez, et il est suffisamment flexible pour évoluer avec vos structures de classe changeantes.
Définition d’un chemin de fichier
StorageManager
est livré avec plusieurs options de configuration. L’un des plus importants est le chemin d’accès à l’emplacement de stockage des données. Vous pouvez le voir en action dans le Listing 2.
Listing 2. Définir un chemin pour le stockage des données
final MyDataRoot myRoot = new MyDataRoot();
final EmbeddedStorageManager storageManager = EmbeddedStorage.start( myRoot, Paths.get("data") );
Vous pouvez gracieusement arrêter le moteur avec storageManager.shutdown();
.
Multithreading dans MicroStream
Dans le code d’application multithread, les données mutantes et persistantes doivent être synchronisées. Microstream fournit un Lambda à cette fin, comme indiqué dans la liste 3.
Listing 3. Accès synchronisé
XThreads.executeSynchronized(() -> { root.changeData(); storageManager.store(root); });
Configuration MicroStream
MicroStream propose une variété d’options de configuration, que vous pouvez définir de manière déclarative ou par programme.
Par exemple, vous pouvez configurer le système de fichiers NIO (E/S non bloquantes) qui sous-tend les opérations de lecture/écriture dans le gestionnaire de fichiers, comme indiqué dans le Listing 4. Cet exemple est tiré de la documentation MicroStream.
Listing 4. Configurer le système de fichiers NIO
NioFileSystem fileSystem = NioFileSystem.New();
EmbeddedStorageManager storageManager = EmbeddedStorageFoundation.New() .setConfiguration( StorageConfiguration.Builder()
.setStorageFileProvider( Storage.FileProviderBuilder(fileSystem)
.setDirectory(fileSystem.ensureDirectoryPath("storageDir")) .createFileProvider() )
.setChannelCountProvider(StorageChannelCountProvider.New(4))
.setBackupSetup(StorageBackupSetup.New(
fileSystem.ensureDirectoryPath("backupDir") )) .createConfiguration() )
.createEmbeddedStorageManager();
Vous pouvez également charger une configuration externe à partir de JSON, YAML et XML.
Interrogation dans MicroStream
Un résultat intéressant de l’approche de MicroStream est l’absence de besoin d’un langage de requête spécialisé comme SQL ou HQL ou d’une API de critères. Vous pouvez simplement utiliser Java standard pour naviguer dans votre graphique d’exécution et sélectionner les résultats. Vous pouvez utiliser la boucle à l’ancienne ou l’API Stream de style fonctionnel pour parcourir les associations et tester la propriété ou les propriétés que vous recherchez. L’exemple donné par MicroStream se trouve dans le Listing 5, mais toute approche typique fonctionnera.
Listing 5. Trouver un objet dans le graphe
public List
getUnAvailableArticles() {
return shop.getArticles().stream() .filter(a -> !a.available()) .collect(Collectors.toList()) ;
}
Le résultat est que, comme votre couche de données stocke des objets Java anciens, vous pouvez utiliser Java pour vos requêtes.
Options de stockage MicroStream
Bien que la valeur par défaut soit le système de fichiers, MicroStream est une couche abstraite capable de fonctionner avec d’autres solutions de persistance. Il peut même s’exécuter sur des systèmes de gestion de bases de données relationnelles comme MariaDB, via des connecteurs. Le Listing 6 vous donne un aperçu de cela.
Listing 6. Utiliser un connecteur MariaDB RDBMS
MariaDbDataSource dataSource = new MariaDbDataSource();
dataSource.setUrl("jdbc:mysql://host:3306/awesomedb");
dataSource.setUser("user");
dataSource.setPassword("secret");
SqlFileSystem fileSystem =
SqlFileSystem.New(SqlConnector.Caching(SqlProviderMariaDb.New(dataSource)));
EmbeddedStorage.start(fileSystem.ensureDirectoryPath("microstream_storage"));
Il s’agit d’une capacité assez puissante pour passer des objets Java à la base de données et inversement de manière transparente, en particulier par rapport au travail impliqué à l’aide d’un mappeur relationnel objet (ORM) comme Hibernate.
Une prise en charge similaire existe pour l’utilisation de magasins de données non relationnels comme Redis et MongoDB, et de magasins de données cloud comme Amazon S3 et Oracle Cloud Storage.
Modes de stockage MicroStream
MicroStream prend en charge deux modes de stockage, paresseux et impatient. Par défaut, MicroStream utilise le stockage différé.
Dans le stockage différé, une fois qu’un objet est persistant, il ne sera plus stocké, même s’il est modifié. Pour conserver un objet modifié, vous devez explicitement effectuer un appel pour le stocker. Cela présente l’avantage évident en termes de performances d’éviter toute interaction avec le système de stockage sous-jacent, sauf si le développeur l’a demandé.
Dans le stockage hâtif, MicroStream mettra automatiquement à jour les instances persistantes à mesure qu’elles changent. Vous pouvez voir comment activer le stockage hâtif dans le Listing 7.
Listing 7. Stockeur Eagle
Storer storer = storage.createEagerStorer(); storer.store(myData); storer.commit();
Modificateur de champ transitoire
MicroStream implémente de manière transparente le modificateur transitoire, et ces membres ne seront pas conservés par le moteur. Cela constitue un moyen simple de désactiver le stockage.
Performances MicroStream
Le développeur principal de MicroStream donne ici une description concise des implications sur les performances du framework. C’est une lecture courte et intéressante. Il explique comment le système atteint les meilleures performances de sa catégorie, sans perdre l’intégrité référentielle, en lisant une fois les métadonnées de mise en page de la classe, puis en surveillant les modifications. Cela vous aidera également à comprendre comment MicroStream atténue les limites de la réflexion.
Un autre aspect intéressant de MicroStream est la façon dont il garde une trace des entités qui se sont détachées du graphique (c’est-à-dire qui ont été ramassées) et doivent donc être supprimées du stockage. C’est ce qu’on appelle l’entretien ménager dans MicroStream et représente une réalisation technique impressionnante.
L’approche de MicroStream pour stocker et charger un graphe d’objets en cours d’exécution est révolutionnaire et pourrait potentiellement changer le paysage du développement Java à l’avenir. Il s’agit d’un changement inattendu par rapport à l’architecture conventionnelle de stockage de données de service, mais bienvenu qui élimine les principales sources de complexité.
MicroStream vaut bien un long examen lorsque l’on considère les besoins de persistance de vos applications Java.
Copyright © 2022 IDG Communications, Inc.