Engineering Kiosk Episode #73 Cache-freundliches Programmieren, CPU-Caches, Ersetzungsstrategien und Cache-Invalidierung

#73 Cache-freundliches Programmieren, CPU-Caches, Ersetzungsstrategien und Cache-Invalidierung

Diese Episode in deiner Podcast-App hören...

Shownotes / Worum geht's?

There are only two hard things in Computer Science: cache invalidation and naming things.

Caches sind einfach überall. Jede Aktion auf einem Computer nutzt eine Vielzahl an Caches. Sei es der Browser Cache, DNS-Cache, In-Memory Cache auf dem Server oder dein lokaler CPU Cache L1-L4. Doch was sind Caches eigentlich? Welche Cache-Layer und Cache-Hierarchien gibt es? Wie funktionieren Caches? Wie kann ich Cache-freundlich programmieren? Was passiert, wenn der Cache voll ist und was sind Eviction-Policies? Wie relevant sind heutzutage eigentlich die CPU-Caches L1 bis L4 für die normalen Software-Entwickler*innen? Wie kann ich verifizieren, ob mein Code Cache-freundlich ist? Und warum ist Cache Invalidation eigentlich ein hartes Problem?

Bonus: Was Bandlaufwerke mit Caching und niederländisches Hähnchen mit Queues zu tun haben.

Das schnelle Feedback zur Episode:

👍 (top) 👎 (geht so)

Sprungmarken

(00:00:00) Intro

(00:01:02) Es gibt nur zwei harte Probleme in der Informatik

(00:06:56) Caching und Cache Invalidierung

(00:07:25) Was ist ein Cache?

(00:10:36) Jeder nutzt Caches jeden Tag: Cache-Layer

(00:12:34) Cache-Hierarchien und wie relevant sind CPU Caches (L1 bis L4) heute noch?

(00:16:39) Wie funktioniert eigentlich ein Cache? Cache Hit, Cache Miss, Cache Ratio

(00:21:27) Ersetzungsstrategien / Eviction-Policies: FIFO, LIFO, LRU, TTL, MRU, LFU

(00:31:57) Wie kann ich Cache-Freundlich programmieren um den L1 bis L4 Cache richtig zu nutzen und Monitoring von L1 bis L4 Caches

(00:48:39) Ist die Funktionsweise von L1 bis L4 Caches valide für andere Arten von Caches?

(00:51:12) Warum ist Cache Invalidierung ein hartes Problem?

Hosts

Feedback (gerne auch als Voice Message)

 

Transkript

Das Transkript wurde automatisiert per Speech-to-Text erstellt und kann daher Fehler enthalten.

Andy Grunwald (00:00:03 - 00:00:37) Teilen

Willkommen im Engineering Kiosk und cool, dass du wieder dabei bist. In dieser Episode geht es um das Thema Caching. Mit hoher Wahrscheinlichkeit fallen dir sofort Dinge wie Redis, Memcache, Local Storage und Co. ein. Doch all diese Dinge lassen wir einfach mal weg. Wir sprechen über Cache-Hierarchien, über CPU-Caches L1 bis L4, wie du cachefreundlich programmieren kannst und überprüfst, ob dein CPU-Cache ordentlich ausgenutzt wird und das Ganze sogar mit JavaScript. Welche Ersetzungsstrategien es gibt, wenn der Cache voll ist, sowas wie LIFO, FIFO, Least Frequently Used und Least Recrently...

Wolfi Gassler (00:00:38 - 00:00:43) Teilen

Da merkt man, wie schwierig Cache-Probleme eigentlich sind, sogar mit der Aussprache. Andi, du darfst nochmal probieren.

Andy Grunwald (00:00:43 - 00:00:55) Teilen

Least Frequently Used und Least Recently Used, was ein exklusiver und inklusiver Cache ist und final, warum Cache-Invalidierung eigentlich so ein hartes Problem in der Informatik ist. Los geht's, viel Spaß!

Wolfi Gassler (00:01:02 - 00:01:09) Teilen

Andi, vervollständig mal den folgenden Satz. Es gibt nur zwei harte Probleme in der Informatik.

Andy Grunwald (00:01:09 - 00:01:13) Teilen

Exactly Once Delivery, Naming Things, Exactly Once Delivery.

Wolfi Gassler (00:01:13 - 00:01:22) Teilen

Dass du so spontan auf so ein Bullshit kommst, aber wahrscheinlich, du kommst ja aus dieser Datenbank, Kafka-Welt. Gib zu, dir hat den gestern jemand erzählt.

Andy Grunwald (00:01:22 - 00:02:07) Teilen

Ich gebe zu, ich habe die Tage einen neuen KIP gelesen. KIP steht für Kafka Improvement Proposal. Das ist das Format der Design-Dokumente für Kafka. Wenn du da an Kafka etwas ändern möchtest, dann schreibst du ein sogenanntes KIP. Und es hat jemand vorgeschlagen, einen Queuing-Mechanismus in Kafka einzubauen. Beziehungsweise ist das der Kipp, der gerade besprochen wird. Und wenn du um Message-Queuing sprichst, weil Kafka, Achtung, Geheimnis, ist keine Message-Queue. Die wollen es jetzt aber einbauen, dass du Message-Queuing hast. dann sprichst du natürlich auch um so Themen wie at least once delivery und exactly once delivery und darum geht es dann und deswegen kam ich relativ schnell auf so einen Blödsinn.

Wolfi Gassler (00:02:07 - 00:02:10) Teilen

In der Kafka Community gibt es keine Holländer, oder?

Andy Grunwald (00:02:10 - 00:02:13) Teilen

Ich denke schon, aber Moment mal, Kip, das war was zum Essen in Holland.

Wolfi Gassler (00:02:14 - 00:02:18) Teilen

Hey, du bist gut, es heißt Händel oder Hühnchen, damit du das auch verstehst.

Andy Grunwald (00:02:19 - 00:02:23) Teilen

Ne, es heißt aber Kafka Improvement Proposal, heißt das glaube ich.

Wolfi Gassler (00:02:23 - 00:02:35) Teilen

Genau, genau gleiche Schreibweise. Aber kommen wir zurück zu dem Spruch mit den zwei harten Dingen. Du weißt natürlich, auf was ich anspiele, Hoffi, oder? Also wie heißt das korrekte Zitat?

Andy Grunwald (00:02:35 - 00:02:44) Teilen

Ich glaube, es gibt nur zwei harte Dinge in der Informatik. Cache invalidation und naming things, glaube ich. Das ist, glaube ich, der originale Spruch oder andersrum.

Wolfi Gassler (00:02:45 - 00:03:00) Teilen

Keine Ahnung, ob es da eine Reihenfolge gibt. Ich habe ehrlich gesagt den Spruch nie ganz richtig verstanden. Und ich weiß bis heute nicht, ob der eigentlich so ironisch gemeint war oder ob der irgendwie ernst gemeint ist. Aber mittlerweile wird er auch, glaube ich, ironisch verwendet. In ganz vielen Variationen, wie in deiner zum Beispiel auch.

Andy Grunwald (00:03:00 - 00:03:26) Teilen

Also ich weiß nicht, ob der ironisch verwendet wird, er wird inzwischen aber sehr weitläufig verwendet, da es natürlich meines Erachtens nach nicht nur zwei schwierige Probleme in Informatik gibt, sondern deutlich mehr. Aber auch bei den zwei originalen Punkten, Naming Sinks und Cache Invalidierung, ich glaube, da müssen wir uns ans Herz fassen, das ist leider einfach eine harte Sache, oder? Ich meine, wie viele Klassen kennst du, die Utility Manager oder so Factory oder sowas heißen?

Wolfi Gassler (00:03:27 - 00:04:03) Teilen

Ja, aber bei Benahmung sind immer Menschen im Spiel. Und darum ist es, glaube ich, automatisch ein schwieriges Problem. Und da finde ich es ein bisschen misleading, weil das ja eigentlich gar kein Informatikproblem ist, sondern ein menschliches Problem, vielleicht sogar soziologisches Problem, wie man miteinander kommuniziert und so. Aber da bin ich der Meinung, dass es wirklich ein schweres Problem ist. Aber bei der Cash-Invalidierung, da bin ich mir nicht hundertprozentig sicher, ob das wirklich so ein schweres Problem eigentlich ist, aber da werden wir auch noch ein bisschen in die Tiefe gehen heute. Aber mal vorweg, kennst du den Menschen, der das eigentlich gesagt hat? Weil den Spruch liest man ja immer überall, aber weißt du, wer dahinter steht?

Andy Grunwald (00:04:03 - 00:04:08) Teilen

Ich glaube, ich kenne mehr Sprüche von Otto Walkes oder Rudi Carell, aber ich weiß nicht, wer diesen Spruch gesagt hat.

Wolfi Gassler (00:04:09 - 00:04:25) Teilen

Das ist ja meistens so mit diesen ganzen Sprüchen, dass man eigentlich die Person dahinter nicht kennt, aber wir haben das ja letztes Mal auch schon besprochen, eigentlich sind die Personen ja gar nicht so wichtig im Hintergrund. Hast du mir erklärt, wie es um Performance gegangen ist mit dem Casey, ich hab den Namen schon wieder vergessen, Episode 68 war das, glaube ich, oder?

Andy Grunwald (00:04:26 - 00:04:33) Teilen

Du redest von dieser Clean-Code-Geschichte, ne? Also, dass das Clean-Code langsame Programme erzeugt.

Wolfi Gassler (00:04:33 - 00:04:51) Teilen

Genau. Oder Premature Optimization is the root of all evil, hat zum Beispiel Donald Knuth als erstes in den 60ern, glaub ich, in irgendeinem Paper rausgehauen mal. Kennt man auch nicht. Aber der gute Kerl hinter dem, es gibt nur zwei harte Dinge in der Informatik, ist der Phil Carlton. Hast du das schon mal gehört?

Andy Grunwald (00:04:51 - 00:04:52) Teilen

Nee, ich tu mir leid.

Wolfi Gassler (00:04:52 - 00:05:05) Teilen

Ja, ich auch nicht. Und zwar hat damit vielleicht auch zu tun, dass der eigentlich relativ früh gestorben ist in einem Autounfall. Und der war ursprünglich Architekt bei Netscape. Kennst du noch Netscape, Andi, oder bist du da schon zu jung?

Andy Grunwald (00:05:05 - 00:05:11) Teilen

Nee, das war grad so die Zeit, da hab ich grad Internet bekommen. Also ich hab den Netscape-Browser auf jeden Fall schon mal verwendet.

Wolfi Gassler (00:05:11 - 00:05:35) Teilen

Und es ist ganz nett, diese Original-Webseite von ihm zu Netscape-Seiten, die gibt's noch online und die wird gepflegt von ein paar Leuten und online gehalten. Und es ist auch ganz interessant, er stellt sich da nämlich vor als Netscape-Architekt und als Keeper of the Darwin Page, wo es um den Darwin Award geht und Leute, die sich ziemlich dumm ins Jenseits befördert haben. Kennst du wahrscheinlich hoffentlich, oder?

