2 Punkte von GN⁺ 2024-03-11 | 1 Kommentare | Auf WhatsApp teilen
  • Amazon S3 ist eine frühe Cloud-Technologie aus dem Jahr 2006, stark bei der Dateispeicherung, aber kein Dateisystem, das die Unix-Datei-API unverändert ersetzt
  • Die Unix-Datei-API ist eher ein tiefes Modul mit einer schmalen Schnittstelle wie open, read, write, seek, close, hinter der sich Buffering, Page Cache, Berechtigungen und IO-Scheduling verbergen
  • S3 wirkt mit GetObject und PutObject einfach, erlaubt über Range aber nur partielles Lesen und unterstützt kein partielles Überschreiben
  • Datenbanken wie Postgres, SQLite, MySQL, MongoDB und Elasticsearch sind auf seitenweises Überschreiben angewiesen, weshalb es abseits sehr kleiner Datensätze kaum passt, SQLite- oder DuckDB-Dateien unverändert auf S3 zu legen
  • Hohe Lese- und Schreibbandbreite sowie geringer Betriebsaufwand sind Stärken von S3, doch Einschränkungen wie fehlendes rename/move, langsame Listenabfragen, eine reine XML-API und das Fehlen einer lokalen Testumgebung müssen mitbedacht werden

S3 speichert Dateien, ist aber kein Dateisystem

  • S3 ist eine frühe Cloud-Technologie aus dem Jahr 2006 und wurde entsprechend der damaligen Sprachregelung als „Object Store“ bezeichnet
  • In der Praxis wird es weithin als Dateispeicher genutzt, aber es als „Amazon Cloud Filesystem“ zu verstehen, trifft nur teilweise zu
  • Es eignet sich gut zum Speichern von Dateien, kann aber das Verhalten und die Erwartungen an klassische Dateisysteme nicht eins zu eins ersetzen

Unix-Datei-API und tiefe Module

  • Der Kern der Unix-Datei-API lässt sich auf die folgenden fünf Aufrufe zusammenfassen
    • open(filepath): öffnet eine Datei
    • file.read(size=100): liest an der aktuellen Position und verschiebt die Position nach vorn
    • file.write("hello, world"): schreibt an der aktuellen Position und verschiebt die Position nach vorn
    • file.seek(94): bewegt die Position zu einem bestimmten Byte
    • file.close(): schließt die Datei
  • Diese Aufrufe gehören zum Kern der gesamten Systemaufrufe und kommen den minimal nötigen Funktionen zum Lesen und Schreiben von Dateien nahe
  • Weil hinter der schmalen Schnittstelle viel Verarbeitung stattfindet, kann man die Unix-Datei-API als tiefes Modul (deep module) betrachten
    • Buffering und Page Cache
    • Umgang mit Fragmentierung
    • Rechtemanagement
    • IO-Scheduling
    • Auch von Funktionen wie Wear Levelling auf SD-Karten profitieren Nutzer, ohne sich direkt darum kümmern zu müssen

Flache Module, YAML und ORM

  • Flache Module haben im Verhältnis zu dem, was sie leisten, eine relativ große API-Oberfläche
  • Ein heutiger Hinweis auf flache Module ist oft, wenn die Schnittstelle YAML ist
    • YAML wirkt wie eine Markup-Sprache, wird aber in der Praxis als wiederverwendbare Syntax verwendet, auf die sich fast beliebige Semantik legen lässt
    • Im DevOps-Bereich funktioniert YAML oft wie eine „Programmiersprache“
    • Wenn eine YAML-Minisprachleife Wiederholungsstrukturen bietet, ist Turing-Vollständigkeit möglich
  • Flache Module sind nicht immer schlecht
    • SQL-ORMs sind ihrem Wesen nach lecke Abstraktionen und ohne Verständnis von SQL schwer sinnvoll zu nutzen
    • In manchen Fällen kann ein flaches Modul die bestmögliche Form sein
  • Unter gleichen Bedingungen ist ein tieferes Modul besser

Die S3-API ist einfach, aber nicht die Datei-API

  • Die Unix-Datei-API hat sich Anfang der 1970er etabliert; aus Kompatibilitätsgründen blieb die Schnittstelle erhalten, während sich die interne Implementierung mehrfach änderte
  • Amazon S3 implementiert die Unix-Dateisystem-API nicht neu
  • Die Grundoperationen von S3 entsprechen der Unix-Datei-API nur teilweise
    • GetObject(Bucket, Key, Range=None): liest das gesamte Objekt oder einen Teil davon
    • PutObject(Bucket, Key): schreibt das gesamte Objekt
  • Es gibt zwar das zusätzliche Konzept eines Buckets, aber gemessen am Verhältnis von Funktionalität zu Schnittstelle ist S3 sogar einfacher als die Unix-Datei-API
  • Der entscheidende Unterschied ist das Fehlen von partiellem Überschreiben
    • Über das Range-Argument von GetObject lässt sich ein Teil eines Objekts lesen
    • Es ist jedoch nicht möglich, nur einen Teil eines Objekts zu überschreiben
    • Überschreiben geht nur auf Ebene der gesamten Datei
  • Deshalb passt S3 nur für einen Teil der bisherigen Datei-Anwendungsfälle wirklich gut

