[shutterstock:313779428, Sashkin]

[shutterstock:313779428, Sashkin]

Speicherstrategien & -management

Wenn die Daten einer Hana-Anwendung nicht mehr von einem einzelnen Serverknoten verarbeitet werden können (Scale-up), dann müssen die Daten auf mehrere Knoten verteilt werden (Scale-out). Da Numa den Zugriff auf den lokalen Hauptspeicher betrifft, geht dieser Artikel nicht genauer auf Aspekte von verteilten Systemen ein.

Dennoch ähneln sich die Techniken zur Verbesserung der Performance in Numa-Systemen und in verteilten Landschaften.

Da SAP-Anwendungen oft mehrere Hundert Gigabyte oder auch Terabyte an Daten verwalten, ist ein effizienter Zugriff auf den Hauptspeicher von wesentlicher Bedeutung.  Auf diesen Aspekt konzentriert sich der Artikel:

SAP hat auf der Sapphire 2012 in Orlando ein System präsentiert, das analytische Anfragen auf einer verteilten Hana-DB mit 100 Knoten mit insgesamt 100 TB aggregiertem Hauptspeicher verarbeitet.

Typische verteilte Hana-Landschaften verwenden eher fünf bis zehn Serverknoten. Es ist jedoch klar, dass in einer verteilten Serverlandschaft der Schwerpunkt eher auf einer effektiven Verteilung der Daten und Anfragen sowie einer effizienten Netzwerkkommunikation beruht als auf einem effizienten Zugriff auf den Hauptspeicher.

Was ist Numa?

Moderne Serversysteme haben auf ihrer Platine mehrere Prozessoren (oder CPUs) – typisch sind ein bis vier CPUs in Desktop-Systemen von Intel, während hingegen in Intel-Servern zwei bis acht CPUs anzutreffen sind. Prozessoren sind über einen Socket mit der Platine verbunden.

In jeder dieser CPUs stecken normalerweise mehrere Cores, in denen die Berechnungen ausgeführt werden. Moderne Intel CPUs enthalten zwei bis zehn Cores. Insgesamt stehen damit großen Servern bis zu 80 Cores für die Datenverarbeitung zur Verfügung.

Da unter anderem aus thermischen Gründen die Taktfrequenz in den Cores nicht mehr weiter erhöht werden kann, wird in den kommenden Jahren die Anzahl der Cores in Servern noch weiter zunehmen. Die CPUs und der Hauptspeicher sind über ein Bussystem miteinander verbunden.

Wenn die Berechnungen für eine Anfrage über viele Cores verteilt werden kann, stellt sich die Frage, wie die Daten zu den Cores transportiert werden. Grundsätzlich gibt es hier auf der Ebene der Prozessorarchitektur zwei Alternativen (Hennessy & Patterson, 2012):

  1. Symmetric Multiprocessing (SMP):
    In dieser Architektur ist die Zugriffszeit auf eine Speicheradresse für alle Adressen und für alle Cores gleich. Diese Architektur ist in Abbildung 2 dargestellt. Jedem Prozessor sind Caches lokal zugeordnet. Der Zugriff auf den Hauptspeicher erfolgt über einen Bus, den sich alle Prozessoren teilen. In dieser Architektur kann der Speicherbus zum Flaschenhals werden, weil Leseoperationen, die nicht vom lokalen Cache bedient werden können, und alle Schreiboperationen auf den gemeinsamen Speicherbus zugreifen müssen.
  2. Non-Uniform Memory Access:
    In dieser Architektur (Abbildung 3) werden Prozessoren sowohl Caches als auch Speicher lokal zugewiesen. Für einen Prozessor ist der Zugriff auf den lokalen Speicher schneller als der Zugriff auf Speicher eines anderen Prozessors, weil entfernte Zugriffe über einen Speicherbus verarbeitet werden müssen. Für Anwendungsprogramme ist die Zuordnung von physischem Speicher zu einzelnen Prozessoren nicht direkt erkennbar – sie arbeiten wie in einem SMP mit einem homogenen Adressraum.

Da in modernen Intel-Systemen in einem Prozessor mehrere Cores enthalten sind, ergibt sich eine Numa-Architektur auf der Ebene der Prozessoren, aber ein SMP-System auf der Ebene jedes Prozessors.

Letzteres wird auch als Chip-Multi-Processor bezeichnet (CMP). Beispiele für SMP-Systeme sind Intel Pentium D, Intel Itanium, IBM Power, Sun UltraSparc T2 oder SGI MIPS, während Beispiele für Numa-Architekturen Intel Nehalem CPUs oder AMD Opteron CPUs (und deren Nachfolger) sind.

Ist Numa relevant für Hana?

Die SAPHana-DB wurde in Zusammenarbeit mit Intel für die Ausführung auf aktuellen Intel-Xeon-Prozessoren optimiert. Beispielsweise nutzt die Hana-DB die SSE-Erweiterungen von Intel-Prozessoren, um in einer Maschineninstruktion mehrere Elemente parallel zu verarbeiten.