Andy Grunwald (00:05:35 - 00:05:37) Teilen

Nee, aber ist das sowas wie den Turing Award?

Wolfi Gassler (00:05:38 - 00:05:58) Teilen

Nein, da gibt es natürlich einen großen Unterschied. Den Turing Award bekommst du ja, wenn du noch lebst, im Normalfall. Den Darwin Award kannst du nur bekommen, wenn du nicht mehr lebst, weil den bekommst du posthum verliehen, wenn es für die Welt besser war, dass du deine Gene nicht weitergegeben hast. Indem du dich auf Tirolerisch, würde man sagen, butchert. Verstehst du das?

Andy Grunwald (00:05:58 - 00:05:58) Teilen

Bescheuert?

Wolfi Gassler (00:06:00 - 00:06:07) Teilen

Ja, tollpatschig. Wenn man sich tollpatschig verabschiedet hat. Kennst du wirklich nicht? Du hast noch nie was vom Darwin Award gehört?

Andy Grunwald (00:06:07 - 00:06:08) Teilen

Nee, nee. Tut mir leid.

Wolfi Gassler (00:06:08 - 00:06:09) Teilen

Jetzt muss ich wieder ein Beispiel raussuchen.

Andy Grunwald (00:06:10 - 00:06:18) Teilen

Aber ich hab mich auch noch nicht mit kuriosen Todesfällen so auseinandergesetzt. Also vielleicht mal irgendwo gelesen und dann gedacht hab, aha, das war ein Scherz, aber ich wusste nicht, dass es so was wirklich gibt.

Wolfi Gassler (00:06:18 - 00:06:38) Teilen

Also ich hab mal schnell gegoogelt, auf Wikipedia gibt's zum Beispiel einen Fall von 1993. Da hat sich ein Rechtsanwalt in einem Hochhaus im 24. Stock gegen die Fensterscheibe geworfen, um zu demonstrieren, wie stark doch die Fensterscheiben sind. Der Fensterrahmen hat aber nachgegeben und er ist aus dem 24. Stock rausgefallen und ist gestorben.

Andy Grunwald (00:06:40 - 00:06:50) Teilen

Es tut mir total leid, dass ich darüber lachen muss, aber ich frage mich halt jetzt gerade so, war das ein Prozess gegen den Fensterhersteller? Was war das für ein Prozess und wurde er auch danach weitergeführt?

Wolfi Gassler (00:06:50 - 00:06:52) Teilen

Ja, er hat ihn auf jeden Fall nicht weitergeführt.

Andy Grunwald (00:06:52 - 00:06:56) Teilen

Gut. Kommen wir aber mal zum Thema weg von kuriosen Todesfällen.

Wolfi Gassler (00:06:56 - 00:07:19) Teilen

Sondern hin zum Caching und zur Cache-Invalidierung, warum das eigentlich ein schwieriges Problem ist oder ob es ein schwieriges Problem ist, weil ich bin ja eigentlich auch der Meinung, vielleicht gewesen, bevor ich tiefer recherchiert habe, dass ja eigentlich Caching jetzt kein so schweres Problem eigentlich ist. Man verwendet ja irgendwie regelmäßig Caches und die sind da, funktionieren irgendwie, machen auch alles schneller. Wo liegt das Problem?

Andy Grunwald (00:07:19 - 00:07:36) Teilen

Ich habe das Gefühl, man kann gar nichts mehr verwenden, ohne einen Cache da drin. Aber fangen wir mal ganz ganz vorne an. Holen wir die Leute ab, die mit dem ganzen Begriff da noch nicht so viel Erfahrung haben bzw. Lass uns mal ganz kurz klären, was überhaupt ein Cache ist.

Wolfi Gassler (00:07:37 - 00:07:54) Teilen

Ich habe mir gedacht, ich fange jetzt ganz schlau an zu erklären, was eigentlich Cache in der englischen Sprache bedeutet. Aber dazu muss ich mal selber nachschauen. Oder weißt du das zufällig, Andi? Weil irgendwie als Informatiker hörst du Cache dein ganzes Leben nur mit dem Computer Cache. Aber was bedeutet dieses Wort eigentlich? Oder könntest du das jetzt spontan übersetzen?

Andy Grunwald (00:07:55 - 00:07:59) Teilen

Ich kenne Geocaching und dann habe ich so das Gefühl, dass das irgendwas mit Schatz zu tun hat.

Wolfi Gassler (00:08:00 - 00:08:06) Teilen

Ja, scheinbar geht's in die Richtung Verstecklager, wo man irgendwas ablehnt.

Andy Grunwald (00:08:06 - 00:08:11) Teilen

Gut, ich hoffe, ich verstecke meine Daten, die ich cache, nicht, sondern sie werden ...

Wolfi Gassler (00:08:11 - 00:08:53) Teilen

Aber ich hab grad auf DictLeo nachgeschert, und irgendwie, die meisten Übersetzungen sind ja auch wieder Cache-Speicher, Zwischenspeicher. Also bleiben wir mal beim Informatikbereich. Ein Zwischenspeicher. Und zwar geht es beim Cache eigentlich immer darum, dass man Geschwindigkeit rausholt, indem man Daten zwischenspeichert und verhindert, dass man die von irgendwoher bekommen müsste, laden müsste, berechnen müsste. Einfach irgendwas, eine Tätigkeit, die lange dauert, dass man die verkürzt, indem man einen Wert oder eine ganze Datei, kann ja alles sein, zwischenspeichert. Auf einem schnelleren Medium natürlich. Also im Endeffekt will man ja schneller sein und speichert das dann irgendwo ab, wo man schnell darauf zugreifen kann und spart sich dadurch viel Zeit.

Andy Grunwald (00:08:53 - 00:09:16) Teilen

Nehmen wir mal zwei Beispiele. Bei dem schnelleren Zugriff wäre das, wenn ich ein Bandlaufwerk habe. Und ich habe einen Prozess, der möchte einen Datenrecord von dem Bandlaufwerk lesen, dann dauert das, weiß ich nicht, 15 Sekunden. Und wenn ich den Datensatz bereits gelesen habe und dann in meinen Hauptspeicher lade, dann dauert das ein paar Nanosekunden. Das wäre dann zum Beispiel ein Cache, da hat man natürlich Datendeplizierung.

Wolfi Gassler (00:09:16 - 00:09:31) Teilen

Du bist immer ein Fan von aktuellen Beispielen oder von praktischen Beispielen. Wer verwendet den Bandlaufwerk heutzutage noch und noch ein Cache dazu? Genau, du hast lange genug überlegt, niemand.

Andy Grunwald (00:09:31 - 00:09:45) Teilen

Amazon S3 in den Retention Policies, wenn du da die Tier Storage nutzt, um weniger Geld zu zahlen, die lagern das bestimmt nicht auf irgendwelchen Festplatten, sondern lagern die Klamotten irgendwo ganz tief irgendwas günstiges.

Wolfi Gassler (00:09:45 - 00:09:49) Teilen

Aber da hast du dann meistens keinen Cash, weil die Daten brauchst du ja wirklich nie.

Andy Grunwald (00:09:49 - 00:10:01) Teilen

Wenn du die rausholen möchtest, wirst du mit hoher Wahrscheinlichkeit werden die im Hot Storage von S3 dann für die Art gecached, bis sie dann nach der TTL wieder verfallen. So stelle ich mir das bei denen in der Infrastruktur vor.

Wolfi Gassler (00:10:01 - 00:10:03) Teilen

Okay, schönes abstraktes Beispiel.

Andy Grunwald (00:10:03 - 00:10:56) Teilen

Naja, die andere Geschichte ist, ich nehme mir dein Bankkonto, weil da du sehr viel Geld hast bzw. sehr viele Transaktionen hast, ist die Summe aller Transaktionen sehr schwer zu ermitteln auf Basis der Anzahl deiner Transaktionen. Wenn ich jetzt einmal die Summe aber berechnet habe, dann kann ich mir diese zwischenspeichern und muss nicht die Summe aus allen deinen Transaktionen erneut errechnen. wäre dann zum Beispiel auch ein Ergebnis, was ich zwischenspeichern könnte. Das bedeutet, alles was teuer ist, und teuer heißt nicht geldteuer, sondern zeitlich gesehen teuer, das versuchen wir zu verkürzen. Und gerade hatte ich schon gesagt, es ist eigentlich recht schwer, irgendetwas, was mit Computern oder Handys oder was, was ich nicht zu tun hat, zu nutzen, ohne einen Cache zu nutzen. Und auf dieses Thema hat der Wolfgang mich vor ein paar Tagen gestoßen. Und jetzt möchte ich dich bitten, mir das mal zu erklären. Warum ist das denn so?

Wolfi Gassler (00:10:57 - 00:12:11) Teilen

Ja, du brauchst dir mal nur grundsätzlich überlegen. Als Beispiel, wenn du als User jetzt eine Webseite aufrufst, dann hast du da wahrscheinlich ohne Übertreibung irgendwo 100 Cache Layer dazwischen. Also um den Wert, der auf deiner Webseite dort angezeigt wird, von der Festplatte, wo das gespeichert ist, bis zu dir auf deinem Bildschirm zu bringen, hast du garantiert hunderte Cache-Layer dazwischen. Weil du hast im Browser einen Cache-Layer drin. Der Browser cached was. Die CDNs sind natürlich Caches. Haben wir auch eine eigene Episode dazu. Die Web-Server haben Caches eingebaut. DNS-Cache natürlich. Die Datenbank hat natürlich einen Cache. Einen Query-Cache. Die Datenbank hat einen Page-Cache. Das Operating-System hat einen Cache. Filesystem hat vielleicht irgendwo noch einen Cache. Der Controller von deinen Festplatten hat zum Beispiel einen Cache. Und natürlich, die CPU hat auch ganz viele Caches. L1-Cache, L2-Cache, L3-Cache hat man vielleicht schon mal gehört. Und durch diese ganzen Cache-Layers muss dieser einzelne Wert, der dir dann auf der Webseite angezeigt wird, durch. Und auch wenn man jetzt als Programmierer vielleicht gar nicht aktiv irgendwo den Cache nutzt, man hat immer Caches, weil alleine durch die CPU müssen diese ganzen Daten durch und dort habe ich ganz viele Caches.

Andy Grunwald (00:12:12 - 00:12:49) Teilen

Als Endanwender werde ich mit hoher Wahrscheinlichkeit hier so ein Browser-Cache kennen oder so ein DNS-Cache, so all das, was ich noch mehr oder weniger selbst beeinflussen kann beziehungsweise clearen kann. Dann als Softwareentwickler oder als Server-Admin kriege ich vielleicht noch die Server-Seite hin, Web-Server, CDNs, Datenbanken, aber dann wird es zumindest in meiner Bubble relativ eng. Aber besonders wenn es dann an die L1 bis L4-Caches geht, die du gerade erwähnt hattest, Ich bin mir grad nicht so sicher, wie relevant das wirklich für die heutigen Nutzer ist und allem drum und dran, weil ich hab das mal im Studium gehört, aber dann auch wieder vergessen, weil ich hab eine CPU gekauft und die sind dann da.

