Ръководство за Apache Ignite

1. Въведение

Apache Ignite е разпределена платформа, ориентирана към паметта с отворен код. Можем да го използваме като база данни, кешираща система или за обработка на данни в паметта.

Платформата използва паметта като слой за съхранение, поради което има впечатляваща производителност. Просто казано, това е една от най-бързите атомни платформи за обработка на данни, които се използват в момента.

2. Инсталиране и настройка

Като начало разгледайте страницата за начало за първоначалните инструкции за настройка и инсталиране.

Зависимостите на Maven за приложението, което ще изградим:

 org.apache.ignite ignite-core ${ignite.version}   org.apache.ignite ignite-indexing ${ignite.version} 

ignite-core е единствената задължителна зависимост за проекта . Тъй като ние също искаме да взаимодействаме със SQL, индиксирането на запалване също е тук. $ {ignite.version} е най-новата версия на Apache Ignite.

Като последна стъпка стартираме възела Ignite:

Ignite node started OK (id=53c77dea) Topology snapshot [ver=1, servers=1, clients=0, CPUs=4, offheap=1.2GB, heap=1.0GB] Data Regions Configured: ^-- default [initSize=256.0 MiB, maxSize=1.2 GiB, persistenceEnabled=false]

Изходът на конзолата по-горе показва, че сме готови за работа.

3. Архитектура на паметта

Платформата е базирана на Durable Memory Architecture . Това позволява да се съхраняват и обработват данните както на диск, така и в памет. Той увеличава производителността, като използва ефективно ресурсите на RAM на клъстера.

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

Трайната архитектура на паметта се разделя на блокове с фиксиран размер, наречени страници. Страниците се съхраняват извън купчината на Java и се организират в RAM. Той има уникален идентификатор: FullPageId .

Страниците взаимодействат с паметта, като използват абстракцията PageMemory .

Помага за четене, писане на страница, както и за разпределяне на идентификатор на страница. Вътре в паметта Ignite свързва страници с буфери на паметта .

4. Страници с памет

Страницата може да има следните състояния:

  • Разтоварен - в паметта не е зареден буфер на страница
  • Clear - буферът на страницата се зарежда и синхронизира с данните на диска
  • Durty - буферът на страницата съдържа данни, които са различни от тези на диска
  • Мръсна контролна точка - има друга модификация, която започва преди първата да продължи на диска. Тук започва контролна точка и PageMemory поддържа два буфера памет за всяка страница.

Трайната памет разпределя локално сегмент памет, наречен Data Region . По подразбиране той има капацитет от 20% от паметта на клъстера. Конфигурацията на множество региони позволява съхраняването на използваемите данни в паметта.

Максималният капацитет на региона е сегмент памет. Това е физическа памет или непрекъснат байтов масив.

За да се избегнат фрагментации на паметта, една страница съдържа множество записи ключ-стойност . Всеки нов запис ще бъде добавен към най-оптималната страница. Ако размерът на двойката ключ-стойност надвишава максималния капацитет на страницата, Ignite съхранява данните в повече от една страница. Същата логика се отнася и за актуализиране на данните.

SQL и кеш индексите се съхраняват в структури, известни като B + Trees. Кешовите ключове са подредени по техните ключови стойности.

5. Жизнен цикъл

Всеки възел Ignite работи на един екземпляр на JVM . Възможно е обаче да се конфигурира да има множество възли Ignite, работещи в един JVM процес.

Нека да разгледаме типовете събития от жизнения цикъл:

  • BEFORE_NODE_START - преди стартирането на възлите на Ignite
  • AFTER_NODE_START - изстрелва се веднага след стартирането на възпламенителния възел
  • BEFORE_NODE_STOP - преди иницииране на спиране на възела
  • AFTER_NODE_STOP - след като възелът Ignite спре

За да стартирате възел за възпламеняване по подразбиране:

Ignite ignite = Ignition.start();

Или от конфигурационен файл:

Ignite ignite = Ignition.start("config/example-cache.xml");

В случай, че се нуждаем от повече контрол върху процеса на инициализация, има друг начин с помощта на интерфейса LifecycleBean :

