Wir haben einen eigenen Dateispeicherdienst für Logs, XML, JSON, andere Textdateien und PDF-Dokumente gebaut.
Ausgangslage
Der Dienst ist eine REST-API. Seine Datenbank speichert nur die Metadaten jeder Datei; der Inhalt selbst liegt in Ordnern auf der Festplatte. Die Menge an Dateien ist groß, deshalb haben wir uns entschieden, den Inhalt zu komprimieren.
Herausforderung
Die Komprimierung sparte viel Platz, aber große Dateien ließen sich nur langsam abrufen: Der Client musste warten, bis die ganze Datei entpackt war, bevor das erste Byte ankam.
Die Frage war, ob sich Komprimieren überhaupt noch lohnt.
Vorgehen
Wir haben die Komprimierung beibehalten und geändert, wie Dateien geschrieben und gelesen werden.
- Streamen statt erst entpacken. Die Antwort wird während des Sendens entpackt. Die ersten Bytes gehen sofort raus, und der Speicherbedarf hängt nicht von der Dateigröße ab.
- Komprimierte Bytes, wenn der Client sie annimmt. Akzeptiert ein Client die Kodierung, in der eine Datei gespeichert ist, gehen die gespeicherten Bytes unverändert mit einem
Content-Encoding-Header raus. Der Server entpackt nichts, und über das Netz gehen weniger Daten. - Ein schnellerer Codec. Neue Dateien werden mit Zstandard (zstd) geschrieben, das um ein Mehrfaches schneller entpackt als gzip, bei ähnlicher oder besserer Kompressionsrate. Der Codec steht in den Metadaten jeder Datei, so werden alte und neue Dateien nebeneinander ausgeliefert.
- Nur komprimieren, was kleiner wird. PDF-Dokumente sind intern bereits komprimiert. Eine Datei wird nur dann komprimiert gespeichert, wenn sie dadurch deutlich kleiner wird; sonst bleibt sie unverändert, ohne Codec in den Metadaten.
GET /files/7f3a…/content HTTP/1.1
Accept-Encoding: zstd, gzip
HTTP/1.1 200 OK
Content-Type: application/xml
Content-Encoding: zstdErgebnis
Die Dateien bleiben auf der Festplatte komprimiert. Eine große Datei kommt an, sobald sie angefordert wird, nicht erst nach dem Entpacken, und Clients, die komprimierte Antworten annehmen, erhalten um ein Mehrfaches weniger Daten.