Wolfi Gassler (00:12:49 - 00:15:24) Teilen

Ja, du bist ja so ein Apple-Jünger. Du glaubst ja, dass automatisch alles, was von Apple kommt, die besten CPUs hat und du schaust da gar nicht mehr drauf. Ich glaub, andere Leute schauen vielleicht sogar auf diese L1-Caches, auf die Größe, weil die liest man ja doch irgendwie und ist der AMD besser oder Intel besser, wer hat die größeren Caches. Also ich glaube bei Hardware-Nerds schauen da schon drauf. Und du hast natürlich recht, das ist ziemlich weg abstrahiert oder transparent. Wobei ich ja dieses Wort transparent überhaupt nicht mag, weil ich weiß nie ob transparent heißt man sieht alles und hat den Zugriff oder ist transparent im Sinne von alles ist weg abstrahiert. Darum bevorzuge ich immer weg abstrahiert dieses Wort. Aber man hat eigentlich auf diesen L1 bis L4 Cache gar nicht so viel Einfluss. Aber man hat natürlich Einfluss über Umwege und es ist sehr sehr relevant für die Programmierung. Aber vielleicht um die L1 und L4 Caches besser mal zu verstehen, ist glaube ich auch ganz wichtig diese Cache Hierarchie oder Memory Hierarchie zu verstehen, die man eigentlich bei einem Computer hat. Und zwar in jedem Computer, in jedem Server, auch wenn der virtualisiert ist, auch wenn du JavaScript verwendest. Im Hintergrund läuft es irgendwo immer und ist auch relevant für dich. Und diese Memory-Hierarchie ist natürlich auch der ganzen Geschwindigkeit geschuldet. Und dem Fakt, dass meistens Speichermedien, die größer sind, einfach langsamer sind. Eine klassische Festplatte oder dein Bandlaufwerk, um das wieder zu strapazieren, ist natürlich sehr langsam, dafür kannst du ganz viel speichern. Eine Festplatte ist ein bisschen schneller, kannst aber weniger drauf speichern. Und nach oben hin wird der Speicherplatz natürlich immer kleiner. Das heißt, irgendein Hauptspeicher ist kleiner als die Festplatte, dafür schon relativ schnell. Und danach kommen die Cache Layers in der CPU oder GPU Und die Layer in der CPU heißen eben L1, L2, L3, manchmal auch L4. Und man kann sich das wie so eine Pyramide vorstellen, darum spricht man auch von so einer Pyramide oder Hierarchie, wo ganz unten die Festplatte ist und dann wird nach oben hin das immer kleiner aber schneller. Und ganz am Ende ist die CPU, die dann wirklich eine Berechnung macht. Aber um irgendeine Berechnung zu machen und den Wert von der Festplatte zu lesen, muss der Wert zuerst von der Festplatte in den Hauptspeicher, in den L3-Cache, dann in den L2-Cache, L1-Cache, bis er dann irgendwann bei der CPU ankommt. Und die Caches kannst du auch nicht ausschalten. Also jeder verwendet diese Caches. Und es ist gut, dass man die verwendet, weil sonst wäre alles extrem langsam natürlich. Also die machen schon Sinn. Aber man muss durch diese ganzen Caches durch, um überhaupt mit Daten zu arbeiten. Bis dann beim Register vom CPU eben mein Integer ankommt, den ich dann in der Variable gespeichert habe.

Andy Grunwald (00:15:25 - 00:15:42) Teilen

Wenn ich aber jetzt meiner Frau sagen würde, hör mal, wenn du auf Instagram wieder ein Reel anguckst, weißt du eigentlich, dass du deinen L1, L2 und L3 Cache von deinem iPhone dauerhaft nutzt, immer wenn du hier durchscrollst? Dann fragt ihr mich, Andi, was willst du von mir? Ich weiß dann mal, was ein Cache ist.

Wolfi Gassler (00:15:43 - 00:15:55) Teilen

Ja, aber die ist ja auch keine Programmiererin, aber du bist Programmierer und du schaust auch den ganzen Tag Reels an übrigens und du hast dir auch noch nie überlegt, was da Caches beteiligt sind. Und das ist der große Fehler, das solltest du eigentlich machen als Programmierer.

Andy Grunwald (00:15:55 - 00:15:57) Teilen

Okay, also setzt du gerade die ...

Wolfi Gassler (00:15:57 - 00:16:03) Teilen

Du solltest zum Beispiel auch wissen, wie groß so ein Cache ist. Wie groß ist denn so ein L1-Cache in deinem Laptop?

Andy Grunwald (00:16:03 - 00:16:08) Teilen

Ich gehe stark davon aus, dass der relativ klein ist und nicht so groß wie meine Festplatte, sondern, weiß ich nicht, ein paar Kilobyte.

Wolfi Gassler (00:16:09 - 00:16:36) Teilen

Ich habe dir jetzt leider nicht deine Apple-Werte rausgesucht, aber ich nehme mal einen besseren Prozessor, einen Ryzen zum Beispiel. Der hat 512 Kilobyte, habe ich jetzt gerade rausgesucht, L1 Cache, L2 Cache 4 Megabyte, L3 Cache 16 Megabyte. Und wenn man zum Beispiel so in die Server-Ecke geht, so ein Xeon, Intel Xeon, der hat dann teilweise schon um die 100 Megabyte Cache. Also durchaus eine ordentliche Größe, würde ich mal sagen. Also gerade wenn man in Programmgrößen denkt, 100 Megabyte muss man erst mal vollbekommen mit irgendwelchen Werten.

Andy Grunwald (00:16:36 - 00:17:12) Teilen

Ein YouTube-Video und hast das Ding gegessen. Aber ich meine, der Speicherplatz, zumindest ML1 bis L4 Cache oder auch in anderen Caches, ist ja in der Regel begrenzt. Wir haben ja jetzt keinen unendlichen Speicher, egal wo wir drin sind. Lass uns doch mal kurz darüber sprechen, wie funktioniert eigentlich ein Cache, weil ich denke, Wenn du die Anforderung stellst, dass ich als Programmierer, als Softwareentwickler, mich mit Caches auskennen muss, beziehungsweise weiß, wie ich die benutze, optimiere, oder beziehungsweise auch weiß, wann ich diese einfach versuche wegzulassen, dann muss ich ja verstehen, wie so ein Cache funktioniert, worauf es ankommt, wovon ich hier rede.

Wolfi Gassler (00:17:13 - 00:18:23) Teilen

Ja, eigentlich ist der Cache ganz simpel ein Speichermedium, wie eine Festplatte. Man greift einfach darauf zu, bekommt was schnell raus, kann aber auch was rein speichern. Und der Cache, was wir unter Cache eigentlich verstehen, ist dann das ganze System, auch die Logik um dieses Speichermedium, um dieses schnelle Speichermedium rundherum. die das managt, was dort abgelegt wird, wann es dort abgelegt wird, wann was geschrieben wird, wann was rausgeworfen wird, weil wir sind ja da in einem relativ kleinen Bereich unterwegs, also wenn man jetzt einen L1 Cache mit 512 KB nimmt, wir können natürlich nicht alles in unserem L1 Cache speichern, wir sind da begrenzt von der Speicherkapazität, das heißt wir müssen auch irgendwann entscheiden, Was kommt wieder raus? Was lassen wir drin? Und das ist natürlich auch ein großer Bereich von Caches, der gar nicht so leicht ist, in einer möglichst optimierten Variante zu implementieren. Also die Logik von dem Cache ist eigentlich das Wichtige, ist natürlich dann in Hardware gegossen, bei der CPU irgendwo, aber das ist das eigentlich ausschlaggebende, wie dieses Gesamtwerk, so ein kleiner Computer fast, dann arbeitet mit seinem Speicher, mit den Zugriffsmechanismen, mit der Logik und alles, was man dazu braucht.

Andy Grunwald (00:18:24 - 00:18:40) Teilen

Ich glaube, was wichtig zu wissen ist, dass wenn man etwas im Cache gespeichert hat, dass man wissen muss, wie man diesen Datenrecord wieder aus dem Cache rausholt. Und das tut man in der Regel, wenn man so eine Art ID hat oder so einen fixen Key, den man kontinuierlich wieder berechnen kann.

Wolfi Gassler (00:18:41 - 00:20:19) Teilen

Du hast einfach einen Identifier, bei der CPU ist es natürlich irgendwo der Speicher, also die Speicheradresse, um genau zu sein, mit der man den Wert anspricht. Bei einem Query Cache in der Datenbank ist die ID oder der Wert die Query an sich oder die ID von einer Zeile in der Datenbank. Also du hast immer irgendwo einen Identifier, der dir ermöglicht auf die Daten eigentlich zuzugreifen. Oder den Dateinamen bei der Festplatte wäre ja ungefähr das gleiche. Also du brauchst so einen Identifier und der Cache arbeitet anhand dieses Identifiers und speichert dir den eigentlichen Wert unter dem Identifier ab. Und wenn du jetzt schon was im Cache abgespeichert hast und wiederholst, wiederverwenden musst, weil du eine Variable hast, die du in einer Vorschleife zum Beispiel durchgehst, dann hast du einen Cache-Hit, das heißt der Wert ist im Cache schon verfügbar. Du holst dir den aus dem Cache raus, aus dem schnellen Cache, zum Beispiel aus dem L1-Cache und musst gar nicht mehr in den L2-Cache gehen oder womöglich sogar auf die Festplatte oder in den Hauptspeicher. Weil du den schon im L1-Cache hast, hast du einen Cache-Hit, kannst du den sofort verwenden. Wenn du den noch nicht im Cache liegen hast, dann hast du einen Cache-Miss. Das sind die zwei wichtigen Begriffe, die man auch im Monitoring dann verwendet. Cache-Hit und Cache-Miss. Wie viele Zugriffe kann ich direkt aus meinem Cache holen und wie viele muss ich eben eher von meinen langsamen Medien holen und dann im Cache abspeichern. Und diese Hit-Ratio ist eigentlich so ein KPI, den man möglichst optimieren will, weil eben die Caches viel, viel schneller sind und umso mehr ich aus meinem Cache rausholen kann, umso schneller ist mein Programm, umso schneller ist mein Computer oder meine gesamte Architektur, Datenbank, was es dann auch immer ist.

Andy Grunwald (00:20:19 - 00:20:23) Teilen

Die Hit-Ratio selbst ist die Relation zwischen Cache-Hit und Cache-Mistern.

Wolfi Gassler (00:20:24 - 00:20:34) Teilen

Genau, also wenn ich 70% Hit-Ratio habe, dann kann ich 70% aus meinem Cash holen und bei 30% von meinen Anfragen muss ich auf die langsame Festplatte wieder zurückgreifen und die Daten holen.

Andy Grunwald (00:20:35 - 00:20:41) Teilen

Und ab wie viel Prozent Hit-Ratio ist so ein Cash gut, effizient? Lohnt sich der?

