Рубрики
Без рубрики

Краткое руководство по Apache Geode

Изучите основы возможностей Geode как сетки данных в памяти, включая сложное кэширование и распределенные вычисления.

Автор оригинала: baeldung.

1. Обзор

Apache Geode -это распределенная сетка данных в памяти, поддерживающая кэширование и вычисление данных.

В этом уроке мы рассмотрим ключевые концепции Geode и рассмотрим некоторые примеры кода с использованием его Java-клиента.

2. Настройка

Во-первых, нам нужно загрузить и установить Apache Geode и установить среду gfsh . Для этого мы можем следовать инструкциям в официальном руководстве Geode .

И во-вторых, этот учебник создаст некоторые артефакты файловой системы. Таким образом, мы можем изолировать их, создав временный каталог и запустив вещи оттуда.

2.1. Установка и настройка

Из нашего временного каталога нам нужно запустить экземпляр Locator :

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

Локаторы отвечают за координацию между различными членами Geode Кластера , которые мы можем дополнительно администрировать через JMX.

Далее, давайте запустим экземпляр Server для размещения одного или нескольких данных Region |/s:

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

Мы устанавливаем параметр –server-port равным 0, чтобы Geode выбирал любой доступный порт. Хотя, если мы оставим это, сервер будет использовать порт по умолчанию 40404. Сервер-это настраиваемый член Кластера , который работает как долговременный процесс и отвечает за управление данными Регионами .

И, наконец, нам нужен Регион :

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

То Регион в конечном счете, именно там мы будем хранить наши данные.

2.2. Проверка

Давайте убедимся, что у нас все работает, прежде чем мы пойдем дальше.

Во-первых, давайте проверим, есть ли у нас наш Сервер и наш Локатор :

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

И далее, что у нас есть наш Регион :

gfsh> describe region --name=baeldung
..........................................................
Name            : baeldung
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

Кроме того, у нас должны быть некоторые каталоги в файловой системе под вашим временным каталогом под названием “локатор” и “сервер 1”.

С этим результатом мы знаем, что готовы двигаться дальше.

3. Зависимость Maven

Теперь, когда у нас есть работающий Geode, давайте начнем изучать клиентский код.

Чтобы работать с Geode в нашем Java-коде, нам нужно будет добавить Java-клиент Apache Geode библиотеку в наш pom :


     org.apache.geode
     geode-core
     1.6.0

Давайте начнем с простого хранения и извлечения некоторых данных в нескольких регионах.

4. Простое хранение и извлечение

Давайте продемонстрируем, как хранить отдельные значения, пакеты значений, а также пользовательские объекты.

Чтобы начать хранить данные в нашем регионе “баельдунг”, давайте подключимся к нему с помощью локатора:

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

4.1. Сохранение Отдельных Значений

Теперь мы можем просто хранить и извлекать данные в нашем регионе:

@Test
public void whenSendMessageToRegion_thenMessageSavedSuccessfully() {

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

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

4.2. Сохранение нескольких значений одновременно

Мы также можем сохранить несколько значений одновременно, скажем, при попытке уменьшить задержку в сети:

@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. Сохранение Пользовательских Объектов

Строки полезны, но рано или поздно нам придется хранить пользовательские объекты.

Давайте представим, что у нас есть запись клиента, которую мы хотим сохранить, используя следующий тип ключа:

public class CustomerKey implements Serializable {
    private long id;
    private String country;
    
    // getters and setters
    // equals and hashcode
}

И следующий тип значения:

public class Customer implements Serializable {
    private CustomerKey key;
    private String firstName;
    private String lastName;
    private Integer age;
    
    // getters and setters 
}

Есть несколько дополнительных шагов, чтобы иметь возможность хранить их:

Во-первых, они должны реализовать Сериализуемый . Хотя это не является строгим требованием, сделав их сериализуемыми, Geode может хранить их более надежно .

Во-вторых, они должны быть в пути к классам вашего приложения, а также в пути к классам нашего Geode Server .

Чтобы получить их в путь к классам сервера, давайте упакуем их, скажем, с помощью mvn clean package .

И тогда мы можем ссылаться на полученный jar в новой команде start server :

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

Опять же, мы должны выполнить эти команды из временного каталога.

Наконец, давайте создадим новый Регион с именем “baeldung-customers” на Сервере , используя ту же команду, которую мы использовали для создания региона “baeldung”:

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

В коде мы, как и раньше, свяжемся с локатором, указав пользовательский тип:

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

И, затем, мы можем хранить вашего клиента, как и раньше:

@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. Типы регионов

В большинстве сред у нас будет более одной копии или более одного раздела нашего региона, в зависимости от требований к пропускной способности чтения и записи.

До сих пор мы использовали реплицированные области в памяти. Давайте посмотрим поближе.

5.1. Реплицируемый регион

Как следует из названия, Реплицированный регион хранит копии своих данных на более чем одном Сервере|/. Давайте проверим это.

Из консоли gfsh в рабочем каталоге давайте добавим еще один Сервер с именем server2 в кластер:

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

Помните, что когда мы делали “baeldung”, мы использовали –type=REPLICATE . Из-за этого Geode автоматически реплицирует наши данные на новый сервер.

Давайте проверим это, остановив server1:

gfsh> stop server --name=server1

А затем давайте выполним быстрый запрос по региону “баельдунг”.

Если данные были успешно реплицированы, мы получим результаты:

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

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

Итак, похоже, что репликация прошла успешно!

Добавление реплики в наш регион повышает доступность данных. И, поскольку более одного сервера могут отвечать на запросы, мы также получим более высокую пропускную способность чтения.

Но, что, если они оба разобьются? Поскольку это области в памяти, данные будут потеряны . Для этого мы можем вместо этого использовать –type=REPLICATE_PERSISTENT , который также хранит данные на диске во время репликации.

5.2. Разделенная область

С большими наборами данных мы можем лучше масштабировать систему, настроив Geode для разделения области на отдельные разделы или сегменты.

Давайте создадим один разделенный Регион с именем “baeldung-partitioned”:

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

Добавьте некоторые данные:

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

И быстро проверить:

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

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

Затем, чтобы проверить, что данные были разделены, давайте снова остановим server 1 и повторно запросим:

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

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

На этот раз мы вернули только некоторые записи данных, потому что на этом сервере есть только один раздел данных, поэтому, когда server 1 упал, его данные были потеряны.

Но что, если нам нужны и разделение, и избыточность? Geode также поддерживает ряд других типов . Следующие три удобны:

  • PARTITION_REDUNDANT разделы и реплицирует наши данные между различными членами кластера
  • PARTITION_PERSISTENT разбивает данные на разделы , такие как PARTITION , но на диск, и
  • PARTITION_REDUNDANT_PERSISTENT дает нам все три варианта поведения.

6. Язык запросов объектов

Geode также поддерживает язык объектных запросов или OQL, который может быть более мощным, чем простой поиск по ключу. Это немного похоже на SQL.

Для этого примера давайте воспользуемся регионом “баельдунг-клиент”, который мы построили ранее.

Если мы добавим еще пару клиентов:

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);

Затем мы можем использовать QueryService для поиска клиентов, чье имя “Аллан”:

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

7. Функция

Одним из наиболее мощных понятий сеток данных в памяти является идея “переноса вычислений в данные”.

Проще говоря, поскольку Geode-это чистая Java, нам легко не только отправлять данные, но и выполнять логику с этими данными.

Это может напомнить нам об идее расширений SQL, таких как PL-SQL или Transact-SQL.

7.1. Определение функции

Чтобы определить единицу работы для Geode, мы реализуем интерфейс Функции Geode.

Например, давайте представим, что нам нужно изменить все имена клиентов на заглавные.

Вместо того, чтобы запрашивать данные и заставлять наше приложение выполнять работу, мы можем просто реализовать Функцию :

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();
    }
}

Обратите внимание, что getId должно возвращать уникальное значение, поэтому имя класса, как правило, является хорошим выбором.

Контекст функции | содержит все наши данные о регионе, и поэтому мы можем сделать из него более сложный запрос или, как мы сделали здесь, изменить его.

И Функция имеет гораздо больше мощности, чем это , поэтому ознакомьтесь с официальным руководством , особенно методом//getResultSender .

7.2. Функция развертывания

Нам нужно, чтобы Geode знал о нашей функции, чтобы иметь возможность запускать ее. Как и в случае с нашими пользовательскими типами данных, мы упакуем банку.

Но на этот раз мы можем просто использовать команду deploy :

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

7.3. Выполнение Функции

Теперь мы можем выполнить Функцию из приложения, используя службу Function:

@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. Заключение

В этой статье мы познакомились с основными концепциями экосистемы Apache Geode . Мы рассмотрели простые get и put со стандартными и пользовательскими типами, реплицированные и секционированные области, а также поддержку oql и функций.

И, как всегда, все эти образцы доступны на GitHub .