Mit Apache Ignite steht eine hoch-performante, integrierte und verteilte In-Memory Plattform bereit die im Zusammenspiel mit Kubernetes zu wahrer Hochform aufläuft. In dieser Kombination lassen sich flexibel skalierbare In-Memory Computing Systeme elegant realisieren. In diesem Vortrag stellen wir die wesentlichen Features und die Architektur von Apache Ignite vor. Anhand von anschaulichen Beispielen zeigen wir mögliche Use-Cases, wie etwa den Einsatz als Kommunikations-Backbone einer Microservice-Architektur oder als Plattform zur Verarbeitung von kontinuierlichen Event-Daten. Zur Demonstration von Resilienz und Skalierbarkeit werden die Beispiele auf einem tragbaren K8S Cluster ausgeführt.
@data2day @qaware #CloudNativeNerd
https://www.data2day.de/veranstaltung-5997-elegantes-in-memory-computing-mit-apache-ignite-und-kubernetes.html?id=5997
5. QAware 5
Im Enterprise Umfeld ist die Realität oft eine Andere.
Zustand ist hier nicht die Ausnahme sondern die Regel.
Wie aggregiere ich
zusammenhängende
Sensor-Daten?
Wie verarbeite ich
einen kontinuierlichen
Daten-Strom effizient?
Wie suche und
analysiere ich
Daten effizient?
Wie stelle ich zeitlich
limitierte Auth-Tokens
ausfallsicher im Cluster
zur Verfügung?
Wie gehe ich mit
Zustandsbehafteten
Technologien um?
Wie greife ich
auf performant
auf langsame
Legacy DBs zu?
6. QAware 6
Die Lösung: Der Zustand wird ausgelagert und selbst zu
einem Service.
Zustandsverwaltung wird in einen
dedizierten Service ausgelagert.
Einfacher Cache (mit PUT und GET)
Komplexe Abfragen und Analysen.
Persistent und Konsistent.
Skalierbar und Hochverfügbar.
8. Was ist Ignite? Eine In-Memory Computing Plattform.
QAware 8
Apache Ignite is an in-memory computing platform that is durable, strongly consistent,
and highly available with powerful SQL, key-value and processing APIs.
Key-Value: ein voll transaktionaler, verteilter Key/Value Store. Horizontal skalierbar.
Durable Memory: das RAM als voll funktionsfähige Storage-Layer (nicht nur Caching-Layer). Off-Heap.
Integration mit Ignite Persistence für volle Datenkonsistenz und Resilienz bei kompletten Cluster-Failures.
Ignite Persistence: Optional. Verteilter Disk-Storage Layer für Daten und Indizes auf SSDs, Flash, …
ACID Compliance: der In-Memory und der Disk Store sind ACID-compliant und bieten Strong Consistency.
Collocated Processing: Berechnungen werden zu den Daten gesendet (und nicht umgekehrt). Minimierte
Datenbewegungen sorgen für gute Skalierbarkeit.
Vollständige SQL Unterstützung: Ignite ist eine verteilte SQL Datenbank. Unterstützt SQL, DDL und DML.
Nutzer können Ignite mittels reinem SQL nutzen (CREATE TABLE, INSERT, SELECT, DELETE, …).
Scalability und Durability: Ignite ist ein elastisches, horizontal skalierbares verteiltes System. Nodes können
dynamisch hinzugefügt und entfernt werden. Ist resilient gegenüber teilweisen Cluster-Ausfällen.
9. Historie und Releases seit Feb 16, 2014.
QAware 9
2014-10-01
Project enters
incubation.
2014-02-16
First commit.
2015-04-04
v1.0.0
2015-09-18
Project graduated
from incubation.
2017-07-27
v2.1.0
2017-05-04
v2.0.0
2016-09-28
v1.4.1
2016-12-05
v1.8.0-rc1
12. Implementierung der JCache (JSR 107) Spec
Unterstützt verschiedene Cache Modes:
REPLICATED, PARTITIONED, NEAR und LOCAL
Affinity basierte Kollokation von Daten mit Daten
und Daten mit Compute.
Unterstützt Cache Abfragen per API, SQL und
Lucene Text Queries
Kontinuierliche Queries für Echtzeit Abfrage und
Streaming der Ergebnisse
Atomic oder Transactional Cache Mode
Pessimistic und Optimistic Transaktionen
Cross-Cache Transaktionen sind möglich
Data Rebalancing wenn sich die Topologie ändert
Der Data Grid Baustein ist ein Distributed Key/Value
Store und Cache.
QAware 12
13. Partitioned Caches im Detail.
QAware 13
Cache Mode mit bester Skalierbarkeit.
Ideal für große Datenmengen. == Total Memory
(RAM + Disk)
Mehr Nodes bedeutet mehr Daten.
Ideal bei häufigen Updates, da nur Primary Node
und optional Backups aktualisiet werden.
Affinity Collocation sollte genutzt werden um
Daten performant zu verarbeiten.
Jeder Schlüssel wird genau einem Primary
Node zugeordnet.
Near Cache für den performanten Zugriff auf
Daten in Remote Client JVMs.
14. Replicated Caches im Detail.
QAware 14
Cache Mode mit bester Verfügbarkeit der Daten
auch im Fehlerfall
Alle Daten sind auf jedem Node.
Aber Updates müssen an alle Nodes propagiert
werden, das hat Einfluss auf die Skalierbarkeit.
Replicated Caches sind als Partitioned Caches
realisiert. Jeder Key hat eine Backup Copy auf
jedem Node.
Near Cache für den performanten Zugriff auf
Daten in Remote Client JVMs.
15. Ignition.setClientMode(true);
Ignite ignite = Ignition.start("data-grid.xml");
CacheConfiguration<String, Company> cacheConfig = new CacheConfiguration<>("companyCache");
IgniteCache<String, Company> cache = ignite.getOrCreateCache(cacheConfig);
Company qaware = new Company("1", "QAware GmbH", Long.MAX_VALUE);
cache.putIfAbsent(qaware.getCompanyId(), qaware);
SqlQuery<String, Company> sql = new SqlQuery<>(Company.class, "revenue > ?");
try (QueryCursor<Cache.Entry<String, Company>> cursor = cache.query(sql.setArgs(1_000_000))) {
List<Company> companies = cursor.getAll().stream().map(Cache.Entry::getValue).collect(Collectors.toList());
...
}
ignite.compute().affinityRun("companyCache", "1", () -> {
Company company = cache.get("1");
// we collocated employees with the company, so access to the employee objects is local.
IgniteCache<EmployeeKey, Employee> employeeCache = ignite.cache("employeeCache“);
Employee reimer = employeeCache.localPeek(new EmployeeKey("11", company.getCompanyId()));
...
});
Data Grid Quellcode und Demo.
QAware 15https://github.com/lreimer/ignite-data2day
Ignite im Client Mode starten.
Beispiel für Caching von
Daten und SQL Query.
Beispiel für Data Collocation
und Affinity Run.
16. Einzigartige, horizontal skalierbare, Fehler tolerante In-
Memory SQL Datenbank
ANSI-99 SQL compliant SQL, DML und DDL
Unterstützung von Cross-Cache Queries und Distributed
Joins (Collocated und Non-Collocated)
Einfache Java Annotation basierte Konfiguration von SQL
Query Fields und Indizes
Anbindung von externen Anwendungen erfolgt per JDBC
und ODBC Treiber
Anbindung von Ignite Clients erfolgt primär über das Ignite
SQL (oder Lucene Search) API
Ignite SQL ist eine ANSI-99 SQL kompatible In-Memory
Datenbank mit Zugriff per JDBC, ODBC oder SQL API.
QAware 16
17. Class.forName("org.apache.ignite.IgniteJdbcDriver");
Connection connection = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10800?collocated=true");
Statement stmt = connection.createStatement());
stmt.executeUpdate("CREATE TABLE city (id LONG PRIMARY KEY, name VARCHAR) WITH "template=partitioned, backups=0"");
stmt.executeUpdate("CREATE INDEX idx_city_name ON city (name)");
PreparedStatement stmt = connection.prepareStatement("INSERT INTO city (id, name) VALUES (?, ?)")
stmt.setLong(1, 1L);
stmt.setString(2, “Heidelberg");
stmt.executeUpdate();
Ignition.setClientMode(true);
Ignite ignite = Ignition.start("ignite-sql.xml");
IgniteCache<Long, String> cityCache = ignite.cache("SQL_PUBLIC_CITY");
SqlFieldsQuery query = new SqlFieldsQuery("SELECT p.name, c.name FROM Person p, City c WHERE p.city_id = c.id");
FieldsQueryCursor<List<?>> cursor = cityCache.query(query);
Iterator<List<?>> iterator = cursor.iterator();
SqlFieldsQuery query = new SqlFieldsQuery("DELETE FROM city");
cityCache.query(query).getAll();
Ignite SQL Quellcode und Demo.
QAware 17https://github.com/lreimer/ignite-data2day
Nutzung von DDL und SQL per JDBC API.
SQL Queries über Ignite SQL API
Treiber registrieren & Verbindung öffnen.
21. High Performance, Low Latency, Linear Scalability.
Einfaches API um Berechnungen und Daten-
verarbeitungen im Cluster verteilt auszuführen.
Zero-Deployment für Jobs durch Peer Classloading.
Broadcast und Load-Balancing von Closures auf dem
Cluster oder einer Cluster Node Gruppe.
Cluster-enabled ExecutorService Implementierung
Leichtgewichtige Abstraktion und APIs für In-
Memory MapReduce (oder ForkJoin) Tasks.
Collocation von Berechnung und Daten.
Mit dem Compute Grid können Berechnungen auf den
Ignite Cluster Nodes verteilt ausgeführt werden.
QAware 21
22. Ignite ignite = Ignition.start("compute-grid.xml");
IgniteCompute compute = ignite.compute(ignite.cluster().forRemotes());
compute.run(() -> System.out.println("Running distributed closure (1) on " + ignite.cluster().localNode().id()));
compute.broadcast(() -> System.out.println("Broadcasting distributed closure on " + ignite.cluster().localNode().id()));
final String question = "How many characters has this sentence?";
Collection<Integer> res = compute.apply(String::length, Arrays.asList(question.split(" ")));
int total = res.stream().mapToInt(Integer::intValue).sum();
IgniteCache<Integer, String> cache = ignite.cache("someCache");
compute.affinityRun("someCache", key, () -> {
System.out.println("Co-located processing [key= " + key + ", value= " + someCache.localPeek(key) + ']');
});
ExecutorService executorService = ignite.executorService(ignite.cluster().forRemotes());
executorService.submit(new IgniteRunnable() {
@IgniteInstanceResource private Ignite ignite;
@Override
public void run() {
System.out.println("Processing runnable on " + ignite.cluster().localNode().id() + " from grid job.");
}
});
Compute Grid Quellcode und Demo.
QAware 22https://github.com/lreimer/ignite-data2day
Ausführung einfacher Closures
auf einem oder allen Nodes
Collocated Compute and Data
ExecutorService API von Ignite
24. Das Service Grid kann als Backbone für eine Microservice-
basierte Applikation verwendet werden.
Kontinuierliche Verfügbarkeit der Dienste im Cluster
unabhängig von Änderungen der Topologie.
Load-Balancing der Anfragen auf Service Instanzen.
Singleton Pattern: Cluster-Singletons, Node Singletons und
Key Affinity Singletons sind möglich.
Deploy/Undeploy von Diensten zur Laufzeit.
Deployment von Diensten beim Start von neuen Nodes.
Programmatischer Zugriff auf Service Katalog + Metadaten.
Nutzung von Remote Services erfolgt über einen Interface-
basierten Proxy Mechanismus (Access Transparency)
Mit dem Service Grid können beliebige Dienste in Ignite
ausfallsicher betrieben und aufgerufen werden.
QAware 24
25. Ignite ignite = Ignition.start("service-grid.xml");
IgniteServices services = ignite.services();
PingService pingService = services.serviceProxy("PingService", PingService.class, true);
String pong = pingService.ping();
services.deployClusterSingleton("RandomUuidService", new DefaultRandomUuidService());
RandomUuidService randomUuidService = services.serviceProxy("RandomUuidService", RandomUuidService.class, false);
String response = randomUuidService.randomUUID();
public class DefaultPingPongService implements PingService, Service {
@IgniteInstanceResource private Ignite ignite;
@Override
public void init(ServiceContext ctx) throws Exception {...}
@Override
public void cancel(ServiceContext ctx) {...}
@Override
public void execute(ServiceContext ctx) throws Exception {...}
@Override
public String ping() { return "pong“; }
}
Service Grid Quellcode und Demo.
QAware 25https://github.com/lreimer/ignite-data2day
Proxy-based PingService
Nutzung mit Stickyness
Deployment eines
Cluster Singleton
PingService Implementierung
mit Resource Injection
27. Topic-basierte, Cluster-weite Kommunikation
zwischen allen Cluster Nodes.
Das Data Grid bietet zusätzlich eine schnelle,
verteilte Blocking Queue Implementierung.
Topic Nachrichten können Ordered oder
Unordered publiziert werden.
Nachrichten können an alle oder an eine Gruppe
von Cluster Nodes zugestellt werden.
Nachrichten können einen Timeout haben.
Neue Cluster Nodes werden automatisch für alle
Topics registriert.
Listener können nur auf dem lokalen Node oder
auf allen Nodes registriert werden.
Ignite ermöglicht einfaches Queue und Topic basiertes
Messaging ohne zusätzliche Middleware.
QAware 27
33. Einfaches und schnelles Deployment on-
premise oder in einer Cloud Umgebung.
Läuft auf Bare Metal aber auch auf
virtualisierter Hardware.
Kann Stand-alone und auch als Docker
Container betrieben werden.
Für GCE und AWS stehen entsprechende
VM Images zur Verfügung.
Der Ignite Node Discovery-Mechanismus
muss passend zur jeweiligen Umgebung
konfiguriert werden.
Infrastructure-as-a-Service und Platform-as-a-Service
Deployments von Apache Ignite werden unterstützt.
QAware 33
34. echo "- The default provider is GCE"
export KUBERNETES_PROVIDER=gce
export KUBE_GCE_ZONE=europe-west1-d
export NUM_NODES=4
echo "- Another possible provider is AWS"
export KUBERNETES_PROVIDER=aws
export KUBE_AWS_ZONE=eu-central-1a
export NODE_SIZE=t2.small
curl -sS https://get.k8s.io | bash
Easy K8s setup: Local, Bare Metal, Cloud or Managed.
34QAware
36. Services sind eine Abstraktion für eine logische
Sammlung von Pods
Pods sind die kleinste deploybare Compute
Einheit in K8S
Deployments dienen der Deklaration von Pods,
Volumes und RCs
Replica Sets stellen die geforderte Anzahl an
Replicas sicher
Labels sind Key/Value Paare die zur Identifikation
verwendet werden
Config Maps enthalten Umgebungsanhängige
Konfigurationswerte, diese werden in Pods als
Volumes oder per ENV verwendet.
Volumes sind Verzeichnisse auf die Container
zugreifen können.
Die wichtigsten K8s Konzepte die man kennen muss.
QAware 36
37. apiVersion: v1
kind: Service
metadata:
# Name of Ignite Service used by Kubernetes IP finder.
# must be equal to TcpDiscoveryKubernetesIpFinder.serviceName.
name: ignite
spec:
clusterIP: None # custom value.
ports:
- port: 9042 # custom value.
selector:
# Must be equal to one of the labels set in Ignite pods'
# deployment configuration.
app: ignite
QAware 37
Ein Kubernetes Service übernimmt die Node Discovery
für die Pods des Ignite Clusters.
$ kubectl create –f ignite-service.yaml
https://github.com/lreimer/ignite-data2day
38. apiVersion: v1
kind: ConfigMap
metadata:
name: kubernetes-ignite-xml
data:
kubernetes-ignite.xml: |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans ...>
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
...
<!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean
class="org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes.TcpDiscoveryKubernetesIpFinder">
</bean>
</property>
</bean>
</property>
</bean>
</beans>
QAware 38
Über eine Kubernete ConfigMap werden die Ignite Pods
mit der nötigen XML Konfiguration versorgt.
Ignite Node Discovery
läuft über den definierten
Kubernetes Service
$ kubectl create –f ignite-configmap.yaml
https://github.com/lreimer/ignite-data2day
39. apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ignite
spec:
replicas: 2
template:
metadata:
labels:
app: ignite
spec:
containers:
- name: ignite-node
image: apacheignite/ignite:2.1.0
env:
- name: CONFIG_URI
value: file:///opt/ignite/apache-ignite-fabric-2.1.0-bin/data2day/config/kubernetes-ignite.xml
- name: OPTION_LIBS
value: ignite-kubernetes
ports: ...
volumeMounts:
- mountPath: /opt/ignite/apache-ignite-fabric-2.1.0-bin/data2day/config
name: ignite-config
volumes:
QAware 39
Die Ignite Data Nodes werden über ein Kubernetes
Deployment gestartet und skaliert.
$ kubectl create –f ignite-deployment.yaml
$ kubectl scale deployment ignite --replicas=4
Label muss zum Selector
im Ignite Service passen
Die nötige Konfiguration
wird per ENV an den Ignite
Container übergeben
Ignite XML Konfiguration per
ConfigMap VolumeMount
https://github.com/lreimer/ignite-data2day
41. Apache Ignite ist eine mächtige In-Memory Computing
Plattform die mit Kubernetes zur Hochform aufläuft.
41
Apache Ignite ist eine ausgereifte und stabile Plattform.
Das API fühlt sich gut an, es ist einfach zu programmieren.
Einfache Use Cases lassen sich sehr schnell umsetzen.
Mannigfaltige Deployment Optionen und schnelles Setup.
Die Dokumentation ist gut und ausreichend.
QAware
42. Quellcode und Lesestoff für Zuhause …
42
https://github.com/lreimer/ignite-data2day
https://apacheignite.readme.io/docs
Microservices on Top of an In-Memory Data Grid: Part I
https://goo.gl/2jqm1E
Microservices on Top of an In-Memory Data Grid: Part II
https://goo.gl/edNlUK
Microservices on Top of an In-Memory Data Grid: Part III
https://goo.gl/uAPoNw
QAware