Wolfi Gassler (00:20:41 - 00:21:27) Teilen

Ja, das kommt natürlich ganz darauf an, wie schnell dein Medium ist. Wenn man sich jetzt überlegt, okay, du hast einen Browser-Cash, der ist natürlich super schnell, weil der auf dem Computer ist. dann ist die Hit-Ratio natürlich unter Umständen auch schon gut, wenn du 10% oder 3% aus deinem Cache abfrühstücken kannst, weil der Zugriff auf das Internet durch alle Systeme durch, durch Webserver und so weiter bis zu dem eigentlichen Wert oder das Bild oder was du auch immer gerade abrufst, der Vorteil ist natürlich so hoch, dass sich vielleicht auch 5% schon rentieren. Hingegen bei einer CPU willst du vielleicht natürlich wesentlich höher sein, vor allem wenn du eine Vorschleife oder so in dem Programm hast, Weil da der Unterschied natürlich nicht so hoch ist und um möglichst viel rauszuholen, probierst du da natürlich aufs letzte noch raus zu optimieren.

Andy Grunwald (00:21:27 - 00:21:56) Teilen

Jetzt hattest du gesagt, so ein L1-Cache hat relativ wenig bzw. viel Speicher. Das kommt, glaube ich, gerade auf die Perspektive an. Du hattest gerade gesagt, L1-Cache ist so bei 512 KB, der L2-Cache bei 4 MB, der L3-Cache bei 16 MB. Das ist ja nicht wirklich viel Daten. Besonders im Zeitalter, wo Data the new oil ist. Also, was passiert denn, wenn... Also, wie reagiert denn so ein Cache, wenn ich da einfach mehr Daten reinpacke, als da Platz drin haben?

Wolfi Gassler (00:21:57 - 00:23:05) Teilen

Was ja ständig passiert, weil du hast ja einen ständigen Austausch, du liest ständig Daten ein, du schaust ein YouTube-Video, das geht auch wieder durch die ganzen L-Caches durch, also du hast ja ständig Traffic-Verkehr auf deinen Caches und du musst ständig entscheiden, was wirfst du wieder raus aus deinem Cache, was kommt rein. Und da gibt es diese sogenannten Ersetzungsstrategien oder im Englischen Eviction Policies, Replacement Policies, gibt es mehrere Begriffe dafür, aber die beschreiben alle dasselbe, diesen Algorithmus, wie entscheidest du, was rausgeworfen wird aus deinem Cash und was du drin belast, weil du willst eben die Hit-Ratio möglichst hoch halten und je nachdem, was du wieder rauswirfst, wenn du immer genau diese Sachen rauswirfst aus deinem Cash, die du aber vielleicht im nächsten Schritt brauchen würdest, in der Zukunft, das heißt du musst immer die Zukunft vorhersagen, Wenn du die immer rauswirfst, die wichtigen Dinge, dann hast du natürlich extrem niedrige Hit-Ratio und vielleicht wird es am Ende sogar langsamer, weil du musst dir dann im Cache nachfragen, dann wieder auf die Festplatte gehen und so weiter. Also du hast dann sogar mehrere Anfragen womöglich auf verschiedene Cache-Layer und das macht das Ganze langsamer. Also darum ist es extrem wichtig, was wird ersetzt und was wirfst du aus deinem Cache raus.

Andy Grunwald (00:23:06 - 00:23:12) Teilen

Den Term Eviction Policy habe ich auch schon öfters gelesen in Dokumentationen wie von meiner Lieblingsdatenbank Redis oder auch Cassandra.

Wolfi Gassler (00:23:12 - 00:23:16) Teilen

Das ist keine Datenbank. Dein Cache, wolltest du sagen. Redis ist ein Cache.

Andy Grunwald (00:23:16 - 00:23:20) Teilen

In-Memory-Data-Structure-Server, wenn du es genau wissen möchtest.

Wolfi Gassler (00:23:20 - 00:23:27) Teilen

Haben wir übrigens auch eine eigene Episode gemacht. Moment, Andi, musst du jetzt wirklich nachschauen, was für eine Episoden-Nummer das ist? Kennst du unsere Episoden nicht komplett auswendig?

Andy Grunwald (00:23:28 - 00:23:31) Teilen

Episode Nummer 54 vom Januar diesen Jahres.

Wolfi Gassler (00:23:31 - 00:23:32) Teilen

Hätte ich natürlich sofort auf Anhieb gewusst.

Andy Grunwald (00:23:33 - 00:23:49) Teilen

Aber du hast grad schon von Algorithmus gesprochen, Eviction Policy. Also, wie ... Was gibt's denn da für Algorithmen? Wie entscheiden die denn, was, wann, wie, woraus fliegt? Ist das random? Ist das immer der zuletzt geschriebene Record? Also, da werden sich mit hoher Wahrscheinlichkeit ganz viele schlaue Menschen noch mehr Gedanken gemacht haben.

Wolfi Gassler (00:23:50 - 00:27:03) Teilen

Nicht nur gemacht haben, die machen sich immer noch Gedanken, weil es ist wirklich ein riesen Forschungsgebiet und je nach Cache ist es natürlich unterschiedlich. Also wenn du natürlich in dem Browser Cache bist, dann hast du da andere Ersetzungsstrategien als jetzt in dem CPU Cache im L1 bis L4 Cache. Die klassischen Ersetzungsstrategien, die man vielleicht schon mal gehört hat, sind FIFO und LIFO, also First In, First Out, Last In, First Out, die man auch sonst in der Programmierung ja kennt bei Queues und solchen Dingen. Das Problem bei First In, First Out, das würde so, wenn man naiv auf die Caches schaut, am ehesten Sinn machen. Das, was am ältesten ist, das fliegt als erstes wieder raus. Wenn man dann aber überlegt, okay, ich habe eine Schleife zum Beispiel, dann kann es sein, dass mein Wert, der da gespeichert ist, meine i-Variable zum Beispiel in der Schleife, die liegt ja schon ganz lang in dem Cache drin. Also die wurde als erstes gespeichert, wie die Schleife angefangen habe. Jetzt will ich die aber vielleicht nicht ständig rausschmeißen, diese Variable i, nur weil sie alt ist, weil ich brauche sie ja ständig. Und darum ist man dann eher übergegangen auf den LRU-Mechanismus, least recently used, Das heißt, die Daten, die am wenigsten verwendet werden, die werden rausgeschmissen. Und dadurch ich in meiner For-Loop dieses i ständig liese und ständig schreibe, bleibt es in meinem Cache vorhanden. Hingegen irgendwas anderes, in der For-Loop zum Beispiel, diese Daten, die werden nur einmal geschrieben, die fliegen dann irgendwann wieder raus. Man kann das Ganze noch kombinieren, zum Beispiel mit einem TTL, Time To Live Flag. Das nennt sich dann TLRU, also Time Aware Least Recently Used. Damit kann ich sicherstellen, dass zum Beispiel irgendwelche Werte nach einer gewissen Zeit automatisch immer aus meinem Cache rausfliegen und ich automatisch immer die Grunddaten nochmal neu einließe. Aber wie gesagt, es kommt ganz stark auf den Use-Case drauf an und es gibt zum Beispiel auch Use-Cases, ganz schräge Use-Cases, wo most recently used, also diese Daten, die gerade kürzlich geschrieben habe, rausfallen. Der Algorithmus ist zum Beispiel in der Datenbank-Welt. Und wenn man intuitiv dran denkt, klingt das ein bisschen komisch, dass ich diesen Wert, den ich gerade verwendet habe, möglichst schnell wieder rauskicke aus meinem Cache. Aber es wurde eben gezeigt in einem Paper in der Datenbank-Welt, dass das unter Umständen der beste Algorithmus sein kann in der Datenbank-Welt, wenn man sehr lange Listen durchgeht, durchloopt, dass der Cache dann am besten funktioniert, weil man eben die Daten, die man gerade eingelesen hat, auf keinen Fall mehr braucht, weil man ja den gesamten Loop einmal durchlaufen muss, bis man wieder an dem Punkt angekommen ist, wo man dieses Datum wieder brauchen würde. Also es ist wirklich komplett unterschiedlich, wird viel geforscht und je nach Anwendungsbereich braucht man da andere Algorithmen. Und wir können da gerne mal auch einen Link in die Show Notes setzen zur Wikipedia Seite. Es gibt nämlich eine eigene Wikipedia Seite nur zu Replacement Policies und die ist wirklich, wirklich lang und hat alle möglichen Namen und Spezialvarianten, wo dann approximierte statistische Werte noch mit reinkommen, wo man spezielles Mehrwissen über die Daten verwendet, um eben zu wissen, was wird oft verwendet, was nicht. Da haben sich wirklich viele Leute Gedanken drüber gemacht und für den jeweiligen Anwendungszweck spezielle Algorithmen entwickelt.

Andy Grunwald (00:27:04 - 00:27:40) Teilen

Ich hab grad mal in der Redis-Dokumentation nachgeschaut, weil ich hab's aber schon mal erwähnt, die Dokumentation ist einfach sehr, sehr gut und auch wenn du nicht Redis verwendest, lernst du da sehr viel. Und dann bin ich auf die Seite der Eviction Policy gegangen und hab mal geguckt, okay, was kann der denn hier so alles? Neben FIFO, LIFO und was weiß ich nicht noch alles, also den Standarddingern, kann der auch all keys random was natürlich dann eher so russisch und das ist glaube ich okay dich brauchen wir heute nicht mehr und dich brauchen wir heute nicht mehr ich mich würde halt schon gern mal ein praktischer use case von all keys random interessieren steht eine erklärung.

Wolfi Gassler (00:27:40 - 00:27:58) Teilen

Drin warum das verwendet wurde Also wenn ich jetzt raten müsste, dann würde ich sagen, das ist, um irgendwelche Tests zu machen, dass man so einen Base Case hat, wenn man das ganze Performance testet, dass man einen Base Case ausprobiert und von dem weg dann die Optimierungen testen kann, weil Random ist das Schlechteste.

Andy Grunwald (00:27:58 - 00:28:00) Teilen

Verwenden Sie den All Keys Random, wenn.

Wolfi Gassler (00:28:00 - 00:28:02) Teilen

Sie einen Zyk- Moment, ist das sogar Deutsch?

Andy Grunwald (00:28:03 - 00:28:29) Teilen

Nein, ich hab's gerade übersetzt. Verwenden Sie ein All-Keys-Random, wenn Sie einen zyklischen Zugriff haben, bei dem alle Schlüssel kontinuierlich abgefragt werden, oder wenn Sie erwarten, dass die Verteilung gleichmäßig ist. Mit hoher Wahrscheinlichkeit ist dann der Cash-Policy-Eviction-Algorithmus All-Key-Random auch sehr schnell, weil, nimm halt einfach ein Random-Key, also du musst ja nicht viel Metadaten mittracken, wie bei Least-Recently-Used, da musst du ja schon richtig Metadaten mittracken.

Wolfi Gassler (00:28:29 - 00:29:21) Teilen

