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

Whitelabeling - Skalierungsschmerz einer mandan...

Whitelabeling - Skalierungsschmerz einer mandantenfähigen Plattform

Der Traum eines jeden FinTechs: plötzlich interessieren 500 Banken für die eigene Online-Plattform! Wir haben das Produkt, sie die Kunden - klingt perfekt! Doch wie stellt man 100 neuen Mandanten pro Monat eine perfekt individualisierte Kopie der eigenen Plattform bereit? Lässt sich das betreiben und passen die laufenden Kosten in ein FinTech-Budget? Wir zeigen Ihnen, wie wir das angegangen sind und unsere Java-EE basierte Plattform mandantenfähig wurde, was für uns funktionierte, und wo wir an Grenzen gestoßen sind.

Gregor Tudan

January 22, 2019
Tweet

Other Decks in Technology

Transcript

  1. Wer ist VisualVest ? Gründung: Januar 2015 Robo Advisor Standort:

    Frankfurt am Main Going Live: März 2016 100% Tochter von Union Investment Aktuell 300 Mandanten 18 Mitarbeiter Seite 3
  2. Seite 4 2014 Konzept und Entscheidung 2015 Gründung & Entwicklungsstart

    VisualVest 2016 Public Go Live 2016 Entscheidung für MeinInvest März September Ende 2017 Juli Go-Live der ersten Bank
  3. Agenda 1. White-Labeling & Mandantenfähigkeit • Welche Modelle gibt es?

    • Was passt zu mir? 2. Tech-Deep-Dive • Was brauche ich? • Welche Frameworks können das? 3. War-Stories & Lessons Learned Seite 5
  4. Whitelabeling • Was ist Whitelabeling ? • Anpassung des gleichen

    Produktes individuell für den Kunden • Verwendung von bekannten Marken • Warum braucht man das? • Bereitstellung einer "eigenen" Plattform pro Kunde • Effizienz Seite 6
  5. Kunden Hosten selbst • Bereitstellen der Lösung als „Appliance“ (Kubernetes

    Pod?) • Banken übernehmen das Hosting in der eigenen IT • Ein Vertriebsproblem • Wie bekommt man Updates in die Welt? • Mehr Ärger im 3rd-Level-Support Seite 9
  6. One-Size-Fits-All • Einfach keine Mandantentrennung • Vielleicht ein bisschen Theming

    • Keine Differenzierung bei Features oder Merkmalen (Produkte, Gebühren…) • Ein Produkt- (und Compliance)-Problem Seite 10
  7. Shared-Nothing (Multi-Instance) • Existierende Lösung N-mal duplizieren • Super-Sicher •

    Ein Ops (und Kosten)-Problem • Skaliert (je nach Kundenstruktur) schlecht Seite 11
  8. Multi-Tenancy • Eine Server-Instanz für alle Mandanten • Anpassung über

    Konfiguration • Maßnahmen für Zugriffskontrolle notwendig • Ein Dev-Problem Seite 12
  9. Multi-Tenancy vs. Multi-Instance Multi-Instance Multi-Tenant Kostenmodell f. Mandanten Flach oder

    Stufen Flach, Stufen oder Per-Use Ressourcen Dedicated Resources Shared Resources Wartbarkeit So viele Instanzen wie Kunden zu verwalten Eine Instanz pro N-Kunden zu verwalten Entwicklungs- aufwand Gering – vor allem Konfigurierbarkeit gefragt Hoch – Frameworks müssen Trennung und und Concurrency unterstützen Skalierbarkeit Schwierig – Infrastruktur- und Wartungs- Aufwand steigt proportional zu Kunden Einfach – Infrastuktur wächst mit Anzahl der Benutzer, nicht Kunden Seite 13 Nach: Rodrigo Cândido da Silva – JavaOne 2014 Supporting Multi-tenancy Applications with Java EE
  10. Nehmt doch Docker! 0 40 80 120 160 50 100

    150 200 250 300 350 400 450 500 Benötigte Server Shared Nothing Shared Something Multitenancy Seite 14
  11. Seite 15 Simon Ritter – JavaOne 2011 - The Java

    EE 7 Platform: Developing for the Cloud
  12. Mandantenfähigkeit in JavaEE • 2014: JavaEE 7 – das Cloud-Release,

    dass niemals kam • Buzzwords: “IaaS“, “PaaS“, „SaaS“ • Treiber: Google-App-Engine, Heroku, AWS, OpenShift, CloudFoundry • Vorbilder: SalesForce, SAP ByDesign, Gmail • Fertige Specs für EJB, JPA & JSF • Verschoben auf JavaEE 8 • MicroServices statt Cloud • Verlagerung dieser Themen Richtung MicroProfile Seite 16
  13. Domain-Handling • meinebank.meininvest.de • Kurzname identifiziert die Bank • Wildcard-SSL

    Zertifikat • Wildcard-DNS wäre möglich server { listen 443 ssl; server_name ~^(?<instance>.+?) ⏎ \.meininvest\.de$; location = / { proxy_pass http://localhost:8080; } } Seite 20
  14. HTTP-Interceptor • Requests werden abgefangen • Mandant aus der URL

    auslesen: • meinebank.meininvest.de • In den Request-Scope geschrieben @Provider class MultiTenancyFilter implements ContainerRequestFilter { @Inject MultiTenancySage sage; void filter(ContainerRequestContext ctx) { URI uri = ctx.getUriInfo().getRequestUri(); String tenant = parseURI(uri); sage.setTentant(tenant); } } Seite 21
  15. Konfiguration und Toggles • Bisher traditionell über System-Properties • 100

    ! x 500 " = # • Änderungen zur Laufzeit • Robuste Synchronisierung über alle Server • Hohe Performance, vor allem beim Lesen Seite 22
  16. Konfigurationsdatenbank • „A distributed, reliable key-value store for the most

    critical data of a distributed system.“ • Entscheidend für uns: • Einfach (nur Key-Value-Pairs) • Robust • Effizientes Suchen nach Prefix • angebunden über JCA-Resource-Adapter Seite 23
  17. Datenbanken • Bisher: eine Datenbank pro Service • JPA mit

    Hibernate + Liquibase + PostgreSQL • Strikte Trennung der Mandanten notwendig • Datenbank pro Mandant • Schema pro Mandant • Mandantenspalte pro Tabelle Eine Datenbank pro Service, ein Schema pro Mandant. Seite 24
  18. Multitenancy in der DB Datenbank pro Mandant Schema pro Mandant

    Spalte mit Mandant ID Seite 25 Aus: Hibernate User Manual
  19. Multitenancy mit Hibernate • API wurde für JPA 2.0 schon

    spezifiziert • Von Hibernate implementiert: sessionFactory.withOptions() .tenantIdentifier( tenant ) .openSession(); • Getrennte Caches für Mandanten • Unterstützt alle drei Strategien • Aber: keine Möglichkeit Session zum EntityManager zu machen Seite 26
  20. Multitenancy mit JPA • Möglichkeit eigene Tenant- Provider zu registrieren

    • Resolver: liefert aktuellen Tenant • Provider: liefert eine JDBC- Connection für Tenant • https://medium.com/@gtudan/multi- tenancy-with-jpa-c47416751c8e <persistence> <persistence-unit name="multitenant" transaction-type="JTA"> <properties> <!-- Provider specific multi tenancy config --> <property name="hibernate.multiTenancy" value="SCHEMA"/> <property name="hibernate.multi_tenant_connection_provider" value="de.cofinpro.TenantConnectionProvider"/> <property name="hibernate.tenant_identifier_resolver" value="de.cofinpro.CurrentTenantResolver"/> <!-- schema generation is not supported in multi-tenant environments --> <property name="javax.persistence.schema-generation…" value="none"/> </properties> </persistence-unit> </persistence> Seite 27
  21. JDBC Reauthentication • Verbindung mit User, der nur Connect-Rechte hat

    • Neuanmelden mit dem eigentlichen User • Zusätzliches Pooling nach Mandant (pro Connection-Pool) • Nicht von allen Datenbanken/Treibern unterstützt Seite 28
  22. Multitenancy mit Liquibase • Liquibase: Library zur Versionierung von Datenbankchanges

    • unterstützt bereits Multi-Tenancy • Zur Deploy-Zeit nur in der Spring-Integration implementiert • Alternativ als CDI-Listener oder Servlet-Listener zu implementieren • https://medium.com/@gtudan/multi-tenancy-support-for-liquibase-4d56751eeba8 Seite 29
  23. Login und Authentifizierung • OpenID als Standard • Token wird

    kryptographisch gesichert • bei jedem Request mitgesendet • Vom App-Server überprüft • Relevante Bestandteile eines JSON-Web-Tokens (JWT): • Ausstellender Server (Issuer) • Signatur (Key) • Clients (Origin-URL & Redirect-URL) • Rollen des Benutzers Seite 30
  24. Multitenancy in Keycloak • Keycloak unterstützt mehrere Realms • Keine

    Trennung in der DB • Theming pro Realm möglich • Immer mal wieder Probleme mit „hundrets of reamls“ • Authentication Adapter für Wildfly • normalerweise konfiguriert über Datei (keycloak.json) • Akzeptiert auch Platzhalter (System Properties) • eigene Provider möglich: bestimmt aus URL/Token die relevanten Parameter Seite 31
  25. Multitenancy im Batch Batchverarbeitungen nötig • Nutzung von Partitions •

    Implementierung eines Mappers • Pro Tenant eine Partition • BatchProperty für Tenant Seite 32 https://jaxenter.com/java-ee-7-introduction-to-batch-jsr-352-106192.html
  26. Frontend & Theming • URL-Tricks • Statische Assets unter gleicher

    URL bereitstellen • Bank[1-n].meininvest.de/img/logo.svg • CSS-Tricks • Ein Basis-Stylesheet • Ein Theme-Stylesheet pro Mandantengruppe • eigene Services/SSI für mandantenspezifische Config • Impressum, Datenschutzhinweise, Feature-Toggles… Seite 33
  27. Asynchrone Kommunikation • Wenige Messagebroker unterstützen vHosting • In unserem

    Fall auch nicht notwendig • Eine Queue, mehrere Mandaten • Mandanten als Message-Header • Nutzung von Filtern in den Message-Queues Seite 34 Tenant: meinebank Gemeinsame Queue Tenant == meinebank
  28. Logging • MDC hilft ungemein • setzen des Tenants im

    HTTP-Filter • Log-Format: Wird in jeder Meldung automatisch ausgegeben 08:52:44,647 INFO [de.visualvest.BusinessLogger] (task-569) {"tenant": "meinebank", "clientId": "88b57aea-…"} Persönliche Daten: Der Bankmitarbeiter hat … • Wir verwenden ERK-Stack (ElasticSearch, Rsyslog, Kibana) • Filebasiertes Logging • Rsyslog übermittelt Logs und teilt sie am Server pro Mandant auf Seite 35
  29. Lessons learned • Komplexes Thema mit vielen Aspekten • Konzepte

    kennen und verstehen • Technisch komplex, aber beherrschbar • Zuviel "Magic" führt zu Problemen • Zeit nehmen und schrittweise vorgehen: • Herausforderung für die Entwickler • BigBang in einem Sprint = ! (Oh Gott eine TASKFORCE!) Seite 36