Slide 1

Slide 1 text

Mario-Leander Reimer [email protected] @LeanderReimer Elegantes In-Memory Computing mit Apache Ignite und Kubernetes Heidelberg, 27. September 2017

Slide 2

Slide 2 text

Mario-Leander Reimer Cheftechnologe, QAware GmbH Kontakt Details Phone: +49 89 23 23 15 121 Mail: [email protected] Twitter: @LeanderReimer Github: https://github.com/lreimer 2 Developer && Architect 20+ Jahre Erfahrung #CloudNativeNerd Open Source Enthusiast QAware

Slide 3

Slide 3 text

Exkurs: Cloud-native State

Slide 4

Slide 4 text

QAware 4 Microservices kennen per Definition keinen Zustand. Für Hello World Services ist das ein Kinderspiel.

Slide 5

Slide 5 text

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?

Slide 6

Slide 6 text

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.

Slide 7

Slide 7 text

Introduction

Slide 8

Slide 8 text

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.

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Die wesentlichen Apache Ignite Bausteine im Überblick. QAware 10

Slide 11

Slide 11 text

Data Grid & SQL

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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.

Slide 14

Slide 14 text

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.

Slide 15

Slide 15 text

Ignition.setClientMode(true); Ignite ignite = Ignition.start("data-grid.xml"); CacheConfiguration cacheConfig = new CacheConfiguration<>("companyCache"); IgniteCache cache = ignite.getOrCreateCache(cacheConfig); Company qaware = new Company("1", "QAware GmbH", Long.MAX_VALUE); cache.putIfAbsent(qaware.getCompanyId(), qaware); SqlQuery sql = new SqlQuery<>(Company.class, "revenue > ?"); try (QueryCursor> cursor = cache.query(sql.setArgs(1_000_000))) { List 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 employeeCache = ignite.cache("employeeCache“); Employee reimer = employeeCache.localPeek(new EmployeeKey("11", company.getCompanyId())); ... }); Data Grid Quellcode und Demo. QAware 15 https://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.

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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 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> cursor = cityCache.query(query); Iterator> iterator = cursor.iterator(); SqlFieldsQuery query = new SqlFieldsQuery("DELETE FROM city"); cityCache.query(query).getAll(); Ignite SQL Quellcode und Demo. QAware 17 https://github.com/lreimer/ignite-data2day Nutzung von DDL und SQL per JDBC API. SQL Queries über Ignite SQL API Treiber registrieren & Verbindung öffnen.

Slide 18

Slide 18 text

...startup.servlet.ServletContextListenerStartup IgniteWebSessionsFilter ...cache.websession.WebSessionFilter IgniteWebSessionsFilter /* IgniteConfigurationFilePath config/websession-config.xml IgniteWebSessionsCacheName partitioned QAware 18 Elegantes Web Session Clustering zum Fehler-toleranten Caching von javax.servlet.http Sessions. Cache Configuration für Web Sessions https://github.com/lreimer/ignite-data2day

Slide 19

Slide 19 text

true true org.apache.ignite.cache.hibernate.HibernateRegionFactory hibernate-ignite-grid TRANSACTIONAL QAware 19 Auch der Einsatz von Ignite als 2nd Level Cache von ORM Frameworks ist einfach möglich. Cache Configuration pro JAP Entity 2nd Level Cache Configuration https://github.com/lreimer/ignite-data2day

Slide 20

Slide 20 text

Compute Grid

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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 res = compute.apply(String::length, Arrays.asList(question.split(" "))); int total = res.stream().mapToInt(Integer::intValue).sum(); IgniteCache 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 22 https://github.com/lreimer/ignite-data2day Ausführung einfacher Closures auf einem oder allen Nodes Collocated Compute and Data ExecutorService API von Ignite

Slide 23

Slide 23 text

Service Grid

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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 25 https://github.com/lreimer/ignite-data2day Proxy-based PingService Nutzung mit Stickyness Deployment eines Cluster Singleton PingService Implementierung mit Resource Injection

Slide 26

Slide 26 text

Messaging

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Ignite ignite = Ignition.start("ignite-messaging.xml"); CollectionConfiguration colCfg = new CollectionConfiguration(); colCfg.setCacheMode(CacheMode.PARTITIONED); colCfg.setBackups(1); IgniteQueue queue = ignite.queue("randomUuidQueue", 0, colCfg); queue.add(UUID.randomUUID().toString()); String uuid = queue.poll(5, TimeUnit.SECONDS); IgniteMessaging messaging = ignite.message(); messaging.sendOrdered("OrderedTopic", message, 5000L); messaging.send("UnorderedTopic", message); messaging.localListen("OrderedTopic", (nodeId, msg) -> { System.out.println("Received ordered message [msg=" + msg + ", from=" + nodeId + ']'); return true; // Return true to continue listening. }); messaging.localListen("UnorderedTopic", (nodeId, msg) -> { System.out.println("Received unordered message [msg=" + msg + ", from=" + nodeId + ']'); return true; // Return true to continue listening. }); Ignite Messaging Quellcode und Demo. QAware 28 https://github.com/lreimer/ignite-data2day Topic-based Messaging Queue-based Messaging

Slide 29

Slide 29 text

Streaming

Slide 30

Slide 30 text

Apache Ignite stellt etliche Möglichkeiten zum Einlesen und Streamen von großen Datenmengen bereit. QAware 30

Slide 31

Slide 31 text

IgniteDataStreamer dataStreamer = ignite.dataStreamer("tweetCache"); dataStreamer.allowOverwrite(true); dataStreamer.autoFlushFrequency(10); OAuthSettings oAuthSettings = new OAuthSettings(“consumerKey", “consumerSecret", “accessToken", “acessTokenSecret"); TwitterStreamer streamer = new TwitterStreamer<>(oAuthSettings); streamer.setIgnite(ignite); streamer.setStreamer(dataStreamer); final Gson gson = new Gson(); streamer.setSingleTupleExtractor(msg -> { Tweet tweet = gson.fromJson(msg, Tweet.class); return new GridMapEntry<>(tweet.id, tweet.text); }); Map params = new HashMap<>(); params.put("track", "data2day,qaware,apache ignite,cloud"); params.put("follow", "1346627546,32837461,2650574588"); streamer.setApiParams(params); streamer.setEndpointUrl("/statuses/filter.json"); streamer.setThreadsCount(4); streamer.start(); Ein einfacher TwitterStreamer in nur 20 LOC. QAware 31 DataStreamer für einen Ignite Cache Extract & Parse JSON Erzeigt einen CacheEntry Twitter API Parameter StreamAdapter dient als Abstraktion. https://github.com/lreimer/ignite-data2day

Slide 32

Slide 32 text

Deployment

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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. 34 QAware

Slide 35

Slide 35 text

Konzeptioneller Aufbau eines Kubernetes Cluster. 35 QAware

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

apiVersion: v1 kind: ConfigMap metadata: name: kubernetes-ignite-xml data: kubernetes-ignite.xml: | ... 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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Summary

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

QAware 43

Slide 44

Slide 44 text

Mario-Leander Reimer [email protected] @LeanderReimer github.com/lreimer linkedin.com/qaware slideshare.net/qaware twitter.com/qaware xing.com/qaware