Das ist ein guter Punkt, was du da erwähnt hast, dass so Caches natürlich auch Mehraufwand bedeuten. Also du musst es dann irgendwo mitspeichern, was ist denn als letztes benutzt worden, wie oft ist es benutzt worden und das ist schon ein Mehraufwand und wenn wir da wieder im CPU Bereich sind, dann kannst du dir natürlich das nicht leisten, da irgendwie die Daten, keine Ahnung, statistisch zu analysieren und Approximierungen zu machen, sondern das sind da meistens sehr rudimentäre Algorithmen, natürlich auch super optimiert und die Hersteller, ich habe mal probiert, da was rauszufinden, die sagen auch nicht so richtig, wie das funktioniert, die sagen es ist so LRU-based, aber was genau gemacht wird, sagen sie dann auch nicht. Also Im Hardware-Bereich muss man da sicher anders arbeiten, aber ich vermute mal, die meisten sind so am ehesten LRU-based. Es gibt auch Papers dazu, die probiert haben, das zu reverse-engineeren, was der Intel so gebaut hat zum Beispiel, aber das geht dann schon sehr in die Tiefe.

Andy Grunwald (00:29:21 - 00:29:26) Teilen

Und dann scrollst du auf dieser Redis-Eviction-Policy-Seite ein bisschen runter und dann siehst du...

Wolfi Gassler (00:29:26 - 00:29:32) Teilen

Ich erkläre dir gerade was Tolles über Intel und du kommst schon wieder mit Redis. Du kannst nicht loslassen von Redis, oder?

Andy Grunwald (00:29:32 - 00:29:42) Teilen

Was du mir gerade gesagt hast, ja, Intel hat was Proprietäres, die geben nicht raus, was sie da tun, und es versuchen Leute zu reverse-engineeren. Also eigentlich sagst du gerade, Intel ist wie Apple.

Wolfi Gassler (00:29:43 - 00:29:46) Teilen

Ja, geh voll mit, aber erzähl mal aus deiner offenen Redis-Ecke.

Andy Grunwald (00:29:47 - 00:30:12) Teilen

Du hattest gerade den Eviction Algorithmus LRU, Least Recently Used, erwähnt. Kennst du denn auch Least Frequently Used? Also LFU. Allein, also ich bin ja kein Native, da habe ich mich erstens gefragt, wo ist denn der Unterschied? Frequently Used, am wenigsten häufig verwendeter. least recently used, am seltesten verwendeten, das wäre so die Übersetzung.

Wolfi Gassler (00:30:12 - 00:30:42) Teilen

Ja, es ist eine Kombination, würde ich sagen. Also der frequently, der trackt halt noch statistisch mit, wie oft etwas verwendet wird und recently ist halt nur zeitbasiert, wobei das wahrscheinlich sehr ähnlich ist, aber ich vermute mal, in manchen Anwendungsfällen doch ein unterschiedliches Ergebnis gibt. Weil du natürlich mit einem Zugriff, wenn der kürzlich war, schon wieder sicherstellst, dass das Element nicht mehr rausfliegt. Hingegen wenn du ganz oft schreibst, aber vielleicht eine gewisse Zeit nicht mehr, fliegt es nicht so schnell aus dem Cache raus. Also das ist wahrscheinlich so ein kleiner, feiner Unterschied.

Andy Grunwald (00:30:42 - 00:31:28) Teilen

Du bist sehr, sehr gut, muss ich zugeben. Also das hätte ich jetzt gerade nicht erwartet. Kudos Wolfgang. Und zwar ist LFU und LRU sehr, sehr, sehr nah beieinander, wie du auch beschrieben hast. Es nutzt halt nur einen anderen Metadaten-Counter und da nutzt es einen probabilistischen Counter namens Morris-Counter. Also, du merkst schon, das geht halt alles relativ sogar in algorithmische Zahl, also wie du wirklich zählst. Ich hab eigentlich bisher gedacht, ich zähle immer wie Grafzahl. Nach 1 kommt 2, nach 2 kommt 3. Scheint mit dem Morris-Counter jetzt zum Beispiel nicht so zu sein. Also, ich find's faszinierend, in welchem Bereich der Optimierung sich sehr kluge Leute, deutlich klüger als ich, tagtäglich Gedanken machen.

Wolfi Gassler (00:31:29 - 00:31:53) Teilen

Aber du musst dir das ja auch immer vor Augen halten, wenn du schaffst diesen L1-Cache, wo alle Daten der Welt durchfließen. Also es gibt keinen Computer ohne L1-Cache, glaube ich zumindest. Oder einen Großteil, würde ich mal sagen. Das heißt, alles was an Informationen irgendwie durch die Welt fliegt, geht durch so L1- bis L3-Caches. Wenn du schaffst, irgendwo 3% daraus zu holen, Hast du fast die globale Erderwärmung gelöst, das Problem.

Andy Grunwald (00:31:53 - 00:32:08) Teilen

Ich glaube, dann bist du der neue Green-IT-Officer bei Intel. Aber du fängst jetzt schon wieder von diesen L1, L2, L3-Cachen an. Und ich bin ja ehrlich von dir. Ich bin seit etlichen Jahren in der Web-Entwicklung, beziehungsweise Web- oder Backend-Entwicklung.

Wolfi Gassler (00:32:08 - 00:32:13) Teilen

Traust du dir jetzt nimmer zu sagen, wie lang du schon in der Entwicklung bist, damit die Leute nicht wissen, wie alt du schon bist?

Andy Grunwald (00:32:14 - 00:32:46) Teilen

Nee, das sind diese vier Seiten einer Nachricht. Das kann heißen, okay, ich prahle mit meinen Jahren, ja, oder ich bin schon so alt. Also das kann ich ja nicht beeinflussen, wie das gelesen wird. Auf jeden Fall Webentwicklung, Backendentwicklung, von mir aus auch C-Programmierung. Ja, aber ich habe mir jetzt noch nie Embedded Software oder ähnliches geschrieben. Mein Punkt ist aber jetzt gerade, ich hatte noch nie wirklich direkten Kontakt zu L123-Caches. Was bringt mir das als Softwareentwickler jetzt, dass ich weiß, wie groß mein L1-Cache ist? Oder betrifft das nur meine Framerate bei Counter-Strike?

Wolfi Gassler (00:32:46 - 00:34:01) Teilen

Ja, also die Größe macht natürlich was aus. Umso größer, umso besser. Kann man mal ganz so allgemein sagen bei Caches in der Cache-Hierarchie. Und mir wundert eigentlich das, warum du noch keinen Kontakt hattest, weil man muss als Programmierer in eigentlich schon im Kopf haben, wie so Caches funktionieren und wie auch Programmiersprachen funktionieren. Weil es gibt zum Beispiel den großen Unterschied zwischen C und Fortran, dass die, wenn du eine Matrix abspeicherst, also ein zweidimensionales Array, also eine große Tabelle auf gut Deutsch, also nehmen wir mal an, irgendeine Matrix, 100x100 Felder, Dann speichert dir Fortran das ganze im Speicher spaltenbasiert ab, das heißt Fortran speichert die erste Zelle ab, dann die erste Zelle von der zweiten Zeile, dann die erste Zelle von der dritten Zeile und wenn du das klassisch in C oder in deiner Lieblingssprache Go machst, wobei ich habe jetzt keine Ahnung über Go, aber ich sage einfach mal Go macht das auch zeilenweise, dann speichert C zuerst, erste Zelle, zweite Zelle, dritte Zelle, vierte Zelle, immer die erste Zeile ab im Speicher und dann kommt die nächste Zeile und dann kommt die nächste Zeile. Und das macht einen extrem großen Unterschied, wie du dann auf die Daten zugreifst. Und das eine ist unter Umständen langsamer und das andere schneller.

Andy Grunwald (00:34:01 - 00:34:04) Teilen

Und warum ist das ein oder andere jetzt schneller beziehungsweise besser?

Wolfi Gassler (00:34:04 - 00:36:07) Teilen

Ja, da kommt ein ganz wichtiges Element ins Spiel, das sogenannte Prefetching-Verhalten von Caches. Weil Caches sind so aufgebaut, also diese 512 KB L1-Cache zum Beispiel, die sind in sogenannten Cache-Lines, also Cache-Zeilen aufgebaut. Hat man vielleicht schon mal gehört, eine Cache-Line. Das heißt eigentlich, wenn ich da einen Integer-Wert raushole aus meinem L1-Cache, dann macht der Cache sogenanntes Prefetching. Also ich würde es mal so übersetzen mit voreilenden Gehorsam, weil der Cache denkt, wenn du jetzt einen Integer abrufst, Denn wirst du wahrscheinlich den Integer dahinter auch gleich noch brauchen. Und der fetcht dir das schon mal vorab aus dem L2-Cache in den L1-Cache. Obwohl du noch gar nicht gesagt hast, ich brauche das Element. Macht der Cache das automatisch, weil der Cache immer eine gesamte Cache-Line fetcht. D.h. z.B. beim L1-Cache 64 Bytes meistens, 128 Bytes beim L2-Cache, wird die gesamte Zeile mit 64 Bytes aus dem L2-Cache in den L1-Cache geschoben, obwohl du nur einen kleinen Integerwert brauchst. Macht der Cache das automatisch. Und wenn jetzt Fortran deine Daten aber spaltenweise ablegst, du aber zeilenweise durch deine Tabelle durchgehst, eine klassische Vorschleife, zuerst immer eine Zeile, dann springst du in die nächste Zeile, dann die ganze zweite Zeile, dann die ganze dritte Zeile. Wenn du so durch eine Fortran Matrix oder zweidimensionales Array durchwanderst, Dann probiert dir der Cache immer die ganze Zeile zu fetchen oder zumindest die nächsten Zellen und du springst aber schon in die nächste Zeile und wirst irgendein ganz anderes Element, was dir der Cache gar nicht geholt hat im Vorhinein und du hast ständig Cache Misses und deine Cache Ratio geht extrem nach unten und du musst immer wieder alles neu schreiben in deine Caches und immer die Daten wiederholen und dein Programm wird dann super langsam, nur weil du mit Fortran zum Beispiel zeilenweise durch dein Programm gehst oder mit C spaltenweise. Also du musst wissen, wie liegen deine Daten im Speicher und wie greifst du darauf zu.

Andy Grunwald (00:36:07 - 00:36:14) Teilen

Wenn ich jetzt Fortran entwickeln würde, stimme ich dir zu. Nur meine Frage ist, wer entwickelt heutzutage, Achtung, freiwillig noch Fortran?

Wolfi Gassler (00:36:15 - 00:36:39) Teilen

Du glaubst gar nicht, wie viele Leute Fortran programmieren. Die ganze wissenschaftliche Welt, diese ganzen Bauingenieure, wenn die irgendwelche Strömungsanalysen machen, deine ganzen Handy-Apps. Okay, Apple hat wahrscheinlich nur eine Wetter-App, die erlaubt keine anderen Wetter-Apps. Die basieren garantiert auch alle im Hintergrund, diese ganzen Modelle, irgendwo auf Fortran. Also Fortran ist noch überall unterwegs in der Welt. Gibt es auch, glaube ich, Neuerungen. Also es ist nicht so schlimm wie Cobol.

