Un guide rapide sur Apache Geode

Un guide rapide sur Apache Geode

1. Vue d'ensemble

Apache Geode est une grille de données distribuée en mémoire prenant en charge la mise en cache et le calcul des données.

Dans ce didacticiel, nous allons couvrir les concepts clés de Geode et parcourir quelques exemples de code à l'aide de son client Java.

2. Installer

Tout d'abord, nous devons télécharger et installer Apache Geode et définir l'environnementgfsh . Pour ce faire, nous pouvons suivre les instructions enGeode’s official guide.

Et deuxièmement, ce tutoriel va créer des artefacts de système de fichiers. Donc, nous pouvons les isoler en créant un répertoire temporaire et en lançant des choses à partir de là.

2.1. Installation et configuration

Depuis notre répertoire temporaire, nous devons démarrer une instanceLocator:

gfsh> start locator --name=locator --bind-address=localhost

Locators are responsible for the coordination between different members of a Geode Cluster, que nous pouvons ensuite administrer via JMX.

Ensuite, démarrons une instanceServer pour héberger une ou plusieurs donnéesRegions:

gfsh> start server --name=server1 --server-port=0

Nous définissons l'option–server-port sur 0 afin que Geode choisisse n'importe quel port disponible. Cependant, si nous le laissons de côté, le serveur utilisera le port par défaut 40404. A server is a configurable member of the Cluster that runs as a long-lived process and is responsible for managing data Regions.

Et enfin, nous avons besoin d'unRegion:

gfsh> create region --name=example --type=REPLICATE

LeRegion est finalement l'endroit où nous stockerons nos données.

2.2. Vérification

Veillons à ce que tout fonctionne avant d’aller plus loin.

Commençons par vérifier si notreServer able nosLocator:

gfsh> list members
 Name   | Id
------- | ----------------------------------------------------------
server1 | 192.168.0.105(server1:6119):1024
locator | 127.0.0.1(locator:5996:locator):1024 [Coordinator]

Et ensuite, que nous avons nosRegion:

gfsh> describe region --name=example
..........................................................
Name            : example
Data Policy     : replicate
Hosting Members : server1

Non-Default Attributes Shared By Hosting Members

 Type  |    Name     | Value
------ | ----------- | ---------------
Region | data-policy | REPLICATE
       | size        | 0
       | scope       | distributed-ack

De plus, nous devrions avoir des répertoires sur le système de fichiers sous notre répertoire temporaire appelé «locator» et «server1».

Avec cette sortie, nous savons que nous sommes prêts à passer à autre chose.

3. Dépendance Maven

Maintenant que nous avons un Geode en cours d'exécution, commençons à examiner le code client.

Pour travailler avec Geode dans notre code Java, nous allons devoir ajouter la bibliothèqueApache Geode Java client à nospom:


     org.apache.geode
     geode-core
     1.6.0

Commençons par simplement stocker et récupérer des données dans quelques régions.

4. Stockage et récupération simples

Voyons comment stocker des valeurs uniques, des lots de valeurs ainsi que des objets personnalisés.

Pour commencer à stocker des données dans notre "exemple" de région, connectons-nous-y à l'aide du localisateur:

@Before
public void connect() {
    this.cache = new ClientCacheFactory()
      .addPoolLocator("localhost", 10334)
        .create();
    this.region = cache.
      createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
        .create("example");
}

4.1. Enregistrement de valeurs uniques

Maintenant, nous pouvons simplement stocker et récupérer des données dans notre région:

@Test
public void whenSendMessageToRegion_thenMessageSavedSuccessfully() {

    this.region.put("A", "Hello");
    this.region.put("B", "example");

    assertEquals("Hello", region.get("A"));
    assertEquals("example", region.get("B"));
}

4.2. Enregistrer plusieurs valeurs à la fois

Nous pouvons également enregistrer plusieurs valeurs à la fois, par exemple lorsque vous essayez de réduire la latence du réseau:

@Test
public void whenPutMultipleValuesAtOnce_thenValuesSavedSuccessfully() {

    Supplier> keys = () -> Stream.of("A", "B", "C", "D", "E");
    Map values = keys.get()
        .collect(Collectors.toMap(Function.identity(), String::toLowerCase));

    this.region.putAll(values);

    keys.get()
        .forEach(k -> assertEquals(k.toLowerCase(), this.region.get(k)));
}

4.3. Enregistrement d'objets personnalisés

Les chaînes sont utiles, mais le plus tôt possible, nous devrons stocker des objets personnalisés.

