CodamAIDocs
Themafertig

Datenbanken, Pools, Migration

Jeder Mandant hat eine eigene Datenbank mit eigenem Verbindungspool. Wann sie angelegt und wie ihr Schema migriert wird.

Ausprägungen
Anlage bei ProvisionierungAnlage beim ersten ZugriffDatenbank fehlt ohne Freigabe → 500Server nicht erreichbar → 503Migration pro MandantPool pro ZielRäumen ungenutzter Mandanten

Worum es geht

In MULTI hat jeder Mandant eine eigene Datenbank. Zu jeder Datenbank gehören drei Dinge, die CDMS verwaltet:

  • die Datenbank selbst, mit dem Mandantenschlüssel als Namen,
  • ihr Schema, also die Tabellen der Modelle,
  • ein Verbindungspool. Das ist ein Vorrat an offenen Verbindungen zur Datenbank, die sich die Anfragen ausleihen, statt jedes Mal eine neue aufzubauen.

Dazu kommt für jedes Ziel ein Objekt, das Hibernate zum Arbeiten braucht: die EntityManagerFactory. Sie kennt die Modelle des Ziels und wird beim ersten Zugriff gebaut. Mit ihr entstehen auch Pool und Schema.

Der Lebenslauf eines Persistenzziels

  1. 1
    CDMS
    erster Zugriff auf Mandant acme seit dem Start, oder CIAS stellt acme bereit
  2. 2
    CDMS→Database
    fragt den Datenbankserver: Gibt es die Datenbank acme?
  3. 3
    CDMS→Database
    fehlt sie und ist Anlegen freigegeben → CREATE DATABASE acme
  4. 4
    CDMS
    baut den Verbindungspool für acme
  5. 5
    CDMS→Database
    bringt das Schema auf den aktuellen Stand
  6. 6
    CDMS
    baut die EntityManagerFactory mit den Mandanten- und Benutzer-Modellen
    Ergebnis: Ab jetzt nutzen alle Anfragen von acme Pool und Factory, bis sie geräumt werden.

Wann die Datenbank angelegt wird

Es gibt zwei Wege, die zum selben Ergebnis führen:

Bereitstellung vorab oder beim ersten Zugriff

Wann: CIAS läuft in derselben Anwendung wie CDMS und legt den Mandanten an.

  1. 1
    CIAS
    legt den Mandanten acme an
  2. 2
    CIAS→CDMS
    bittet um Bereitstellung von acme
  3. 3
    CDMS→Database
    legt Datenbank und Schema an, wie oben beschrieben

Ergebnis: Scheitert das, erfährt es der Betrieb beim Anlegen des Kunden und nicht der Kunde bei seiner ersten Anfrage. Das Anlegen lässt sich gefahrlos wiederholen.

Wann: CIAS läuft als eigener Dienst, oder die Bereitstellung wurde übersprungen.

  1. 1
    Client→CDMS
    erste Anfrage für acme
  2. 2
    CDMS→Database
    legt Datenbank und Schema an, wie oben beschrieben

Ergebnis: Die erste Anfrage dauert länger. Scheitert die Anlage, bekommt diese Anfrage den Fehler.

Wann: CODAMAI_PERSISTENCE_TENANT_MODE=SINGLE

Es gibt nur die eine Datenbank. Eine Bereitstellung je Mandant hat nichts zu tun und meldet sofort Erfolg.

Ergebnis: Die eine Datenbank muss es geben oder sie wird beim Start wie oben angelegt.

Was CDMS tut, wenn es die Datenbank braucht
Datenbankserver erreichbarDatenbank vorhandenAnlegen freigegebenErgebnis
jaja–Datenbank wird benutzt
janeinjaDatenbank wird angelegt und benutzt
janeinnein500 CDMS_TENANT_DATASOURCE_NOT_FOUND
nein––503 CDMS_TENANT_DATASOURCE_UNAVAILABLE, kein Anlegeversuch

Die Freigabe ist CODAMAI_PERSISTENCE_DATABASE_AUTO_CREATE_TENANT_DATABASE=true. Ohne sie legt der Betrieb jede Mandanten-Datenbank selbst an. Ein nicht erreichbarer Server gilt nie als „Datenbank fehlt“. Sonst würde ein kurzer Ausfall eine Anlage auslösen.

Automatisch anlegen kann CDMS Datenbanken auf MySQL, mit Zeichensatz utf8mb4. Direkt vor dem CREATE DATABASE prüft CDMS den Namen noch einmal: nur Kleinbuchstaben, Ziffern und Bindestriche.

Das Schema migrieren