Andy Grunwald (00:36:39 - 00:36:43) Teilen

Ich stelle die Frage anders. Kriege ich so ein Performance-Gain auch in JavaScript hin?

Wolfi Gassler (00:36:43 - 00:36:44) Teilen

Ja, bekommst du.

Andy Grunwald (00:36:44 - 00:36:45) Teilen

Und jetzt bin ich gespannt.

Wolfi Gassler (00:36:46 - 00:37:20) Teilen

Ihr habt das gerade für diese Episode mal ausprobiert und habt einen JavaScript-Code geschrieben, der, jetzt muss ich selber nachschauen, 10.000 mal 10.000 eine Matrix macht und einfach durchläuft. Und ich hab einmal das ganze spaltenorientiert gemacht und einmal zeilenorientiert. Also diese zwei Vorschleifen vor bla bla bla i und j, einmal ist i außen und einmal ist i innen in dieser Vorschleife. Ganz simpel. Und habt ihr es ein paar mal hintereinander ausgeführt und nicht nur einmal? Warum ist das Problem, wenn man es nur einmal ausführt?

Andy Grunwald (00:37:20 - 00:37:21) Teilen

Du meinst jetzt für einen Performance-Test?

Wolfi Gassler (00:37:21 - 00:37:22) Teilen

Ja.

Andy Grunwald (00:37:22 - 00:37:28) Teilen

Mit hoher Wahrscheinlichkeit, weil du dann Seiteneffekte durch andere Applikationen oder ähnliches haben kannst. Um einfach statistisch relevant zu sein.

Wolfi Gassler (00:37:28 - 00:39:36) Teilen

Das natürlich auf der einen Seite, aber auch innerhalb eines Aufrufes habe ich das Ganze mehrfach aufgerufen, weil du hast das Cache Warming Phänomen. Wenn du ja über viele Daten drüber gehst, das erste Mal wird alles in deine Caches geladen. Zum Beispiel vom RAM in den L3 Cache und der L3 Cache ist groß. Das heißt du hast die ganzen Daten schon im L3 Cache liegen. Das heißt im ersten Zugriff ist es mal ziemlich langsam, weil du alles aus deinem RAM in den L3 Cache bringen musst. Im zweiten Zugriff hast du das dann aber schon im L3 Cache, dann ist das plötzlich schneller. Also umso öfterst du mit den Daten arbeitest, umso mehr von den Daten liegt natürlich im L3, L2, L1 Cache und dadurch kannst du da auch Speed rausholen. Und wenn du fair testen willst, musst du wirklich die Durchläufe öfters machen und du siehst es dann auch sofort, dass das schneller wird. Also bei meinem Durchlauf zum Beispiel, der erste Durchlauf hat 1,7 Sekunden gedauert und der zweite Durchlauf über dieselben Daten nur mehr 0,8 Sekunden. Also du hast da schon einen deutlichen Unterschied und dann bleibt er relativ konstant, also um die 0,8 Sekunden, wenn du dann drüberläufst. Aber das interessante ist, wenn man das vergleicht, man läuft durch diese 10.000x10.000 Matrix zahlenweise durch, hast du beim ersten Zugriff 1,7 Sekunden, wie erwähnt, danach immer 0,8. Jetzt machst du das Ganze spaltenorientiert, dann hast du das erste Mal 1,7 und dann bleibt es bei 1,7 Sekunden. Das heißt, wenn du spaltenweise durchläufst, hast du immer diese langsame Zeit und du hast keinen Performance Gain durch die Caches. Das heißt, du hast die doppelte Zeit, die du brauchst, um durchzulaufen, um zu schreiben in dieser Matrix und kannst keine Vorteile durch die Caches nutzen. Also wir reden da von 100% mehr Zeit, die das Programm benötigt. Und das ist JavaScript. Und ihr habt es mit Node.js ausprobiert und ihr habt es sogar im Browser ausprobiert, bei mir einfach in der Konsole. Da ist das gleiche Phänomen, dauert übrigens um die 10 Sekunden, der gleiche Code, der mit Node.js 1,7 Sekunden braucht und die langsame Variante 20 Sekunden. Also du hast die doppelte Zeit, die benötigt wird, nur wegen den L-Caches und sogar im Browser. Also noch mehr Abstraktion gibt es eigentlich gar nicht mehr, als wenn du im Browser programmierst.

Andy Grunwald (00:39:37 - 00:39:53) Teilen

Okay, also du sagst mir jetzt gerade, dass die zeilenorientierte Programmierung bei dir deutlich schneller ist als die spaltenorientierte Programmierung in deinem Array-Index-Beispiel jetzt hier. Meine erste Frage ist, warum sollte ich dann die spaltenorientierte Variante überhaupt wählen?

Wolfi Gassler (00:39:54 - 00:41:11) Teilen

Naja, es kommt darauf an, wie du deine Daten ablegst. Wenn du dir jetzt vorstellst, du hast eine große Tabelle. Also nehmen wir mal ein ganz konkretes Beispiel. Du willst einen Recommender für Netflix-Filme bauen. Und du hast deine Daten vorliegen in einer ganz großen Tabelle. Die Spalten sind deine Filme, die Zeilen sind deine User. Und dann hast du überall die Infos, wer welcher User welchen Film gehört hat. Ist einfach eine große Matrix. Und jetzt ist die Frage, wie funktioniert dein Algorithmus? Ist er irgendwie User-basiert? Analysiert er die Filme zuerst? Und je nachdem musst du entscheiden, sind die Filme deine Spalten oder sind die Filme deine Zeilen? Und dazu musst du natürlich auch wissen, wie gehst du durch deine Daten durch? Also wie ist dein Algorithmus? Das heißt, du musst einerseits verstehen, wie funktioniert dein Algorithmus und wie speicherst du die Daten ab. Und wenn diese zwei Dinge nicht zusammenpassen, dass die Daten nicht so optimiert vorliegen, wie der Algorithmus dann durch deine Daten durchwandert, dann hast du diese vielen Cache Misses. Und daher macht es natürlich auch Sinn, sich mal durchzuüberlegen, wie liegen meine Daten wirklich im Speicher und wie greife ich darauf zu. Natürlich kann es auch sein, dass du beide Varianten brauchst. Dann müsstest du dir überlegen, was mache ich öfters oder so zum Beispiel, dass das performanter wird. Aber man kann da wirklich, indem man zwei Variablen austauscht, i und j, diese Zählvariablen, kannst du 100% Performance Gain rausholen.

Andy Grunwald (00:41:12 - 00:41:35) Teilen

Wie kann ich das Ganze denn überhaupt verifizieren, dass meine Daten im L1 oder im L4 Cache landen, dass ich primär Cache-Hits habe anstatt Cache-Misses? Gibt es da irgendwie eine Metrik? Kann ich da meinen Prometheus-Node-Exporter irgendwie draufpacken? das linux tool was ich anwenden kann wenn meine applikation läuft also wie messe.

Wolfi Gassler (00:41:35 - 00:42:14) Teilen

Ich das denn also ich habe keine ahnung wie prometheus das machen könnte aber ich bin mir sicher dass es da irgendeinen exporter gibt weil für prometheus gibt es einfach alle exporter und was man in linux exporten kann kann ja auch irgendwo nach prometheus exporten. Also grundsätzlich kann man einfach mal Performance-Tests machen mit dem Wissen, dass es diese Caches gibt und ich kann einfach, so wie ich es jetzt gemacht habe, zwei JavaScript-Programme gegeneinander laufen lassen und ich sehe, dass eines langsamer ist, das andere schneller, dann kann ich mir ausrechnen, okay, es muss irgendwas mit dem zu tun haben, mit dem Speicherzugriff. Aber da brauche ich natürlich ein gewisses Verständnis. Es gibt auch dieses Perth-Tool in Linux, einfach Perth, das Command.

Andy Grunwald (00:42:14 - 00:42:16) Teilen

So wie Performance, also die Kurzform von Performance.

Wolfi Gassler (00:42:17 - 00:43:19) Teilen

Genau, die Kurzform von Performance, dem kann ich mit übergeben, was ich da testen will, was für Caches, L1 Cache, L2 Cache und das Programm dahinter noch und dann wird das ganze Programm ausgeführt und der misst die Cache Misses und Hits am Weg. Und ich habe das auch mal getestet mit meinem Node.js Programm und man sieht da auch, dass die schnelle Variante zum Beispiel 300.000 Cache Misses hat und die nicht optimierte Variante hat eine Milliarde. Cash Misses. Also du siehst dann ganz deutlich, wie viele L1 Cash Misses du hast. Also du kannst es wirklich für ein Programm testen und siehst es dann auch, wenn du das genauer wissen willst. Aber du musst natürlich trotzdem wissen, wo du nachschaust und eine Vermutung haben, weil du musst natürlich dem Programm sagen, gib mir die Cash Misses zum Beispiel vom L1 Cash oder L2 Cash. Aber du kannst wirklich so in die Tiefe gehen mit einem beliebigen Kommando, also sogar mit JavaScript. Du musst jetzt keine Profiling-Daten oder so irgendwas aktivieren. Du kannst es wirklich so simpel auch aufrufen.

Andy Grunwald (00:43:19 - 00:43:41) Teilen

Wenn du sagst, das eine ist schneller als das andere, von welcher Order of Magnitude sprechen wir denn hier? Denn ich denke mal, dass die wenigsten Tools sich eine 10.000 x 10.000 Matrix aufbauen in einem Performance kritischen Request, wie zum Beispiel High Frequency Stock Trading oder ähnliches. Sondern, dass sowas ja... Naja, gerade beim.

Wolfi Gassler (00:43:41 - 00:44:03) Teilen

Stock Trading würde ich sagen, wo extrem viel mit Daten hantiert wird, da ist das vielleicht sogar relevant. Und wenn man natürlich jetzt auch auf den Browser geht und dieses Programm im Browser ausführt und ihr habt einmal 10 Sekunden und einmal 20 Sekunden, Das ist natürlich schon ein Riesenunterschied. Also das ist die doppelte Zeit. Und das kann natürlich auch exponentiell unter Umständen wachsen, je nachdem, was du für ein Programm schreibst.

Andy Grunwald (00:44:03 - 00:44:20) Teilen

Aber deswegen sag ich ja, die wenigsten Leute werden ja im Browser oder im HTTP-Request sich so eine zehnmal, keine Ahnung was, also eine sehr große Matrix aufbauen. Das wird ja dann irgendwo mit hoher Wahrscheinlichkeit zwischengespeichert oder die Matrix ist nur ein Zwischenschritt für irgendein weiterführendes Ergebnis und das Ergebnis wird dann gecached.

Wolfi Gassler (00:44:21 - 00:45:33) Teilen