Datenbanken lassen sich nicht einfach unverändert auf S3 portieren

  • Viele Datenbanken speichern ihre Daten in Dateien auf einem Dateisystem
    • Postgres hält pro Tabelle 2–3 Dateien sowie diverse Verwaltungsdateien vor
    • SQLite ist dafür bekannt, alle Daten in einer einzelnen Datei zu speichern
    • MySQL, MongoDB und Elasticsearch speichern Daten ebenfalls in Dateien
  • Das Problem ist, dass Datenbanken meist auf partiellem Überschreiben auf Seitenebene basieren
    • Daten werden typischerweise in Seiten von 4 KB oder 8 KB gespeichert
    • In einer Heap-Datei können Tausende solcher Seiten liegen
    • Zur Ablage benötigter Daten werden Seiten teilweise überschrieben
  • Legt man eine SQLite-Datenbank auf S3, müsste bei jedem Schreibvorgang die gesamte Datenbankdatei neu geschrieben werden
  • S3 kann große Schreibvorgänge schnell verarbeiten, aber außer bei den allerkleinsten Datensätzen ist eine Strategie, jedes Mal die komplette Datei zu überschreiben, kaum tragfähig
  • Wenn die Datenbankdatei jedes Mal neu geschrieben wird, lässt sich auch die vom Datenbankentwickler aufgebaute Transaktionsintegrität nur schwer nutzen
  • Auf S3 gewinnt der letzte Schreibvorgang

Was S3 gut kann und was nicht

  • Eine Stärke von S3 ist die sehr hohe Bandbreite beim Lesen und Schreiben
    • Es ist nicht schwer, Berichte über mehr als 10 GB/s beim Lesen oder Schreiben auf S3 im Internet zu finden
    • Es gab auch Erfahrungen, bei denen Schreibvorgänge auf S3 das Büronetzwerk eines Finanzkunden vollständig ausgelastet haben
  • Neben dem Fehlen von partiellem Überschreiben gibt es weitere Einschränkungen im Vergleich zu einem Dateisystem
  • S3 kennt keine rename- oder move-Operation
    • Umbenennen erfolgt über CopyObject und anschließend DeleteObject
    • CopyObject benötigt lineare Zeit proportional zur Dateigröße
    • Hat man viele Dateien an die falsche Stelle geschrieben, ist das Zurückrollen sehr langsam
  • Das Auflisten von Dateien ist langsam
    • Die Lese- und Schreibbandbreite ist sehr hoch, aber das Auflisten gespeicherter Einträge ist deutlich langsamer
    • Es kann sogar langsamer sein als ein langsames lokales Dateisystem
  • Dafür ist der Betriebsaufwand geringer als bei einem Dateisystem
    • Man gibt nur Bucket und Key-Namen an, den Rest übernimmt die Cloud
    • Wiederkehrende Aufgaben wie Backups, Offsite-Replikation und Provisionierung werden reduziert
    • Provisionierung betrifft nicht nur Kapazität, sondern auch IO-Operationen

Bei Schnittstellen zwischen Organisationen sind tiefe Module noch wichtiger

  • Dass S3 die erste populäre Cloud-API war, hängt auch mit den Vorteilen tiefer APIs zusammen
  • Tiefe APIs helfen dabei, Komplexität zwischen Modulen innerhalb eines Systems zu verbergen, und sind in kostspieligen Beziehungen wie der Interaktion zwischen zwei Unternehmen noch wichtiger
  • Die Verbindung von Computersystemen zwischen Unternehmen wurde traditionell als Integration bezeichnet und fast als Synonym für Schmerz behandelt
  • Große Enterprise-Software wie SAP ist kein tiefes Modul
    • Fast die gesamte Organisation muss SAP verstehen
    • Es braucht laufende Abstimmung mit bestehenden Arbeitsweisen
    • SAP-Integrationsprojekte sind teuer, riesig und scheitern immer wieder
  • Die interne Komplexität von S3 ist nicht unbedingt geringer als die einer SAP-Installation
    • Amazon nannte S3 zwar „Simple Storage Service“, aber die tatsächliche Komplexität von S3 ist hoch
    • Dazu gehören Queueing-Theorie, IO-Contention, Sharding und viele Probleme, die Dateisysteme ebenfalls lösen müssen
  • Das „simple“ bei S3 steht weniger für echte Einfachheit als für eine tiefe Schnittstelle

Passende Ausnahmen für S3 und verbleibende Grenzen

  • Damit wird nicht ausgeschlossen, dass S3 für bestimmte Anwendungsfälle zu teuer sein kann
  • Die Konzepte tiefer und flacher Module stammen aus John Ousterhouts A Philosophy of Software Design
  • Es gibt auch Datenbanken, die von Anfang an dafür entworfen wurden, die S3-API als Storage-Layer zu nutzen
    • Snowflake ist ein solches Beispiel
    • Das ist aber keine transparente Portierung, sondern erfordert frühe Architekturentscheidungen
    • Snowflake hatte diese Entscheidung spätestens bis 2016 sehr früh getroffen
  • Nicht nur Datenbanken haben Schwierigkeiten auf S3
    • Viele Dateiformate setzen günstige seek-Operationen voraus
    • Zip-Dateien sind ein typisches Beispiel dafür, dass sie auf Festplatte besser performen als auf S3