Da diese Intel-Prozessoren auf einer Numa-Architektur basieren, muss auch der Code der Hana-DB für diese Architektur optimiert werden. Im Folgenden wird auf einige Szenarien eingegangen, wo Numa-Effekte in der Hana-DB relevant sind und wie die Hana-DB damit umgehen kann.

Wenn eine Anfrage die Hana-DB erreicht, wird diese Anfrage zunächst einem Thread zugewiesen. Generell erlauben Threads eine leichtgewichtige nebenläufige Verarbeitung mehrerer Anfragen (im Vergleich zu Prozessen im Betriebssystem).

Aktive Threads werden zu einem Zeitpunkt auf genau einem Core ausgeführt.  Während der Verarbeitung einer Anfrage muss die Datenbank in den meisten Fällen Speicher allokieren, zum Beispiel um das Ergebnis der Anfrage für die Datenbankanwendung aufzusammeln. Der Speicher sollte dann in dem Speicherbereich allokiert werden, der dem Prozessor und Core zugewiesen wurde, damit Speicherzugriffe nicht durch Zugriffe auf entfernten Speicher verzögert werden.

Moderne Betriebssysteme berücksichtigen bereits Numa-Architekturen: Sowohl Microsoft Windows 7 bzw. Windows Server 2008R2 als auch Linux (ab Kernel 2.5) versuchen, den Speicher in dem Bereich zu allokieren, der dem Prozessor des Threads oder Betriebssystemprozess zugeordnet ist. Damit profitieren Anwendungen automatisch von Optimierungen im Betriebssystem.

Hier ist zu beachten, dass Virtualisierungslösungen wie VMware ESX von der physischen Hardware abstrahieren. Da die Software mit logischen CPUs und einer Virtualisierungsschicht für den Speicher arbeitet, können Optimierungen für eine Numa-Architektur auf einem virtualisierten System sogar zu negativen Effekten führen.

Das automatische Speichermanagement des Betriebssystems kann zu unerwünschten Effekten führen, wenn eine Anwendung Speicher selbst verwaltet, um teure Systemaufrufe beim Allokieren und Freigeben von Speicher zu vermeiden. Dann kann Speicher beim Wiederverwenden des Speichers im falschen Bereich vorliegen. Quasi jede Datenbank implementiert ein eigenes Speichermanagement, das auf der Anwendungsebene arbeitet.

Ein weiterer Effekt besteht darin, dass ein Thread Speicher (lokal) allokiert, aber viele andere Threads mit diesem Speicher arbeiten wollen.

Als Beispiel sei der Speicher einer Spalte genannt: Dieser Speicher wird einmal beim Laden der Spalte in den Hauptspeicher allokiert, aber viele Anfragen lesen die Daten der Spalte.

In beiden genannten Szenarien, Speichermanagement auf Anwendungsebene und Speicherzugriff durch viele Threads, kann ein effektives Scheduling der Threads helfen. Auch hier implementieren moderne Betriebssysteme Strategien, Threads dort auszuführen, wo die verwendeten Daten allokiert sind.

Das kann so weit führen, dass ein Thread von einem Core auf einen anderen verschoben wird, damit Speicherzugriffe von lokalem Speicher bearbeitet werden können. Das Betriebssystem stößt jedoch an Grenzen, wo beispielsweise Wissen des Datenbanksystems zu besseren Ergebnissen Entscheidungen führen kann.

Numa-Unterstützung in Hana

Im vorherigen Abschnitt wurden Strategien auf Numa-Architekturen besprochen, die jeder Anwendung auf modernen Servern und modernen Betriebssystemen zur Verfügung stehen.

Diese Techniken allein führen jedoch zu suboptimalen Entscheidungen, weil die speziellen Eigenschaften eines Datenbanksystems nicht berücksichtigt werden können. Auf Datenbank-spezifische Optimierungsmöglichkeiten in der Hana-DB geht dieser Abschnitt ein.

Speichermanagement

Wie oben angedeutet, implementiert die Hana-DB aus Effizienzgründen ein Speichermanagement, das auf der Speicherverwaltung des Betriebssystems aufbaut. Dabei wird Speicher normalerweise nicht an das Betriebssystem zurückgegeben, wenn er im Datenbank-Code freigegeben wird.

Gleichzeitig wird bereits allokierter Speicher wiederverwendet. Dadurch soll zum einen die Fragmentierung des Hauptspeichers, aber auch die Anzahl der System-Aufrufe an das Betriebssystem reduziert werden. An dieser Stelle eröffnen sich Möglichkeiten, die spezifischen Eigenschaften einer Numa-Architektur auszunutzen:

1. Wenn ein Thread Speicher anfordert, so wird dem Thread lokaler Speicher des Prozessors bereitgestellt, damit Zugriffe auf diesen Speicher durch den lokalen Speicher-Controller verarbeitet werden und die Speicherbusse zwischen den Prozessoren entlastet werden. Diese Strategie erscheint besonders in Szenarien sinnvoll, wo der Speicher von Threads auf demselben Prozessor verwendet wird.