Imaginons que nous ayons un enregistrement client que nous souhaitons stocker à l'aide du type de clé suivant:

public class CustomerKey implements Serializable {
    private long id;
    private String country;

    // getters and setters
    // equals and hashcode
}

Et le type de valeur suivant:

public class Customer implements Serializable {
    private CustomerKey key;
    private String firstName;
    private String lastName;
    private Integer age;

    // getters and setters
}

Il y a quelques étapes supplémentaires pour pouvoir les stocker:

Tout d'abord,they should implement SerializableBien que ce ne soit pas une exigence stricte, en les rendantSerializable,Geode can store them more robustly.

Deuxièmement,they need to be on our application’s classpath as well as the classpath of our Geode Server.

Pour les amener au chemin de classe du serveur, empaquetons-les, par exemple en utilisantmvn clean package.

Et puis nous pouvons référencer le fichier jar résultant dans une nouvelle commandestart server:

gfsh> stop server --name=server1
gfsh> start server --name=server1 --classpath=../lib/apache-geode-1.0-SNAPSHOT.jar --server-port=0

Encore une fois, nous devons exécuter ces commandes à partir du répertoire temporaire.

Enfin, créons un nouveauRegion nommé "example-customers" sur leServer en utilisant la même commande que nous avons utilisée pour créer la région "example":

gfsh> create region --name=example-customers --type=REPLICATE

Dans le code, nous contacterons le localisateur comme auparavant, en spécifiant le type personnalisé:

@Before
public void connect() {
    // ... connect through the locator
    this.customerRegion = this.cache.
      createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
        .create("example-customers");
}

Et puis, nous pouvons stocker notre client comme auparavant:

@Test
public void whenPutCustomKey_thenValuesSavedSuccessfully() {
    CustomerKey key = new CustomerKey(123);
    Customer customer = new Customer(key, "William", "Russell", 35);

    this.customerRegion.put(key, customer);

    Customer storedCustomer = this.customerRegion.get(key);
    assertEquals("William", storedCustomer.getFirstName());
    assertEquals("Russell", storedCustomer.getLastName());
}

5. Types de région

Pour la plupart des environnements, nous disposerons de plusieurs copies ou de plusieurs partitions de notre région, en fonction de nos exigences en matière de débit en lecture et en écriture.

Jusqu'à présent, nous avons utilisé des régions répliquées en mémoire. Regardons de plus près.

5.1. Région répliquée

Comme son nom l’indique,a Replicated Region maintains copies of its data on more than one Server Testons ceci.

À partir de la sconsolegfsh dans le répertoire de travail, ajoutons un autreServer nomméserver2 au cluster:

gfsh> start server --name=server2 --classpath=../lib/apache-geode-1.0-SNAPSHOT.jar --server-port=0

Rappelez-vous que lorsque nous avons fait «exemple», nous avons utilisé–type=REPLICATE. Pour cette raison,Geode will automatically replicate our data to the new server.

Vérifions cela en arrêtantserver1:

gfsh> stop server --name=server1

Ensuite, exécutons une requête rapide sur la région "exemple".

Si les données ont été répliquées avec succès, nous obtiendrons des résultats:

gfsh> query --query='select e.key from /example.entries e'
Result : true
Limit  : 100
Rows   : 5

Result
------
C
B
A
E
D

Donc, il semble que la réplication ait réussi!

Ajouter une réplique à notre région améliore la disponibilité des données. Et, comme plusieurs serveurs peuvent répondre aux requêtes, nous obtiendrons également un débit de lecture plus élevé.

Mais,what if they both crash? Since these are in-memory regions, the data will be lost. Pour cela, nous pouvons utiliser à la place–type=REPLICATE_PERSISTENT qui stocke également les données sur le disque lors de la réplication.

5.2. Région partitionnée

Avec des ensembles de données plus volumineux, nous pouvons mieux dimensionner le système en configurant Geode pour scinder une région en partitions ou en compartiments distincts.

Créons unRegion partitionné nommé "partitionné par exemple":

gfsh> create region --name=example-partitioned --type=PARTITION

Ajouter des données:

gfsh> put --region=example-partitioned --key="1" --value="one"
gfsh> put --region=example-partitioned --key="2" --value="two"
gfsh> put --region=example-partitioned --key="3" --value="three"

Et vérifier rapidement:

gfsh> query --query='select e.key, e.value from /example-partitioned.entries e'
Result : true
Limit  : 100
Rows   : 3

key | value
--- | -----
2   | two
1   | one
3   | three