Was an S3 enttäuscht

  • Die S3-API ist nur XML
    • JSON existierte zwar schon 2006, aber damals dominierte XML
    • Schade ist, dass Amazon beim Wechsel von SOAP zu REST keine JSON-Version herausgebracht hat
  • Amazon pflegt auch das XSD-Schema nicht mehr
    • Einer der Hauptvorteile einer XML-API ist gerade das Schema, doch heute ist das Standarddokument die Website
  • Amazon stellt keine lokale Testumgebung bereit
    • In Python wird für ernsthafte Tests oft die Bibliothek moto verwendet
    • Obwohl moto ein Testwerkzeug für einen kommerziellen Dienst ist, wird es von Freiwilligen gepflegt
  • Amazon S3 unterstützt Checksummen, aber sie sind standardmäßig nicht aktiviert
    • Amazon macht verschiedene Aussagen zur Haltbarkeit
    • Von realen Problemen habe ich zwar nichts gehört, aber auch keine Fälle gesehen, in denen diese Aussagen getestet wurden
  • Früher hatte S3 die Falle der Eventual Consistency
    • Wenn man eine Datei las, überschrieb und erneut las, konnte man noch den alten Inhalt sehen
    • Das trat gelegentlich für kurze Zeit auf und sorgte für Verwirrung
    • Andere S3-Implementierungen haben dieses Verhalten nicht nachgebildet, und Amazon hat es vor einigen Jahren mit strong read-after-write consistency behoben