Migrieren heißt: die Tabellen einer Datenbank an den Stand der Modelle anpassen, etwa eine neue Spalte anlegen. Jede Datenbank wird einzeln migriert, und zwar dann, wenn CDMS ihre EntityManagerFactory baut. Das ist nach jedem Start beim ersten Zugriff auf den Mandanten der Fall.

Zwei Arten der Migration
HIBERNATE
Standard
  • Hibernate vergleicht Modelle und Tabellen und ergänzt, was fehlt
  • ergänzt Tabellen und Spalten, löscht und benennt nichts um
  • keine Versionen, kein Protokoll in der Datenbank
  • CODAMAI_PERSISTENCE_DATABASE_AUTO_UPDATE=false schaltet das Ergänzen ab; dann prüft Hibernate nur
FLYWAY
versionierte Skripte
  • SQL-Skripte mit Versionsnummer, in der Anwendung mitgeliefert
  • eigene Ordner für System-Datenbank und Mandanten-Datenbanken
  • jede Datenbank führt ihr eigenes Protokoll, bekommt also nur die fehlenden Skripte
  • Hibernate prüft danach nur noch, ob Tabellen und Modelle passen

Welche Art gilt, steht in CDMS_DATABASE_MIGRATION_MODE (HIBERNATE oder FLYWAY). Die Skripte liegen standardmäßig unter db/migration/system und db/migration/tenant.

System-Datenbank und Mandanten-Datenbanken kennen verschiedene Modelle: die System-Datenbank nur System-Modelle, eine Mandanten-Datenbank nur Mandanten- und Benutzer-Modelle. Nur die Tabelle der Revisionen, die die Historie braucht, gibt es in jeder Datenbank.

Verbindungspools

Jedes Ziel hat seinen eigenen Pool. Bei hundert Mandanten sind das hundert Pools. Damit sie zusammen den Datenbankserver nicht überlasten, halten sie in MULTI im Leerlauf keine Verbindungen offen.

EinstellungStandardBedeutung
CODAMAI_PERSISTENCE_DATABASE_POOL_SIZE20höchstens so viele Verbindungen je Pool
CODAMAI_PERSISTENCE_DATABASE_POOL_MIN_IDLEabgeleitetVerbindungen, die im Leerlauf offen bleiben: in MULTI 0, in SINGLE so viele wie die Pool-Größe
CODAMAI_PERSISTENCE_DATABASE_POOL_IDLE_TIMEOUT_SECONDS600nach so vielen Sekunden ohne Nutzung wird eine überzählige Verbindung geschlossen

Eine Anfrage leiht sich in der Regel je berührter Datenbank eine Verbindung und gibt sie am Ende der Anfrage zurück.

Ungenutzte Mandanten räumen

CDMS hält nicht für jeden Mandanten dauerhaft Factory und Pool bereit. Es räumt sie weg, wenn sie länger nicht gebraucht wurden:

EinstellungStandardBedeutung
CODAMAI_PERSISTENCE_DATABASE_FACTORY_CACHE_SIZE100höchstens so viele Mandanten gleichzeitig bereit; darüber hinaus wird der am längsten ungenutzte geräumt
CODAMAI_PERSISTENCE_DATABASE_FACTORY_CACHE_IDLE_SECONDS1800nach so vielen Sekunden ohne Zugriff wird ein Mandant geräumt; 0 schaltet das ab

Geräumt heißt: Neue Anfragen bauen Factory und Pool neu auf, samt Migrationsprüfung. Laufende Anfragen arbeiten ungestört zu Ende. Geschlossen wird erst, wenn die letzte von ihnen fertig ist. Die System-Datenbank und die Datenbank von SINGLE werden nie geräumt.

Fallen

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • commons-persistence – DataSourceManager (decideTenantDatabaseAction, databaseExist, createDatabase, resolveMinimumIdle, HikariCP)
  • commons-persistence – TenantEntityManagerFactory (obtain, buildFactory, sweepIdle, enforceCacheSize, evict, PINNED_TARGETS, invalidateTenant)
  • commons-persistence – provisioning/TenantProvisioningPort, DatabaseTenantProvisioningAdapter, NoOpTenantProvisioningAdapter, TenantProvisioningConfiguration, MySqlDatabaseCreator
  • commons-persistence – migration/SchemaMigrationConfiguration, FlywaySchemaMigrator, NoOpSchemaMigrator; config/PersistenceProperties
  • CIAS/cias-tenancy – TenantService.rollOut (provision beim Anlegen); CIAS/cias-kernel – TenantKey
  • CDMS/cdms-persistence-database – EntityClassFilterService (Typmengen je Ziel)
Suchen