Ensuite, pour valider que les données ont été partitionnées, arrêtons à nouveauserver1 et relançons la requête:

gfsh> stop server --name=server1
gfsh> query --query='select e.key, e.value from /example-partitioned.entries e'
Result : true
Limit  : 100
Rows   : 1

key | value
--- | -----
2   | two

Nous n'avons récupéré que certaines des entrées de données cette fois parce que ce serveur n'a qu'une seule partition des données, donc lorsqueserver1 a été supprimé, ses données ont été perdues.

But what if we need both partitioning and redundancy? Geode prend également en chargea number of other types. Les trois suivants sont pratiques:

  • PARTITION_REDUNDANT partitionsand réplique nos données sur différents membres du cluster

  • PARTITION_PERSISTENT partitionne les données commePARTITION, mais sur le disque, et

  • PARTITION_REDUNDANT_PERSISTENT  nous donne les trois comportements.

6. Langage de requête d'objet

Geode prend également en charge Object Query Language, ou OQL, qui peut être plus puissant qu'une simple recherche de clé. C’est un peu comme SQL.

Pour cet exemple, utilisons la région "exemple-client" que nous avons créée précédemment.

Si nous ajoutons quelques clients supplémentaires:

Map data = new HashMap<>();
data.put(new CustomerKey(1), new Customer("Gheorge", "Manuc", 36));
data.put(new CustomerKey(2), new Customer("Allan", "McDowell", 43));
this.customerRegion.putAll(data);

Ensuite, nous pouvons utiliserQueryService pour trouver des clients dont le prénom est «Allan»:

QueryService queryService = this.cache.getQueryService();
String query =
  "select * from /example-customers c where c.firstName = 'Allan'";
SelectResults results =
  (SelectResults) queryService.newQuery(query).execute();
assertEquals(1, results.size());

7. Une fonction

L’une des notions les plus puissantes des grilles de données en mémoire est l’idée de «transformer les calculs en données».

En termes simples, puisque Geode est pur Java,it’s easy for us to not only send data but also logic to perform on that data.

Cela pourrait nous rappeler l’idée d’extensions SQL telles que PL-SQL ou Transact-SQL.

7.1. Définir une fonction

Pour définir une unité de travail pour Geode, we implémente l'interfaceFunction de Geode.

Par exemple, imaginons que nous devions changer tous les noms de clients en majuscules.

Au lieu d'interroger les données et de laisser notre application faire le travail, nous pouvons simplement implémenterFunction:

public class UpperCaseNames implements Function {
    @Override
    public void execute(FunctionContext context) {
        RegionFunctionContext regionContext = (RegionFunctionContext) context;
        Region region = regionContext.getDataSet();

        for ( Map.Entry entry : region.entrySet() ) {
            Customer customer = entry.getValue();
            customer.setFirstName(customer.getFirstName().toUpperCase());
        }
        context.getResultSender().lastResult(true);
    }

    @Override
    public String getId() {
        return getClass().getName();
    }
}

Notez quegetId must renvoie une valeur unique, le nom de la classe est donc généralement un bon choix.

LeFunctionContext contient toutes nos données de région et nous pouvons donc en faire une requête plus sophistiquée ou, comme nous l'avons fait ici, la muter.

EtFunction a beaucoup plus de puissance que cela, alors vérifiezthe official manual, en particulierthe getResultSender method.

7.2. Fonction de déploiement

Nous devons informer Geode de notre fonction pour pouvoir l'exécuter. Comme nous l'avons fait avec nos types de données personnalisés, nous emballerons le fichier JAR.

Mais cette fois, nous pouvons simplement utiliser la commandedeploy:

gfsh> deploy --jar=./lib/apache-geode-1.0-SNAPSHOT.jar

7.3. Exécution de la fonction

Maintenant, nous pouvons exécuter lesFunction depuis l'application en utilisant lesFunctionService:

@Test
public void whenExecuteUppercaseNames_thenCustomerNamesAreUppercased() {
    Execution execution = FunctionService.onRegion(this.customerRegion);
    execution.execute(UpperCaseNames.class.getName());
    Customer customer = this.customerRegion.get(new CustomerKey(1));
    assertEquals("GHEORGE", customer.getFirstName());
}

8. Conclusion

Dans cet article, nous avons appris les concepts de base de l'écosystèmeApache Geode. Nous avons examiné des entrées et des sorties simples avec des types standard et personnalisés, des régions répliquées et partitionnées, ainsi que la prise en charge de oql et de fonctions.

Et comme toujours, tous ces échantillons sont disponiblesover on GitHub.