Ja klar, also natürlich, du hast dieses Problem nur in dem Bereich, wo es halt wirklich was ausmacht. Entweder du bist in einem High-Performance-Setup, also irgendwelche Datenbankprogrammierer, die Indizes programmieren oder Caches für Datenbank. Für die ist das natürlich super relevant, wie ein Index aufgebaut wird in der Datenbank. Aber es kann natürlich für dich auch schon relevant sein, wie du was abspeicherst in der Datenbank, dass das optimiert für die Caches abgelegt wird und da kannst du dann schon viel rausholen, weil wenn deine Datenpackabfragen dann schneller werden, hilft das natürlich auch deiner Webapp am Ende, weil du einfach, keine Ahnung, zum Beispiel UUIDs optimierter ablegst in der Datenbank. Ist so ein klassisches Exempel, weil du dann einfach kleinere Werte hast, kürzere Werte und dann hast du automatisch das Prefetching von den L-Caches wieder, die die Mehrdaten reinholen können und hast da natürlich auch dann wieder Vorteile. Also es betrifft schon alle Ebenen und auch die klassischen Web-EntwicklerInnen können da genauso Speed rausholen. Und umso mehr man mit Daten arbeitet, umso wichtiger ist das natürlich, weil sich das dann einfach potenziert dementsprechend. Wenn ich irgendwo 10% raushole und ich mache das halt eine Million Mal und bin dann 10% schneller, das ist natürlich dann schon unter Umständen eine große Zahl, die da am Ende besser wird.

Andy Grunwald (00:45:33 - 00:46:21) Teilen

Wenn ich dich jetzt aber richtig verstehe, kann ich cache-freundlich programmieren, wie dein Spalten-versus-Seilen-orientiertes Beispiel da gerade. Aber ich kann jetzt nicht sagen, hey, L1-Cache, setValue und getValue. Also ich kann nicht wie in einem klassischen Webcache-System oder im Browser, im Local Storage. Also ich kann den nicht hauptsächlich von mir kontrollieren, sondern das macht alles dann... Ja, wer macht das denn eigentlich? Macht das denn das Betriebssystem, der Kernelspace, oder macht das wirklich dann die CPU? Also hat der Linux-Kernel zum Beispiel, der hat der direkten Zugriff auf L1 bis L4? Oder ist die CPU so isoliert, dass man die CPU nur als ganzes ansprechen kann und dass die CPU dann sagt, ich schiebe was, also ich schiebe meine Befehle hierhin und die Daten dahin und so.

Wolfi Gassler (00:46:21 - 00:47:18) Teilen

Also je nach CPU ist es ein bisschen unterschiedlich und manche CPUs kann man in gewisser Weise beeinflussen. Auf was für eine Ebene du das machen kannst, bin ich jetzt auch überfragt, aber kommt wahrscheinlich auch auf die CPU drauf an und was für ein Instruction Set du hast. Aber manchmal kannst du da Einfluss drauf nehmen, aber nur Einfluss insofern, dass du zum Beispiel die Ersetzungsstrategie anpassen kannst, leicht. Also wirklich zu sagen, speichere mir das jetzt in den L1 Cache oder in den L2 Cache, Das kannst du eigentlich nie machen und es ist dann ja auch noch so eine Frage zum Beispiel, was passiert denn, wenn du einen Wert schreibst, wird er im Cache geschrieben und dann in den RAM oder auf die Festplatte oder kannst du den Cache umgehen. Auch solche Dinge kannst du eigentlich als Programmierer kaum beeinflussen. Das ist wirklich alles weg abstrahiert und im Idealfall sogar so tief in der Hardware, dass du kaum etwas beeinflussen kannst, weil das einfach super optimiert ist und es wahrscheinlich sonst langsamer werden würde, wenn du das beeinflusst.

Andy Grunwald (00:47:18 - 00:47:34) Teilen

Vielleicht sollte man es auch nicht beeinflussen, weil wenn sich da sehr viele kluge Menschen Gedanken darum gemacht haben und ich komme da rum mit meinem Programm und sage da, set L1-Cache, nach mir die Sintflut, dann ist das, glaube ich, besser für das ganze Betriebssystem und für die ganzen anderen Applikationen, wenn ich meine Finger davon lasse.

Wolfi Gassler (00:47:35 - 00:48:39) Teilen

Aber wenn du cache-friendly natürlich programmierst, hat das schon einen Vorteil. Und da gibt es dann natürlich auch noch andere Elemente, vor allem wenn du dann parallele Programme hast, mehrere CPUs, geteilten Cache, ob sich die CPUs den Cache teilen oder nicht. Wenn du solche Informationen natürlich hast, kannst du schon natürlich da auch was anpassen, wobei da sind wir uns ehrlich, das brauchen meiner Meinung nach nur Leute, die wirklich auf einer sehr tiefen Ebene unterwegs sind. Und wenn du jetzt ein klassisches PHP-Programm machst, dann brauchst du das wahrscheinlich nicht und brauchst es auch nicht wissen. Aber so ein klassisches, wie du dein Array anlegst, wie du das durchläufst, das macht natürlich einen großen Unterschied aus und das macht schon Sinn, sowas zu wissen. Aber wie das dann im letzten Detail funktioniert, brauchst du meiner Meinung nach nicht wissen. Aber ein Grundverständnis hilft schon beim allgemeinen Programmieren und wenn es halt dann wirklich darum geht, eben hast du das i vorne oder das j vorne, so eine kleine Umstellung kann halt wirklich viel bedeuten. Und wenn man sowas im Hinterkopf hat, während man programmiert, dann erspart man sich halt auch später irgendwelche Performance-Optimierungen, weil es von Haus aus schon hoffentlich dann schnell genug läuft. Und vor allem, wenn man halt wirklich mit viel Daten operiert.

Andy Grunwald (00:48:40 - 00:49:17) Teilen

Ich meine, jetzt haben wir erklärt, was ein Cache ist, dass man eigentlich ohne Caches nicht mehr klarkommt, beziehungsweise das auch gar nicht beeinflussen kann, wie ein Cache funktioniert. Und jetzt sind wir mal ein bisschen tiefer in die L1 bis L4 Caches gegangen, beziehungsweise wie ich als Softwareentwickler und Softwareentwicklerin die ganze Sache ein bisschen beeinflussen kann. Wenn ich doch hier in der Programmierung jetzt unterwegs bin, dann ist das erste, was mir Google entgegenwirft, irgendwas von Amazon, CDN-Cache oder Memcache, Redis, Varnish und irgendwelche Proxys und was weiß ich eigentlich. Ist das, was du gerade beschrieben hast, alles das, was für L1 und L4 valide ist, eigentlich auch so übertragbar auf andere Caches? Also auf klassische Webcaches von heute?

Wolfi Gassler (00:49:18 - 00:50:35) Teilen

Es ist sehr schön, dass du jetzt fragst. Ein Freund von mir hat sich so beschwert, dass wir in der Proxy-Folge, oder ich besser gesagt, in der Proxy-Folge immer behauptet hat, alles ist ein Proxy. Ich würde ja auch sagen, Proxy ist ein Cache. Jetzt könnte ich gleich wieder sagen, alles ist ein Cache und es funktioniert eh alles gleich. Er hat sich da sehr beschwert, dass ich das nicht differenzierter betrachte, aber der kommt auch aus der Netzwerkecke. Also ich glaube, man könnte natürlich im Allgemeinen sagen, alle Caches funktionieren gleich, aber im Detail ist es dann natürlich doch wieder unterschiedlich und bei manchen hast du auch mehr Einfluss drauf. Bei dem CPU Cache hast du halt kaum Einfluss, außer über cache-friendly Programmierung. Wenn du natürlich deinen eigenen Cache programmierst oder irgendein Redis als Cache verwendest, dann hast du ja die Logik geschrieben, wie gecached wird, weil du entscheidest ja, wann etwas in Redis geschrieben wird, wann nicht, wann in die Datenbank. Dann schreibst du die Logik selber, da hast du natürlich mehr Einfluss. Beim Browser hast du HTTP-Headers, wo du den Cache beeinflussen kannst. hast zwar auch nicht hundertprozentig Kontrolle, also ich glaube da unterscheiden sich vor allem die unterschiedlichen Caches, wie weit du sie beeinflussen kannst. Wie kritisch das natürlich auch noch mal ist mit Ersetzungsstrategien ist auch noch mal so ein Punkt. Im Browser ist das vielleicht weniger kritisch als in einem GPU oder CPU Cache. Also da unterscheiden sich die ganzen Caches schon, aber die Grundmethoden sind, würde ich mal sagen, die gleichen.

Andy Grunwald (00:50:36 - 00:52:23) Teilen

Du hast mir auf jeden Fall Lust gemacht, mich etwas mit dem Perf-Tool auseinanderzusetzen, beziehungsweise habe ich auch gerade mal ganz kurz geguckt, Prometheus, also es gibt Prometheus-Exporte und auch der klassische Node-Exporter, das ist so der Standard Prometheus-Exporter, der auf jedem Server läuft. Der hat Metriken für das sogenannte Perf-Subsystem in Linux implementiert. Also du kriegst schon Metriken raus. Ob das jetzt eins zu eins genau die sind mit den Cache-Hits und Misti, da müsste ich nochmal nachgucken. Aber ich glaube, da können uns die ganzen Leute, die im Observability-Bereich, speziell im Linux-Perf-Bereich unterwegs sind, ein bisschen was mehr erzählen. Auf jeden Fall habe ich gerade, als du mir ein bisschen was über die Welt der CPUs erzählt hast, mal kurz gegoogelt. Und zwar mich hat eine Sache nicht losgelassen. Am Anfang hast du erzählt, Cache-Invalidierung ist ja gar nicht so hart. Ich hab mir da ein bisschen Gedanken gemacht und ich meine, wir sind ja schon auf den einen oder anderen Punkt ausgegangen, wie zum Beispiel, dass die Cache-Invalidierung performanceintensiv sein kann. Da hatten wir ja die Eviction Policies genannt, die Ersetzungsstrategien und dann die Metadaten, die da alle mitgezählt werden müssen und warum All Keys Random vielleicht eine ganz gute Idee ist. Aber das ist es ja nicht alles, weil Performance, ja, ist eine schwierige Thematik. Aber da habe ich eine schöne Seite gefunden, die auch nochmal drei weitere Gründe sagt, warum Cash-Invalidierung eine schwierige Sache ist. Und zwar... Grund 1, das Timing. Wann weiß man denn, wann dieser Cache zu invalidieren ist? Weil in der einen Richtung möchtest du natürlich die Hauptsource nicht zu oft anfragen. Das kommt darauf an, wie teuer es ist, die Hauptsource anzufragen. Auf der anderen Seite möchtest du natürlich die Daten auch nicht zu spät invalidieren, weil du dann gegebenenfalls invalide oder sogenannte Stale-Daten, also Out-of-Date-Daten rausgeben würdest.

Wolfi Gassler (00:52:23 - 00:52:58) Teilen