1 Kommentare

 
GN⁺ 2024-03-11
Meinungen auf Hacker News
  • Die Haltbarkeit von S3 mag übertrieben wirken, ist aber glaubwürdig und lässt sich schwer mit traditionellen Dateisystemen vergleichen
    Der Unterschied betrifft nicht nur Software, sondern auch physische Infrastruktur und Sicherheitskultur; die Isolation der Availability Zones von AWS wirkt besser als bei anderen Clouds
    Während der Arbeit an S3 wurde man oft mit Preisvergleichen zu GCP Blob Storage konfrontiert, aber Google konnte Daten im selben Gebäude oder in einem anderen Raum desselben Gebäudes ablegen, daher war das kein fairer Vergleich zur AWS-artigen Trennung
    Die gesamte Organisation war extrem auf Datenintegrität fixiert, versah alles mit Prüfsummen und bereitete sich auch auf große Ereignisse wie Naturkatastrophen vor
    In der Größenordnung von S3 ließ sich sogar Bit Rot erkennen, etwa zufällige Bitflips, die entstehen, wenn Gammastrahlen auf Festplatten-Platter treffen; zudem wurden Ausfallraten nach Plattenhersteller und Produktionszeitraum gemessen, um die Wahrscheinlichkeit von Datenverlust selbst bei defekten Chargen zu verringern
    Man würde wichtige Daten angeblich nirgendwo anders speichern und hat das S3-Placement-System selbst gebaut

    • Mich würden Erfahrungen bei anderen Storage-Anbietern interessieren
      Diese Beschreibung klingt, als würde man Cinnabon dafür loben, den Teig selbst herzustellen; die genannten Dinge sind das, was Storage-Unternehmen normalerweise tun
      Alles mit Prüfsummen zu versehen ist eine Grundfunktion vieler Dateisysteme, und wenn sogar ein Heimcomputer Bit Rot erkennen und Benachrichtigungen ausgeben kann, dann machen große Storage-Anbieter das selbstverständlich
      Auch das Nachverfolgen von Ausfallraten nach Plattenhersteller ist üblich; Storage-Unternehmen veröffentlichen dazu sogar Berichte, und selbst eine IT-Organisation mit sechs Personen hat das per Spreadsheet verwaltet
      Auch außerhalb von AWS – und schon lange bevor es AWS gab – haben viele kluge Leute im Storage-Bereich gearbeitet
    • Die Isolation der Availability Zones von AWS ist nicht besser als bei allen anderen Anbietern
      Georedundante Konten von rsync.net befinden sich zum Beispiel in unterschiedlichen Bundesstaaten oder Ländern, etwa mit Primärspeicher in Fremont und Sekundärspeicher in Denver
      Dass S3 wegen seiner Größe Bit Rot erkennen könne, stimmt ebenfalls nicht; auch mit ZFS auf einem privaten Server lässt sich Bit Rot im kleinen Maßstab gut erkennen
      [1] he.net-Zentrale
    • Daten mit Prüfsummen zu versehen ist weniger Paranoia, sondern ergibt sich natürlich daraus, dass man wissen muss, welche Blöcke unbrauchbar sind, um den Reed-Solomon-Algorithmus auszuführen
      Wenn es genügend solcher Beschädigungsereignisse gibt, könnte das auch als Signal dienen, einzelne Datenblöcke auf andere Maschinen zu verschieben und das System zu „heilen“
      Insgesamt sind die genannten Dinge in Storage-Systemen ziemlich typisch und keine Besonderheit von S3
    • Dass Google Daten im selben Gebäude speichert, scheint nicht zu stimmen
      Laut der Dokumentation zu Google Cloud Storage werden Daten über mehrere Zonen repliziert, und jede Zone wird auf unterschiedliche Cluster abgebildet
      https://cloud.google.com/compute/docs/regions-zones/zone-vir...
    • Statt „glaubt uns“ würde ich lieber Testergebnissen vertrauen
      Ich frage mich, ob es eine neutrale Drittpartei gibt, die Haltbarkeit, Integrität und Konsistenz von S3 so streng geprüft hat wie Jepsen
      Wenn jemand S3-kompatible Cloud-Storage-Dienste gründlich vergleichen würde, könnten dabei erschreckende große Probleme sichtbar werden; vielleicht gibt es so einen Vergleich auch schon
  • Was an S3 wirklich nützlich ist, ist meiner Ansicht nach eher das Listing als die Lese-/Schreibgeschwindigkeit
    In Buckets ohne Versionierung oder ohne Delete Marker funktioniert das Auflisten eines bestimmten Präfixes praktisch wie in konstanter Zeit, sodass man selbst in einem Bucket mit 100 Milliarden Objekten die 1000 alphabetisch folgenden Keys nach einer beliebigen Zeichenkette anfordern kann
    / als Trennzeichen zu verwenden ist nur der Standard; man kann jedes beliebige Zeichen nutzen, um eine Menge gemeinsamer Präfixe zu erhalten, und Verzeichnisse existieren nicht wirklich, sondern sehen nur so aus, als würden sie bei Bedarf erzeugt
    Dank dieser Eigenschaft kann man Daten ohne Performance-Sorgen auf verschiedene Arten nach den benötigten Identifikatoren aufteilen
    Wenn Listing einfach langsam wäre, dateipräfixbasierte Abfragen nicht möglich wären und es wie bei einem traditionellen Unix-Dateisystem proportional zur Anzahl der Keys langsamer würde, wäre S3 überhaupt nicht nützlich

    • Besonders überzeugend finde ich das nicht
      Die Fähigkeit, Keys vor und nach einem Präfix herauszuziehen, ist eine Grundfunktion von Datenbankindizes, die es seit den 1970er-Jahren gibt, und daher nicht besonders beeindruckend
      Die Anwendungsfälle mögen unterschiedlich sein, aber langsames Bucket-Listing war oft hinderlich; sobald ein Bucket auch nur etwas größer wurde, dauerte das Auflisten der Keys länger als das Lesen
      Meiner Erinnerung nach lag das Listing unter 1 Mbit/s, aber ich habe gerade keinen großen Bucket zum Testen
    • Der Unterschied zwischen einer flachen lexikografischen Key-Hierarchie und einer in Verzeichnissen verschachtelten Dateisystemhierarchie wird an einem Beispiel deutlich
      Wenn es dir1/a/000000 bis dir1/a/999999 sowie dir1/b gibt, muss ls dir1/ in einem echten hierarchischen Dateisystem nur die zwei Einträge "a" und "b" durchlaufen und zurückgeben
      Ein flacher String-Index-Key-Value-Store ohne Trennzeichenbehandlung muss dagegen eine Million Verzeichniseinträge von "a/00000" bis "a/999999" durchlaufen, bevor er "b" erreicht
      Deshalb wird bei einer einfachen flachen Hierarchie das Auflisten eines Verzeichnisinhalts nicht zu O(direkte Kinder) wie in einem echten Dateisystem, sondern zu O(alle rekursiven Kinder) und ist damit viel langsamer
      Wenn man dem Listing-Algorithmus jedoch ein Trennzeichen wie / mitteilt, kann der lexikografische Präfixbaum effizient am nächsten / ganze Teilbäume überspringen
      Auch die Amazon-S3-Dokumentation sagt ausdrücklich, dass das Feld CommonPrefixes Millionen von auf tieferen Ebenen verschachtelten Keys überspringt und zusammenfasst
      https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-...
      Ob die tatsächliche Implementierung wirklich die Traversierung einspart oder nur nach der Traversierung die Ergebnisse reduziert, habe ich nicht getestet, aber ich hoffe, dass sie sie einspart
    • Gute UNIX-Dateisysteme seit XFS von 1993, beeinflusst von HPFS, haben Verzeichnisse in irgendeiner Form als B-Tree implementiert
      Daher werden sie nicht proportional zur Anzahl der Einträge langsamer, und auch dateipräfixbasierte Listings sind sehr schnell
    • 99 % der S3-Nutzung dürfte darin bestehen, Objekte über bereits bekannte Keys abzurufen
      Präfix-Listing als Kernfunktion zu sehen, wirkt seltsam
    • Ich weiß nicht, ob wir hier dieselbe Definition von „konstanter Zeit“ verwenden
      Dass man mit einem Netzwerkaufruf 1000 Keys bekommt, garantiert nichts über die Komplexität im Backend
  • Kürzlich habe ich an einem Skript zur Verwaltung von S3-Assets gearbeitet und war von der Geschwindigkeit der Listenabfrage überrascht.
    Ein Kollege meinte, wir bräuchten einen Cache für die Dateiliste, und schickte mir einen vorbefüllten Cache. Zuerst dachte ich, dass das unmöglich nötig sein könne, aber als ich es selbst prüfte, sah die Sache anders aus.
    Es gibt etwa 100.000 Root-Verzeichnisse für einzelne Assets, jeweils mit 5 bis 6 Verzeichnissen und einigen wenigen Dateien; insgesamt sind es vermutlich unter 1 Million Dateien, mit einer Tiefe von höchstens etwa 3 Ebenen.
    Diese Dateien rekursiv aufzulisten dauerte buchstäblich 15 Minuten.
    Ich habe verschiedene Vorschläge zur Beschleunigung von Stack Overflow und ChatGPT ausprobiert, aber ohne nennenswertes Ergebnis, und verstehe nicht, warum es so langsam ist.
    Ich weiß nicht, warum Amazon das nicht behoben hat; von außen wirkt es so, als müsste man einzelnen Buckets nur ein paar B-Bäume verpassen.
    Wenn es ein schwieriges Problem ist, wäre der Grund dafür interessant, und ich würde ihn gern hören.

    • S3 ist im Kern ein Key-Value-Store.
      Dass man Objekte wie „Verzeichnisse“ betrachten kann, ist nur ein Präfixfilter; es ist kein Dateisystem und kennt auch kein Verzeichniskonzept.
    • Die Formulierung „rekursiv“ und die ausführliche Beschreibung von „Verzeichnissen“ und „Ebenen“ machen mir Sorgen.
      Die schnellste Methode, Objekte in S3 aufzulisten, braucht überhaupt keine Rekursion; man listet einfach alle Objekte unter einem Präfix auf.
      Wenn man mit Pfadtrennern S3-Keys als Ordnerstruktur tarnt und „ordnerweise“ durchläuft, wird es deutlich langsamer.
      Beim Aufruf von ListObjectsV2 sollte man keinen delimiter übergeben; wenn man die Trennzeichen-Funktion nicht nutzt, haben „Verzeichnisse“ und „Ebenen“ keinen Einfluss auf die Performance.
      Um eine gewünschte Gesamtdauer zu erreichen, kann man eine Listenoperation in parallele Listenabfragen über mehrere Präfixe aufteilen.
    • Eine interessante Konsequenz dieses Problems ist, dass das Löschen eines S3-Buckets nicht trivial ist.
      Ein Bucket, der Objekte enthält, kann nicht gelöscht werden, und man kann S3 auch nicht in einem Schritt sagen, es solle alle Objekte löschen.
      Für jedes Objekt muss eine eigene Delete-API-Anfrage gesendet werden; dafür muss man außerdem Anfragen senden, die die Objekte in 1000er-Schritten auflisten, und diese Listenaufrufe brauchen Zeit und kosten Geld.
      Dieser Artikel fasst die Lage gut zusammen: https://cloudcasts.io/article/deleting-an-s3-bucket-costs-mo...
      Die schnellste Methode, einen S3-Bucket rasch loszuwerden, ist am Ende, das AWS-Konto zu löschen, zu dem dieser Bucket gehört.
    • Der Grund könnte viel banaler sein.
      Pro Anfrage kann man 10.000 Objekte auflisten, und um die nächsten 10.000 zu bekommen, braucht man das Ergebnis der vorherigen Anfrage; das Ganze ist also vollständig seriell.
      Um 1 Million Dateien aufzulisten, braucht man 100 aufeinanderfolgende Anfragen; selbst bei nur 50 ms Roundtrip-Zeit sind das allein 5 Sekunden für die Roundtrips, und die Kosten für das Erstellen der Liste selbst in einer flachen Iteration kommen noch hinzu.
      Eine Listenabfrage über 10.000 Einträge kostet ungefähr so viel wie ein Schreibvorgang, was an sich schon eher langsam ist; außerdem könnte jede Listenabfrage ein Snapshot mit starker Konsistenz sein, was zusätzliche Kosten verursacht.
      B-Bäume dürften wenig helfen, außer wenn man tatsächlich Verzeichnisse durchläuft; selbst dann liegt der Engpass wahrscheinlich bei Netzwerkoperationen und der nach außen exponierten API.
      Letztlich ist das Auflisten von Dateien kein besonders wichtiger Use Case; normalerweise überlässt man S3 mit Funktionen wie Object Lifecycle die gewünschte Arbeit und lässt sie in der internen Dateisystemschicht effizient erledigen.
    • Zu glauben, in einem S3-Bucket gebe es Verzeichnisse, ist kein gutes Modell.
      Es sind alles Objekte; die Weboberfläche stellt lediglich durch Schrägstriche getrennte Präfixe hübsch dar.
      Jedes Objekt hat einen Key, und dieser Key kann Schrägstriche enthalten; der Einfachheit halber kann man die einzelnen Abschnitte als Verzeichnisse betrachten.
      Aber sobald man versucht, typische Operationen auf Verzeichnissen auszuführen, zerbricht diese Illusion.
  • Die Leute, die S3 gebaut haben, wussten, dass es kein Dateisystem ist, und ich denke, der Name Objektspeicher sollte genau die im Artikel angesprochenen Unterschiede ausdrücken.
    Wenn es heißt, „Objekte waren beliebt“, meint das Objekte als Softwarekomponenten, die ausführbaren Code und lokalen Zustand bündeln; die frühen Beispiele für S3 bestanden aber nicht darin, „Live-Objekte zu serialisieren und in einem anderen Prozess zu deserialisieren“.
    Die Beispiele waren allesamt Dinge wie statische Assets für Websites, und auch im Datenbankbereich wurde damals das Wort Objekt in Begriffen wie „binary large object“ oder „blob“ verwendet.
    S3 war eher ein Ort, an dem man Dinge speicherte, die schlecht in eine Datenbank passten; die beim ursprünglichen Design vorgesehenen Launch-Use-Cases gingen davon aus, dass der Content-Index irgendwo anders liegt, und genau das erklärt auch, warum Listenabfragen langsam sind.

    • Der Autor scheint nicht zu wissen, dass „Objektspeicher“ ein Begriff für Speichersysteme ist und nichts mit objektorientierter Programmierung zu tun hat.
      https://en.wikipedia.org/wiki/Object_storage
    • Ich mache mir Sorgen, dass der Autor objektorientierte Programmierung und Objektspeicher verwechselt.
      Laut der Erklärung von GCP ist Objektspeicher eine Architektur, bei der unstrukturierte Daten in Objekte aufgeteilt und in einer strukturell flachen Datenumgebung gespeichert werden.
      https://cloud.google.com/learn/what-is-object-storage
      Entscheidend sind also unstrukturierte Daten, eine flache Organisation sowie Lese- und Schreibvorgänge auf Ebene ganzer Einträge.
  • S3 ist weder eine Datei noch erst recht ein Dateisystem
    Was man von der Datei-Abstraktion erwartet, ist Veränderbarkeit: Man sollte Teile einer Datei bearbeiten, sie vergrößern und verkleinern sowie an beliebigen Offsets lesen und schreiben können.
    Hat man eine Datei einmal geöffnet, sollte man nicht wieder zur Wurzel oder zu einem übergeordneten Konzept zurückgehen müssen. S3 bietet jedoch nur unveränderliche Objekte auf einer veränderlichen Liste; will man etwas ändern, muss man es kopieren und erneut hochladen.
    Die ursprüngliche Datei-Abstraktion besteht darin, Sektoren auf einer Festplatte zu finden und sie dem Client wie einen zusammenhängenden Puffer erscheinen zu lassen; S3 löst ein anderes Problem.
    Viele missverstehen die gute UNIX-Idee „Alles ist eine Datei“ so, als müsse alles wie ein zusammenhängender virtueller Puffer aussehen.
    Der eigentliche Kern ist, dass es grundlegende Blattknoten gibt – seien es Dateien oder andere Objekte, die das System einem Prozess zeigen möchte –, dass alles, einschließlich Verzeichnissen, in Verzeichnissen aufgelistet werden kann, und dass es einen rekursiven Baum gibt.
    Was ein Dateisystem ausmacht, ist nicht der Typ eines bestimmten Blattknotens, sondern das Verzeichnis.
    Neue Blatt-Typen wie Sockets oder Framebuffer hinzuzufügen ist nahezu trivial und beschädigt diese Idee nicht; fügt man jedoch andere Arten von Containern wie Listen hinzu, wird die Dateisystemstruktur komplizierter und die konzeptionelle Konsistenz bricht.
    S3 tut all das nicht, aber das ist in Ordnung.
    Man legt dort Dinge ab, die nicht in eine Datenbank passen, und hofft lediglich, dass kein Bit Rot entsteht, während man nicht hinsieht.
    Der Wunsch, S3 wie ein Dateisystem zu machen, entsteht meiner Ansicht nach daraus, dass Kunden missverstehen, worin S3 gut ist, und das Produktmanagement dieses Missverständnis nicht verhindert, sondern akzeptiert hat.

    • Ich stimme zu, dass S3 kein Dateisystem ist.
      Die passendere Analogie ist ein Blockspeichergerät, allerdings eher ein sehr merkwürdiges Blockgerät, bei dem die Blockgröße beliebig ist und Schlüssel vergeben werden können.
      Ein Dateisystem ist eine Abstraktion, die auf einem Blockspeichergerät aufsetzt; ein „S3-Dateisystem“ müsste also ebenfalls eine Abstraktion sein, die S3 als zugrunde liegenden Blockspeicher verwendet.
    • Ich frage mich, wie Read-only-Dateisysteme zu dieser Definition passen.
  • Ein Dateisystem ist eine Abstraktion, die auf einem Blockgerät aufgebaut ist.
    Ein Blockgerät stellt ein riesiges Byte-Array bereit und ermöglicht blockweises Lesen und Schreiben, etwa: „Schreibe diese 300 Bytes an Position 273041“.
    Auch das Blockgerät selbst ist eine Abstraktion über tatsächlicher Hardware; „Schreibe diese 300 Bytes“ führt in Wirklichkeit zu Vorgängen wie „Bewege den Kopf von Platter 2 auf Position 6“.
    S3 ist lediglich eine andere Abstraktion auf rohem Speicher und streng genommen ein flacher Key-Object-Store.
    Wenn man Dateisystemfunktionen braucht, sollte man sie in der App implementieren oder ein Dateisystem verwenden.
    Wenn man nur Anhängen braucht, kann man die Append-Kette in einer Datenbank verfolgen und die Chunks in S3 speichern; passt das nicht, nimmt man etwas anderes.
    Wenn man Kopieren braucht, kann man in der Datenbank eine neue Referenz auf dasselbe Objekt anlegen; passt das nicht, nimmt man etwas anderes.
    S3 passt für viele sehr gut, daher sollte man nicht versuchen, es in etwas anderes zu verwandeln.
    Man sollte auch aufhören, die Bedeutung bereits etablierter Fachbegriffe ändern zu wollen: Ein Dateisystem ist ein in Lehrbüchern beschriebenes Konzept, und S3 hat nie behauptet, ein Dateisystem zu sein.
    Ein wenig Betriebssystemdesign zu lernen hilft wirklich und macht auch Spaß.

  • Eine Diskussion zum Vergleich der APIs von Apache Arrows object_store und Apache OpenDAL gab es unter https://github.com/apache/arrow-rs/issues/3888.
    Apache OpenDAL ist eine Bibliothek, die eine dateisystemähnliche API über mehrere Backends hinweg bereitstellt, darunter S3 und verschiedene Cloud-Speicher.
    Einige Datenbanksysteme wie GreptimeDB und Databend verwenden OpenDAL als eine Art besseres S3-SDK für den Zugriff auf Daten in Cloud-Speichern.
    Als weitere Lösungen, die eine dateisystemähnliche Schnittstelle über S3 verwalten, gibt es auch Alluxio und JuiceFS; anders als Apache OpenDAL erfordern sie jedoch separate Deployments und einen dedizierten internen Metadaten-Service.

    • Ich bin mir nicht sicher, ob Alluxio als lokaler Cache-Layer für TrinoDB durch OpenDAL ersetzt werden kann.
  • Wenn man über S3 spricht, ist auch Backblaze B2 erwähnenswert.
    Es ist dreimal günstiger als S3, was mir sehr gefällt; ich bin nicht mit Backblaze verbunden.

    • Backblaze B2 ist günstig, aber wenn man es in einer Produktionsumgebung nutzt, gibt es Dinge, die man in die Kosten einrechnen sollte.
      Es gibt jede Woche ein zweistündiges Wartungsfenster von 11:30 bis 13:30 Uhr PST; normalerweise gibt es keine Downtime, aber gelegentlich kommt es mitten während der US-Geschäftszeiten zu einem vollständigen Ausfall.
      Wenn die Fehlerrate auf ein unbrauchbares Niveau stieg, musste ich ein Support-Ticket eröffnen; in den letzten Jahren ist das ungefähr einmal pro Jahr passiert.
      Der Support stellt nur unzählige Fragen, als hätte er keine Fehlerlogs oder Sichtbarkeit auf der eigenen Seite, und schaut sich das Problem nicht wirklich an.
      Es gibt auch False Successes, bei denen ein Upload als erfolgreich beantwortet wird, tatsächlich aber mit 0 Bytes im B2-System gespeichert wird; daher muss man Uploads auch bei Erfolgscodes unbedingt verifizieren.
      Bei Schwachstellen mit hohem Schweregrad wie der Log4j2-CVE kann es auch zu langen Ausfällen kommen, etwa 10 Stunden Unterbrechung.
      Der Preis ist hervorragend, aber es ist kein Produkt, das direkt mit ausgereifteren Cloud-Speicherdiensten vergleichbar ist.
    • Bei alternativen Diensten ist immer der zentrale Punkt, dass die Daten nur so sicher sind, wie man dem Unternehmen vertrauen kann.
      Allerdings lässt sich das meiner Meinung nach durch zwei Ebenen externer Backups bis zu einem gewissen Grad abfedern.
    • B2 war gut, aber nicht so gut, dass ich dafür auch noch IPv4-Adresskosten zahlen wollte.
      Es ist absurd, dass ein Dienst sich als Multi-Cloud-Lösung bewirbt, während NAT-Gateways und IPv4-Gebühren praktisch überall anfallen und die Einführung damit faktisch unmöglich machen.
      Bei meinem Nutzungsprofil mit vielen Lese- und wenigen Schreibzugriffen hätte ich trotz B2-Bandbreitengebühren Geld sparen können; aber nicht, wenn ich über ein NAT64-Gateway gehen oder stündliche Gebühren zahlen muss, um auf B2 zuzugreifen.
  • Guter Beitrag; es wäre nützlich gewesen, ihn zu lesen, bevor ich meine Reise begonnen habe, Cloud-Speicher mit rclone mount per FUSE einzubinden.
    Nach mehreren Iterationen hat rclone eine VFS-Schicht bekommen, die Speicher wie S3, Google Cloud Storage, Azure Blob, OpenStack Swift oder Oracle Object Storage auf eine POSIX-ähnliche Dateisystemschicht abbildet; der eigentliche rclone mount-Code ist nur eine dünne Schicht darüber.
    Die VFS-Schicht hat mehrere Kompatibilitätsstufen; bei off wird nur das Verzeichnis-Caching gemacht.
    In diesem Modus kann man, wie im Beitrag beschrieben, dieselbe Datei nicht gleichzeitig lesen und schreiben, nicht in die Mitte einer Datei schreiben, und Dateien können nur sequenziell geschrieben werden.
    Erstaunlicherweise funktioniert selbst mit diesen Einschränkungen ziemlich viel gut.
    Die nächste Stufe, writes, unterstützt die meisten POSIX-Funktionen, die Apps erwarten, etwa gleichzeitiges Lesen und Schreiben derselben Datei oder Schreiben in die Mitte einer Datei; das kostet aber, dass eine lokale Kopie der Datei angelegt und beim Schließen asynchron hochgeladen wird.
    Die Dokumentation zum VFS-Caching-Modus bildet die im Beitrag genannten Einschränkungen gut ab: https://rclone.org/commands/rclone_mount/#vfs-file-caching
    Grundsätzlich gibt es in S3 auch keine echten Verzeichnisse, daher kann man keine Verzeichnisse ohne Dateien haben, und Verzeichnisse haben auch keine gültigen Metadaten wie Änderungszeiten.
    Man kann Directory Marker anlegen, also 0-Byte-Dateien, die auf / enden, und viele Tools, darunter rclone, unterstützen das.
    Dass es keine leeren Verzeichnisse gibt, ist normalerweise kein großes Problem, weil die VFS-Schicht sie vortäuscht und die meisten Apps kurz darauf ohnehin etwas hineinschreiben.
    Letztlich ist es ziemlich viel Arbeit, etwas, das wie S3 aussieht, wie ein POSIX-Dateisystem aussehen zu lassen; hinter Verhalten wie dem Umbenennen geöffneter Dateien und kniffligen Sonderfällen steckt viel Täuschung.
    Die Low-Level-Befehle move/sync/copy von rclone machen diese Behandlung nicht, sondern verwenden die S3-API weitgehend unverändert.
    Wenn ich eine Sache an der S3-API ändern könnte, hätte ich gern eine Option, bei Listenabfragen auch Metadaten zu lesen.
    rclone speichert die Änderungszeit von Dateien in Objektmetadaten, aber es gibt keine Möglichkeit, diese massenhaft zu lesen, sodass für jedes Objekt ein HEAD nötig ist.
    Alternativ wäre es auch gut, beim Upload das Last-Modified eines Objekts setzen zu können.

    • Vielleicht ließe sich das umgehen, indem man Metadaten im Schlüsselnamen selbst speichert.
      Die Schlüssellänge ist auf 1024 begrenzt, daher ist die Menge speicherbarer Metadaten begrenzt, aber selbst unter Berücksichtigung des Dateipfads ist das ziemlich großzügig.
      Man könnte ein in normalisierten Pfaden ungültiges Trennzeichen wie // verwenden und etwa /path/to/file.txt//mtime=1710066090 ablegen.
      Man könnte weiterhin das „Verzeichnis“ per Präfix holen und // wie ein Präfix verwenden, um die Datei direkt zu holen.
      Allerdings würde so ein Format die Kompatibilität mit anderer Software vermutlich stark beeinträchtigen.
    • Ich stimme zu, dass eine Option wünschenswert wäre, Metadaten in Listenabfragen einzubeziehen.
      MinIO hat einen „geheimen“ Parameter metadata=true hinzugefügt, der bei passenden Berechtigungen Metadaten und Tags in Listenabfragen einschließt.
      Da es eine Erweiterung ist, kann man sich nicht stabil darauf verlassen, aber rclone könnte es immer versuchen und nutzen, wenn es verfügbar ist.
      0-Byte-Dateien, die auf / enden, sind ebenfalls möglich, aber man kann auch die gemeinsamen Präfixe einer Listenabfrage selbst als Verzeichnisse betrachten.
      Dann haben Verzeichnisse keinen Zustand und können nicht existieren, wenn sich keine Objekte darin befinden – mit entsprechenden Vor- und Nachteilen.
      Wenn man beim Upload Last-Modified setzen könnte, gäbe es weniger clientseitige Einschränkungen; es hat aber auch Vorteile, wenn die Serverzeit maßgeblich ist.
      Bei clientseitiger Replikation oder Spiegelung müssen dieselben Einschränkungen ebenfalls behandelt werden.
      Mein persönlich größter Kritikpunkt ist, dass es kein HeadObjectVersions gibt, das Versionsinformationen für ein einzelnes Objekt zurückgibt.
      ListObjectVersions kann nicht wissen, ob ein gegebenes Präfix ein echtes Präfix oder ein Objektschlüssel ist, und muss daher immer potenziell eine clusterweite Operation sein.
      AWS hat kürzlich GetObjectAttributes hinzugefügt, aber die Versionsinformationen, die dort gut hineingepasst hätten, sind nicht enthalten.
  • Das „Simple“ in S3 bedeutet nicht „nicht tief“, sondern dass es die wenigsten Bauteile braucht, um die Anforderungen zu erfüllen.
    Wenn man einen verteilten, zentralisierten, replizierten, hochverfügbaren, hochhaltbaren, breitbandigen, latenzarmen, stark konsistenten, synchronen, skalierbaren Objektspeicher plus HTTP-REST-API braucht, dürfte es schwierig sein, ihn einfacher als S3 zu bauen.
    AWS S3 hat über lange Zeit viele Funktionen dazubekommen, aber das Grundverhalten ist gleich geblieben.

    • In der Terminologie des Beitrags bedeutet „die minimal nötigen Bauteile“ genau tief.
      Nach Ousterhouts 『A Philosophy of Software Design』 bedeutet einfach, nicht kompliziert zu sein, und Rich Hickeys „Simple Made Easy“ geht in dieselbe Richtung.
      „Tief“ dagegen bedeutet, mit einer kleinen Schnittstelle intern viele komplexe Funktionen bereitzustellen; für S3 passt dieser Ausdruck daher besser als „einfach“.
      Das ist etwas anderes als Einfachheit im Sinne von „an S3 ist nicht viel dran“.
      https://www.infoq.com/presentations/Simple-Made-Easy/
    • Wenn man der Formulierung des Beitrags folgt, könnte man auch sagen, dass Einfachheit fast schon Tiefe und eine schmale Schnittstelle impliziert.