2. In einigen Fällen erscheint es hingegen sinnvoller, den angeforderten Speicher auf mehrere Prozessoren zu verteilen. In aktuellen Systemen scheinen in bestimmten Szenarien die Speicher-Controller einen Flaschenhals darzustellen. In diesen Fällen ist es sinnvoller, sowohl den Speicher also auch die Threads, die den Speicher verwenden, auf verschiedene Prozessoren zu verteilen. Auf diese Weise kann, zum Beispiel beim Zugriff auf große und häufig verwendete Spalten, der Flaschenhals vermieden werden.

Job Scheduling

Ein modernes Betriebssystem trifft in vielen Fällen eine gute Entscheidung, welche Threads auf welchem Core ausgeführt werden sollen.

Bei der Entscheidung wird berücksichtigt, ob es auf einem Prozessor noch Cores gibt, die aktuell keine Berechnungen durchführen, in welchem Aktivitätszustand einzelne Cores und Prozessoren sind (um Energie zu sparen, lohnt es sich, Arbeit auf einzelne Prozessoren zu bündeln und andere Prozessoren zu deaktivieren), ob einzelne Prozessoren aktuell „übertaktet“ laufen (TurboBoost bei Intel) sowie auf welche Daten ein Thread zugreift.

Neben dieser automatischen Entscheidung des Betriebssystems kann ein Anwendungsentwickler die Zuordnung von Threads zu Prozessoren oder Cores beeinflussen.

Im Grunde sind die damit verbundenen Optimierungsmöglichkeiten beim Scheduling der Threads im System abhängig vom Speichermanagement zu sehen:

  1. Wenn Daten, die ein Thread benutzt, lokal einem Prozessor zugeordnet sind, dann sollte der Thread auch auf diesem Prozessor abgearbeitet werden.  Etwas überraschend ist es manchmal lohnend, mehr Threads auf einem Prozessor ausführen zu lassen, als der Prozessor verarbeiten kann (Anzahl Cores, mit Hyperthreading theoretisch zweimal Anzahl der Cores).

    Das ist insbesondere der Fall, wenn diese Threads auf gemeinsamen Speicher zugreifen und dieser Speicher dann bereits in den Caches verfügbar ist.

  2. Manche komplexe Datenbankoperationen lesen und schreiben große Datenmengen und lasten damit den Speicher-Controller eines Prozessors aus.

    Wenn die Daten für diese Operationen bereits auf den lokalen Speicher mehrerer Prozessoren verteilt sind, dann sollten die Threads für den Zugriff auf die Daten auf mehrere Prozessoren verteilt sein. Dadurch werden einzelne Speicher-Controller entlastet, und die Arbeitslast wird auf mehrere Speicherverbindungen und Speicher-Controller verteilt.

  3. In einigen Fällen sollten Datenbank-Operationen wie Join-Operationen mit einem besonderen Augenmerk auf die Numa-Architektur implementiert werden. Erste „Richtlinien“ für derartige Implementierungen werden in der Forschungsliteratur diskutiert (Albutiu, Kemper & Neumann, 2012).

Zukunft von Numa

Nicht nur Datenbank-Software wurde mehrere Jahrzehnte unter der Prämisse erstellt, dass die Verarbeitungsgeschwindigkeit mit der nächsten Prozessor-Generation zunimmt, unter anderem deshalb, weil sich die Taktfrequenz erhöht. Aus technischen Gründen gilt dieser Automatismus seit Beginn des Jahrtausends nicht mehr.

Anbieter wie Intel oder AMD propagieren Systeme, in denen die Arbeit auf mehrere Prozessoren mit jeweils mehreren Cores verteilt wird. Wie in dem Artikel diskutiert, scheint sich eine Architektur durchzusetzen, in der der Speicherzugriff unterschiedlich aufwändig ist – abhängig davon, wo der Speicher physisch allokiert wurde (mit Numa bezeichnet).

Anwendungssoftware muss daher überarbeitet werden, damit sie die Parallelität ausnutzen kann, die mit der Verfügbarkeit von Mehrkern-Architekturen einherging. Damit verbunden, muss die Software die Eigenheiten der Numa-Architektur berücksichtigen und die Allokation von Speicher und den Zugriff darauf optimieren.

Während moderne Betriebssysteme einige Optimierungen in dem Bereich bereitstellen, müssen Performance-kritische Anwendungen wie die Hana-DB deutlich darüber hinausgehende Verbesserungen realisieren.

In der Hana-Datenbank ist bereits eine Reihe dieser Verbesserungen integriert. Dennoch steht die Implementierung von Datenbanken auf Numa-Architekturen erst am Anfang, und weitere Verbesserungen sind zu erwarten.

Das könnte Sie auch interessieren

0 Kommentare

Dein Kommentar

Möchten Sie uns Ihre Meinung zum Thema sagen?
Hinterlassen Sie uns einen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.