public class CustomLifecycleBean implements LifecycleBean { @Override public void onLifecycleEvent(LifecycleEventType lifecycleEventType) throws IgniteException { if(lifecycleEventType == LifecycleEventType.AFTER_NODE_START) { // ... } } }

Тук можем да използваме типовете събития от жизнения цикъл, за да изпълняваме действия преди или след възела да започне / спре.

За тази цел предаваме екземпляра на конфигурацията с CustomLifecycleBean на метода start:

IgniteConfiguration configuration = new IgniteConfiguration(); configuration.setLifecycleBeans(new CustomLifecycleBean()); Ignite ignite = Ignition.start(configuration);

6. Решетка за данни в паметта

Решетката за данни на Ignite е разпределено хранилище ключ-стойност , много познато на разделената HashMap . Той е хоризонтално мащабиран. Това означава, че добавяме повече клъстерни възли, повече данни се кешират или съхраняват в паметта.

It can provide significant performance improvement to the 3rd party software, like NoSql, RDMS databases as an additional layer for caching.

6.1. Caching Support

The data access API is based on JCache JSR 107 specification.

As an example, let's create a cache using a template configuration:

IgniteCache cache = ignite.getOrCreateCache( "baeldingCache");

Let's see what's happening here for more details. First, Ignite finds the memory region where the cache stored.

Then, the B+ tree index Page will be located based on the key hash code. If the index exists, a data Page of the corresponding key will be located.

When the index is NULL, the platform creates the new data entry by using the given key.

Next, let's add some Employee objects:

cache.put(1, new Employee(1, "John", true)); cache.put(2, new Employee(2, "Anna", false)); cache.put(3, new Employee(3, "George", true));

Again, the durable memory will look for the memory region where the cache belongs. Based on the cache key, the index page will be located in a B+ tree structure.

When the index page doesn't exist, a new one is requested and added to the tree.

Next, a data page is assigning to the index page.

To read the employee from the cache, we just use the key value:

Employee employee = cache.get(1);

6.2. Streaming Support

In memory data streaming provides an alternative approach for the disk and file system based data processing applications. The Streaming API splits the high load data flow into multiple stages and routes them for processing.

We can modify our example and stream the data from the file. First, we define a data streamer:

IgniteDataStreamer streamer = ignite .dataStreamer(cache.getName());

Next, we can register a stream transformer to mark the received employees as employed:

streamer.receiver(StreamTransformer.from((e, arg) -> { Employee employee = e.getValue(); employee.setEmployed(true); e.setValue(employee); return employee; }));

As a final step, we iterate over the employees.txt file lines and convert them into Java objects:

Path path = Paths.get(IgniteStream.class.getResource("employees.txt") .toURI()); Gson gson = new Gson(); Files.lines(path) .forEach(l -> streamer.addData( employee.getId(), gson.fromJson(l, Employee.class)));

With the use of streamer.addData() put the employee objects into the stream.

7. SQL Support

The platform provides memory-centric, fault-tolerant SQL database.

We can connect either with pure SQL API or with JDBC. SQL syntax here is ANSI-99, so all the standard aggregation functions in the queries, DML, DDL language operations are supported.

7.1. JDBC

To get more practical, let's create a table of employees and add some data to it.

For that purpose, we register a JDBC driver and open a connection as a next step:

Class.forName("org.apache.ignite.IgniteJdbcThinDriver"); Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/");

With the help of the standard DDL command, we populate the Employee table:

sql.executeUpdate("CREATE TABLE Employee (" + " id LONG PRIMARY KEY, name VARCHAR, isEmployed tinyint(1)) " + " WITH \"template=replicated\"");

After the WITH keyword, we can set the cache configuration template. Here we use the REPLICATED. By default, the template mode is PARTITIONED. To specify the number of copies of the data we can also specify BACKUPS parameter here, which is 0 by default.

Then, let's add up some data by using INSERT DML statement:

PreparedStatement sql = conn.prepareStatement( "INSERT INTO Employee (id, name, isEmployed) VALUES (?, ?, ?)"); sql.setLong(1, 1); sql.setString(2, "James"); sql.setBoolean(3, true); sql.executeUpdate(); // add the rest 

Afterward, we select the records:

ResultSet rs = sql.executeQuery("SELECT e.name, e.isEmployed " + " FROM Employee e " + " WHERE e.isEmployed = TRUE ")

7.2. Query the Objects

It's also possible to perform a query over Java objects stored in the cache. Ignite treats Java object as a separate SQL record:

IgniteCache cache = ignite.cache("baeldungCache"); SqlFieldsQuery sql = new SqlFieldsQuery( "select name from Employee where isEmployed = 'true'"); QueryCursor
    
      cursor = cache.query(sql); for (List row : cursor) { // do something with the row }
    

8. Summary

In this tutorial, we had a quick look at Apache Ignite project. This guide highlights the advantages of the platform over other simial products such as performance gains, durability, lightweight APIs.

В резултат на това научихме как да използваме езика SQL и Java API за съхраняване, извличане, поточно предаване на данни вътре в мрежата за постоянство или в паметта.

Както обикновено, пълният код за тази статия е достъпен в GitHub.