Zurück zur Startseite

OLTP-Kern: API und adaptives Tuning in DBMS

Das neue OLTP DBMS verwendet Seitengröße pro Tablespace, strenge API-Verträge zwischen Schichten und Resource Broker für adaptives Tuning. Diagnostik via eBPF/USDT. Die Architektur eliminiert manuelles Tuning und Leistungsabfall.

Aufbau des OLTP-Kerns: von Seitengröße zu eBPF
Advertisement 728x90

Aufbau eines OLTP-Kerns: API-Verträge, Seitengröße und adaptive Abstimmung

Entwickler einer neuen OLTP-Datenbank haben eine strikte Architektur mit isolierten Schichten mittels Trait-Interfaces in Rust umgesetzt. Jede Schicht verfügt über klare API-Verträge, die Seitengröße ist pro Tablespace konfigurierbar, und die Konfiguration wird von einem Resource Broker ohne manuelle Abstimmung verwaltet. Diagnosen erfolgen über USDT und eBPF.

Seitengröße und Tablespace-Einstellungen

Daten-Seitengrößen reichen von 4-8 KB für reines OLTP bis 16-32 KB für HTAP auf NVMe. Jeder Tablespace ist eine separate Datei mit fester Seitengröße nach der Erstellung. Standard ist 16 KB. Die PageId ist zusammengesetzt: [tablespace_id:16][page_index:48]. Der BufferPool leitet Anfragen an Sub-Caches nach Größe weiter.

Der Superblock am Dateianfang speichert Tablespace-Metadaten unabhängig von der Seitengröße. Beim Mount prüft er die Konfiguration; Abweichungen verhindern den Start ohne Abbau der Funktionalität.

Google AdInline article slot

Architekturschichten und API-Verträge

Der Kern ist in vier Schichten unterteilt:

  • Adapter-Schicht (async tokio): Beendet TLS, parst Wire-Protokoll.
#[async_trait]
pub trait NetworkAdapter {
    async fn handle_connection(&self, stream: Box<dyn ConnectionStream>) -> Result<(), NetworkError>;
}
  • CompatLayer: Parst SQL zu AST, emuliert pg_catalog, übersetzt zu LogicalPlan, lehnt nicht unterstützte Features ab (Fehler 0A000).
pub trait CompatLayer {
    fn translate_query(&self, ast: SqlAst) -> Result<LogicalPlan, CompatError>;
}
  • Core Engine (sync): Optimizer, Executor, Transaktionsmanager. Läuft in einem spawn_blocking-Pool.
pub trait ExecutionEngine {
    fn execute_plan(&self, plan: LogicalPlan, session: &Session) -> Result<ResultSet, ExecutionError>;
}
  • StorageManager: Fassade über PageProvider und TransactionLogSink. Kern fordert Seiten und UNDO-Einträge an.
pub trait StorageManager {
    fn pin_page(&self, page_id: PageId, mode: LockMode) -> Result<PageGuard, StorageError>;
    fn append_undo(&self, txn_id: TxnId, record: UndoRecord) -> Result<UndoPtr, StorageError>;
}

Schichtgrenzen verhindern Detail-Lecks: Lock-Metriken schließen async-Wartezeiten aus.

Adaptive Abstimmung und Resource Broker

Rund 60 Parameter sind in Budgets, Schranken und Overrides unterteilt. Operatoren legen hochstufige Limits fest:

Google AdInline article slot
[resources]
memory_budget = "16GB"
cpu_budget    = "auto"
io_iops       = 5000

Advisors (MemoryAdvisor, IoAdvisor, CpuAdvisor) verteilen Ressourcen sekündlich neu:

  • CpuAdvisor: DOP und Thread-Pool vs. Drosselung.
  • MemoryAdvisor: BufferPool vs. work_mem unter Last.
  • IoAdvisor: Transaktionspriorität, Burst-Erkennung in der Cloud.

Schutzmechanismen

  • Hysteresis: 5s-Fenster, 5%-Schritte zur Vermeidung von Oszillationen.
  • Harte Untergrenzen: Mind. 128 MB für BufferPool/UNDO.
  • Sanfter Übergang: Neue Limits nur für neue Allokationen.
  • Experten-Overrides überschreiben Autotuning.

Hintergrund-Purge des UNDO-Logs statt VACUUM. Laufzeitänderungen ohne Neustart.

Diagnosen: USDT-Probes und eBPF

Diagnosemechanismen sind fest in den Binärcode integriert. USDT-Probes für Laufzeitanalysen, eBPF für Tracing ohne Overhead.

Google AdInline article slot

Wichtige Erkenntnisse:

  • Seitengröße pro Tablespace mit Startprüfungen.
  • Strenge Trait-Verträge zwischen Schichten verhindern Lecks.
  • Resource Broker: Budgets → Autotuning mit Schranken.
  • Diagnosen via eBPF/USDT im Kern.
  • Manuelle Abstimmung durch adaptive Mechanismen ersetzen.

— Editorial Team

Advertisement 728x90

Weiterlesen