Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elegantes In-Memory Computing mit Apache Ignite und Kubernetes. @data2day

Elegantes In-Memory Computing mit Apache Ignite und Kubernetes. @data2day

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

M.-Leander Reimer

September 27, 2017
Tweet

More Decks by M.-Leander Reimer

Other Decks in Technology

Transcript

  1. 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
  2. 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?
  3. 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.
  4. 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.
  5. 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
  6. 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
  7. 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.
  8. 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.
  9. 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 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.
  10. 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
  11. 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 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.
  12. <listener> <listener-class>...startup.servlet.ServletContextListenerStartup </listener-class> </listener> <filter> <filter-name>IgniteWebSessionsFilter</filter-name> <filter-class>...cache.websession.WebSessionFilter</filter-class> </filter> <filter-mapping> <filter-name>IgniteWebSessionsFilter</filter-name>

    <url-pattern>/*</url-pattern> </filter-mapping> <context-param> <param-name>IgniteConfigurationFilePath</param-name> <param-value>config/websession-config.xml</param-value> </context-param> <context-param> <param-name>IgniteWebSessionsCacheName</param-name> <param-value>partitioned</param-value> </context-param> 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
  13. <hibernate-configuration> <session-factory> <property name="cache.use_second_level_cache">true</property> <property name="generate_statistics">true</property> <property name="cache.region.factory_class"> org.apache.ignite.cache.hibernate.HibernateRegionFactory </property>

    <property name="org.apache.ignite.hibernate.ignite_instance_name"> hibernate-ignite-grid </property> <property name="org.apache.ignite.hibernate.default_access_type"> TRANSACTIONAL </property> <mapping class="com.mycompany.MyEntity1"/> <class-cache class="com.mycompany.MyEntity1" usage="read-only"/> <collection-cache collection="com.mycompany.MyEntity1.children“ usage="read-only"/> </session-factory> </hibernate-configuration> 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
  14. 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
  15. 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 22 https://github.com/lreimer/ignite-data2day Ausführung einfacher Closures auf einem oder allen Nodes Collocated Compute and Data ExecutorService API von Ignite
  16. 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
  17. 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
  18. 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
  19. Ignite ignite = Ignition.start("ignite-messaging.xml"); CollectionConfiguration colCfg = new CollectionConfiguration(); colCfg.setCacheMode(CacheMode.PARTITIONED);

    colCfg.setBackups(1); IgniteQueue<String> 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
  20. IgniteDataStreamer<Long, String> dataStreamer = ignite.dataStreamer("tweetCache"); dataStreamer.allowOverwrite(true); dataStreamer.autoFlushFrequency(10); OAuthSettings oAuthSettings =

    new OAuthSettings(“consumerKey", “consumerSecret", “accessToken", “acessTokenSecret"); TwitterStreamer<Long, String> 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<String, String> 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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