Wobei dieses Argument natürlich nur zählt, wenn du exklusive Caches hast, nennt sich das und nicht inklusive. Inklusive Caches heißt zum Beispiel bei dem L1 Cache, das zuerst in den L1 geschrieben wird, dann in den L2, dann in den L3, dann in den Hauptspeicher. Also du hast diese Hierarchie, da kannst du keine veralteten Daten haben, weil da immer alles durch die Hierarchie durch muss. Wenn du aber exklusive Caches hast, wie ein Redis, wo du selber entscheidest, wann hole ich was aus dem Redis, wann aus der originalen Datenbank, da kannst du dann natürlich ungültige Daten haben. Also es kommt dann da auch auf die Architektur natürlich drauf an.

Andy Grunwald (00:52:58 - 00:53:07) Teilen

Ah, das stimmt. Bei CPU hast du dann inklusive Caches wegen dieser L1 bis L4 Hierarchie und die meisten anderen Cache Systeme, Nehmen wir mal ein Web.

Wolfi Gassler (00:53:07 - 00:53:12) Teilen

Sind eigentlich exklusive, würde ich sagen. Also die, die man irgendwie selber einbaut.

Andy Grunwald (00:53:12 - 00:53:16) Teilen

Genau. Obwohl du natürlich dir selbst in deiner Infrastruktur auch ein inklusives Cache-System einbauen kannst, oder?

Wolfi Gassler (00:53:16 - 00:53:18) Teilen

Genau. Könntest du natürlich auch machen.

Andy Grunwald (00:53:18 - 00:53:31) Teilen

Also nehmen wir mal ein Varnish vorne dran. Das hat den ganzen HTML-Output. Und dann als zweiter Layer der Reddits für deine Datenbankabfragen und so weiter. Ist ja schon irgendwie so eine Art Layer-System, oder? Oder Level-System.

Wolfi Gassler (00:53:31 - 00:53:55) Teilen

Ja, aber da ist natürlich der Unterschied, dass sich hinten was ändern kann, ohne dass der Vanish das mitbekommt. Im Hauptspeicher kann sich eigentlich nichts ändern, ohne dass das der L1-Cache mitbekommt, weil das natürlich immer da durchgeht. Vor allem Problem wäre da dann wieder, wenn irgendwie verschiedene CPUs auf einen Speicher zugreifen und so weiter und da aber unterschiedliche Caches haben. Also wie man schon sieht, es wird recht schnell komplex, ja.

Andy Grunwald (00:53:56 - 00:55:16) Teilen

Grund zwei wird die Granularität genannt. Und das bezieht sich speziell darauf, dass du natürlich kontinuierlich wissen musst, welchen Datensatz du invalidieren möchtest. Du möchtest ja nicht kontinuierlich den kompletten Cache invalidieren, sondern mit hoher Wahrscheinlichkeit nur einen granularen Teil, einen Datensatz, fünf Datensätze oder ähnliches. Weil wenn du den kompletten Cache natürlich clearst, dann bist du eigentlich da am Anfang, so als hättest du keinen Cache. Deswegen die Ermittlung, welchen Cache bzw. welchen Datensatz du löschen musst oder auch aufpassen, dass du nicht bei einem Cache Clear den kompletten Datensatz löscht, weil du nur die Hälfte löschen musst, ist natürlich auch eine schwierige Thematik. Hier wird als Beispiel so eine Art deine Bestellhistorie erwähnt. Also stell dir vor, du hast halt einen Shop und da bestellt ein Kunde etwas Neues und du cached dem seine Bestellhistorie. Nur weil der Kunde etwas Neues bestellt hat, musst du ja nicht die komplette Bestellhistorie aus dem Cache löschen, sondern nur updaten. Das ist so eine Sache, dass du dann vielleicht zu viel der Daten löscht. Das ist auch ganz interessant. Kommt natürlich dann auch wieder ganz drauf an, wie legst du deine Daten ab. Legst du die einzelnen Bestellungen ab als einzelne Records oder legst du die Bestellhistorie als ein Record ab? Also, das ist natürlich dann sehr viel ... Boah, ich hasse dieses Wort, was ich jetzt sage. Datenarchitektur. Ich hasse das Wort Datenarchitektur.

Wolfi Gassler (00:55:16 - 00:55:17) Teilen

Ist doch ein schönes Wort.

Andy Grunwald (00:55:17 - 00:56:07) Teilen

Ja, und dann der dritte Grund, also neben der Performance, ist die Consistency. Was die jetzt sagen ... Stell dir vor, du hast lokale Speicher. Stell dir vor, du hast mehrere Server, und jeder Server hat seinen eigenen Cache. Und jeder Server speichert auch die gleichen Cache-Daten ab. Die Konsistenz. dass dein Cache-Record dann auf allen Servern gelöscht wird. Das ist ja auch kein einfaches Problem zu lösen, sodass du innerhalb deines Caches natürlich auch konsistent bist. Besonders bei dem heutigen Tag verteilte Systeme. Ich nenne mal Leader Election als Problem. Das könnte gegebenenfalls in die Richtung eingeordnet werden. Ja, hier Konsensus. Wenn zwei verteilte Systeme, also Wenn zwei Nodes in einem drei-Node-Cluster auf einmal beide sagen, ich bin Leader, dann würde ich sagen, dann ist da von der Konsistenz etwas aus dem Rahmen gelaufen.

Wolfi Gassler (00:56:08 - 00:57:18) Teilen

Also ganz grundsätzlich haben Caches genau das Problem, wie auch alle anderen Bereiche, wo man Daten dupliziert. Also auch in der Datenbank, wo man Daten dupliziert. Das ist ja genau das, was du eigentlich jetzt auch gerade erwähnt hast. Sobald die Daten mehrfach vorhanden habe, habe ich diese ganzen Probleme mit Konsistenz, mit Aktualität und so weiter. Und genau das ist natürlich auch das Problem auf der Cache-Ebene und da muss es vielleicht auch noch möglichst performant sein. Trotzdem bin ich immer noch nicht so überzeugt, ob das wirklich ein schweres Informatikproblem ist, weil es gibt ja auch diesen Spruch, es gibt keine schweren Informatikprobleme, aber ich kann aus jedem Problem ein schweres Problem machen, indem ich möglichst in die Tiefe gehe. Und das haben wir jetzt auch ein bisschen gemacht. Und ich glaube, man kann jedes Problem verkomplizieren. Ich glaube, ein gewisses Grundverständnis ist wichtig. Aber wenn man natürlich in die Tiefe geht, wird alles immer komplizierter und komplexer. Aber meine These ist natürlich, wenn Caching kompliziert ist und ihr eine Datenbank die Caching verwendet, dann müsst ihr neben dem Caching auch noch andere Sachen beachten und ist dadurch automatisch komplizierter. Also ist Datenbank ein eindeutiges komplizierteres Problem in der Informatik als Caching, weil es Caching inkludiert. So, jetzt sag mal da dagegen was.

Andy Grunwald (00:57:18 - 00:58:07) Teilen

Also ich glaube schon, dass Cache-Systeme kompliziert sein können. Ich glaube, es kommt aber wirklich ganz darauf an, wie du, wie baust du es auf, welchen Use-Case, blabliblub, typische Berater-Antwort, it depends. Also zum Beispiel hast du schon mal die Memcache-Slab-Allokation verstanden, ja? Also der geht ja auch so tief, wie legt der seine Speicherbereiche im Memory ab, damit das effizient ist, blabliblub. Also ich glaube schon, dass das sehr, sehr, sehr tief reingehen kann. Genauso wie bei den Eviction-Policies, ja, es gibt eine eigene Wikipedia-Seite. Und je nach Use Case kann das so und so und so sein. Also ich kann mir schon vorstellen, dass das eine harte Aufgabe ist, aber ich bin da, ja ein bisschen teile ich das mit dir. Ich sage es total ungern, aber ich stimme dir ein bisschen zu, dass du jedes Problem hart machen kannst, wobei ich dir nicht zustimme ist, dass Cache Invalidierung kein hartes Problem ist, weil ich denke, das ist schon ein hartes Problem.

Wolfi Gassler (00:58:07 - 00:58:09) Teilen

Ja, ist natürlich immer die Frage, was ein hartes Problem ist.

Andy Grunwald (00:58:10 - 00:58:15) Teilen

Ja, ich bin dumm, deswegen ist ziemlich viel für mich hart. Ich hab nur Bachelor.

Wolfi Gassler (00:58:15 - 00:58:32) Teilen

Ich sag ja, es ist immer relativ natürlich. Aber wir würden uns natürlich freuen, wenn ihr uns auch mal erklärt, was ein hartes Problem ist. Und wahrscheinlich haben wir ganz viele Bereiche auch vergessen von dem ganzen Caching-Thema. Also würden wir uns freuen auf Feedback, am besten in unserer Community. Link dazu findet ihr natürlich in den Show Notes, wie immer.

Andy Grunwald (00:58:32 - 00:58:42) Teilen

Ich gehe auf jeden Fall jetzt zurück in meine IDE und kontrolliere erstmal meinen Source-Code, wie lege ich eigentlich meine Matrix-Operationen alle so ab und meine Matrix-Datenstrukturen.

Wolfi Gassler (00:58:42 - 00:58:48) Teilen

Also ich kann dir gern den Source-Code schicken, den habe ich sogar in mehreren Programmiersprachen. Das heißt, du kannst dir... Den packst.

Andy Grunwald (00:58:48 - 00:58:53) Teilen

Du doch hoffentlich sowieso auf einen GitHub-GIS, damit wir den unten in den Journals verlinken können, oder?

Wolfi Gassler (00:58:53 - 00:58:57) Teilen

Also wenn jemand in unserer Community danach fragt, stelle ich den natürlich gerne zur Verfügung.

Andy Grunwald (00:58:57 - 00:59:02) Teilen

Das war es wieder von uns für diese Woche. Vielen Dank und wir sagen bis bald. Tschüss.

Wolfi Gassler (00:59:02 - 00:59:12) Teilen

Ciao. Ich habe übrigens den Code leider nicht in Go. Ich habe viele Sprachen aber in Go nicht an. Du musst den jetzt in Go schreiben. Wenn jemand in der Community nach Go fragt, musst du den providen.

Andy Grunwald (00:59:12 - 00:59:24) Teilen

Pack die ganze Nacht mal auf Gist und dann mache ich dir den in Go. Schreib mir ein kleines Tutorial, wie ich das messe. Ist jetzt kein Witz. Also ich weiß das ja gerade wirklich nicht. Und dann mache ich das mal in Go und dann können wir mal was schauen, ja?

Wolfi Gassler (00:59:24 - 00:59:28) Teilen

Wer jetzt noch immer dabei ist, Andi macht schon wieder ein Riesenprojekt aus der ganzen Sache.

Andy Grunwald (00:59:28 - 00:59:37) Teilen

Nee, ich möchte Leute educaten, ja? Und du kannst ja wohl auch mal ein paar Zeilen, wie welche Commands man ausführen kann, in den Readme packen. Kriegst ja wohl gerade noch mal hin. So, jetzt aber. Tschüss. Ciao.