 Das ist 14.30 Uhr. Wir fangen an mit dem Vortrag. Hallo, schön, dass ihr gekommen seid. Mein Name ist Michael Stapelberg. Der Vortrag geht über Debian Code Search Instant. Damit ich ein bisschen besser weiß, vor wem ich spreche, könnt ihr bitte alle mal die Hand heben, wer schon mal Debian Code Search benutzt hat. Zwei, drei, vier, okay. Wer hat schon mal davon gehört? Okay. Und wer hat gar keine Ahnung davon? Okay, gut. Für die vier Hände, die gerade hochgegangen sind, reiß ich nochmal ganz kurz ab, worum es eigentlich geht. Und danach konzentriere ich mich hauptsächlich auf das, was seit dem letzten Vortrag vor zwei Jahren dazugekommen ist. Gut. Hier ist nochmal der Vortrag verlinkt, Video und Folien. Das heißt, wer sich das ganze Video nicht anschauen möchte, das gibt es auch mit englischen Untertiteln. Übrigens kann sie einfach die Folien kurz anschauen. Ganz kurz nochmal. Die Motivation überhaupt. Warum braucht man überhaupt eine Code-Suchmaschine? Es gibt recht viele Anwendungsfälle, die ich in meiner tagtäglichen Arbeit mit Open-Source-Software mehr oder weniger häufig habe. Oft ist es so, man bekommt zum Beispiel einen Bug-Report und man sieht darin, okay, hier ist ein Stacktrace und das sind jetzt irgendwie drei, vier Funktionen und dann sieht man halt die Funktionsnamen. Und dann möchte man herausfinden, was tun denn eigentlich diese Funktionen, damit man den Fehler besser verstehen kann. Und damit man nicht bei jeder Funktion schauen muss, okay, in welchem Paket ist sie definiert, sich den Paketqualtext runterladen muss, dann den Paketqualtext indexieren oder einfach direkt durchsuchen, gibt es eben eine Code-Suchmaschine. Mit der kann man also schnell und einfach Funktionen auffinden, die sich in irgendeinem beliebigen Open-Source-Quell-Paket befinden, welches Teil von Debian ist. Das ist nicht alles. Vielleicht möchte man auch genereller suchen. Vielleicht möchte man ein Algorithmus finden, der das implementiert, was man gerade möchte. Vielleicht möchte man irgendwie Heapsort finden, geschrieben in C oder geschrieben in Perl oder was auch immer. Dafür kann man das auch verwenden. Und zu guter Letzt ist noch ein wichtiger Anwendungsfall von den generellen Anwendungsfällen, dass man damit auch schauen kann, welche Pakete benutzen eigentlich diese Funktionen, die ich in meiner Library zur Verfügung stelle. Damit man besser sehen kann, okay, ich muss jetzt die APN dann, wie viele Pakete muss ich anfassen oder muss ich dann eine neue Major-AP Version machen, solche Sachen. Und zu guter Letzt in Debian spezifisch, gibt es natürlich auch Use-Cases. Die Tatsache, dass das Projekt Debian Code-Such heißt, kommt nicht von ungefähr. Also wir benutzen alle Pakete, die in Debian sind, dass das alles freie Software ist. Da hat man dann keine Probleme. Man muss die Software nicht crawlen. Man hat keine Probleme mit der Wiederveröffentlichung des Quelltexts und so was. Und zudem indexieren wir aber auch die Debian-spezifischen Änderungen an den Paketen. Soll bedeuten, wenn man gerade einen Debian-Paket baut und suchen will, okay, wie mache ich jetzt eigentlich diese eine Funktion in dem Gerüst, was das Debian Packaging erlaubt, kann man auch die Konten- und Suchmaschine benutzen, um Beispiele dafür zu finden. Wichtig zu sagen ist noch, dass es eine Regular-Expression-Suchmaschine ist. Das soll bedeuten, man kann wie bei GREP oder wie bei ganz vielen Editorien eine Regular-Expression angeben und hat damit ein sehr mächtiges Werkzeug an der Hand, um ganz genau die Stelle zu finden, die man eigentlich sucht. Das ist ein bisschen wichtig, weil es auch beeinflusst, wie die Architektur der ganzen Suchmaschine ist und welche Software wir zur Verfügung haben, die wir überhaupt benutzen können, um das Ganze umzusetzen. Die Grundlage für diese Regular-Expression-Suche ist hier verlinkt. Das ist ein Projekt von Russ Cox im Paket, das nennt sich Code Search. Ich habe im Wesentlichen dieses Paket genommen, habe es für unseren Anwendungsfall optimiert, also für große Datenmengen, habe einen Webfront-Entrum rumgepackt und alle weiteren Änderungen an der Architektur werde ich euch gleich vorstellen. Am Anfang hatte das ganze Projekt, das Projekt habe ich angefangen, als meine Bachelorarbeit damals in meinem Studium, und ich hatte damals meinen Prof gefragt, so, hey, wo kann ich das denn hosten? Haben wir vielleicht ein Server hier, und da hat er mir stark von abgeraten. Also es scheint, großer bürokratischer Aufwand zu sein, dort einen Server zu bekommen, und selbst wenn ich einen bekommen hätte, dann wäre das vielleicht ein paar Monate, nachdem ich schon angefangen hätte mit der Arbeit und nachdem ich dann meinen Studium abgeschlossen habe, hätte ich dir vielleicht keinen Zugriff mehr drauf. Das heißt, dann habe ich es einfach ganz pragmatisch auf meinen Privatserver gepackt und da lief das dann auch eine ganze Weile. Damals hatte ich das so gemacht, dass ich den Index einmal die Woche neu aktualisiert hatte. Und dann habe ich das dann auch noch eingeladen. Dann kam das erst unter Umständen eine Woche später in der Coatshoopmaschine zum Vorschein. Das ist natürlich ärgerlich und auch einer der Gründe, warum ich diesen Vortrag halte, weil ich erklären möchte, wie geht das besser und wie habe ich es tatsächlich gelöst. Gut, ich habe hier ein Video eingebattet, weil das die einzige Art und Weise ist, wie ich zeigen kann, wie die Coatshoopmaschine früher funktioniert hat. Das ist von meinem Vortrag von vor zwei Jahren. Mein Ziel ist es, dass jetzt also die Vortragsaufnahme von heute ist und wenn ich in zwei Jahren wieder ein Vortrag halte, ihr versteht. Okay, also was ich damals gezeigt habe, ich habe damals das Publikum befragt, wonach soll ich suchen? Hab den Suchtbegriff eingegeben, jetzt achtet ihr drauf, dauert eins, zwei, drei Sekunden vielleicht und dann habe ich hier die Suchergebnisse bekommen. Und dann sieht man hier, es ist einfach so eine Liste, die ersten paar Treffer waren alle aus dem Paket EG-Lipzee, weil die Suchanfrage string-free war also nur so als kurzen Überblick, wie war das früher? Und jetzt kann ich mal noch kurz zeigen, wie sieht das Ganze heute aus. Wenn ich auf code-search.debian.net gehe, sehe ich immer noch die altbekannte Suchmaske. Wenn ich SDR-Frye eingebe, sieht man okay, das sieht es schon deutlich anders aus. Entschuldigung mich, das ist so klein, es soll vielleicht ein bisschen reinzoomen. Man sieht immer noch okay, G-Lipzee sind die ersten paar Treffer, aber man sieht auch, man kann hier den Haken reinmachen und dann sehe ich die Suchergebnisse gruppiert bei den Debian-Paketen, in denen sie erscheinen. Und das Ganze ging auch deutlich schneller und das Ganze sieht auch deutlich ansprechender aus. Wir machen hier mal weiter. Jetzt zur eigentlichen Agenda des Vortrags heute. Zum einen möchte ich kurz noch darauf eingehen, wie hat sich das Projekt bewährt? Ich habe das angefangen, als meine Bachelorarbeit und dachte, das ist ein Tool, was ich auf jeden Fall haben will, das ist ein Tool, was ich persönlich brauche. Allein dafür lohnt es sich wahrscheinlich schon und dann schauen wir mal. Und wie sich das in der Praxis herausgestellt hat, gehe ich gleich darauf ein. Dann zeige ich euch ganz kurz das Monitoring, was es für das System mittlerweile gibt. Monitoring ist unglaublich wichtig, damit man überhaupt weiß, was kann man an dem System machen, wo befindet sich das System gerade und wo will ich hin und dann kann man das messen und vergleichen und optimieren. Dann werde ich die alte und neue Hardware, die Rackspace uns zur Verfügung gestellt hat, vorstellen, die alte Architektur für das Feature eingehen, welches ich Instant Indexing nenne. Dann gehe ich kurz auf Streaming Queries ein, das nenne ich Instant Results. Aus den beiden Funktionen kam auch der Vortragstitel und der Codename für die neue Version Debian Code Search Instant. Dann erkläre ich ein bisschen was über die Optimierung, die wir vorgenommen haben und dann gebe ich noch einen Ausblick, was könnte man in Zukunft noch machen an dem Projekt, wo gibt es noch Potenzial? So wenn ihr Fragen habt, die unglaublich wichtig sind für den weiteren Verlauf und das Projekt rein. Ansonsten haben wir am Ende des Vortrags noch Zeit für generelle Fragen. Okay, zunächst zum Nutzen. Ich möchte nicht unglaublich viel damit angeben, aber wenn man sich das anschaut, wie das verlaufen ist, bin ich durchaus sehr zufrieden damit. Wir bekommen momentan ca. 125 Suchanfragen täglich im Schnitt, also mal mehr, mal weniger, das ist gemessen über das letzte halbe Jahr. Da denkt man sich jetzt, wenn man mit großen Diensten zu tun hat, naja, das ist ja nichts. In queries per second ausgedrückt ist das verschwinden gering, aber man muss sich überlegen, das sind immer 125 Suchanfragen, also 125 mal am Tag hat Software, die wir gemacht haben, vielleicht Leuten geholfen, was rauszufinden, was sie vorher nicht rausfinden konnten. Und immer wenn ich E-Mails bekomme von Leuten, die sich über irgendwas beschweren, weil irgendwie einen Back in der Software ist oder die eine Frage haben oder die mich loben, dann bitte ich sie, dass sie doch auf dieser Wiki-Seite, Debian Code Search, im Schnitt ist, ein kurzes Testimonial hinterlassen. Zum einen, dass andere Leute besser einschätzen können, wie akzeptiert dieser Dienst ist in Debian und zum anderen, weil das auch effektiv wirklich hilft. Also wenn ich zum Beispiel mich an DSR wende, also die Debian System Administrators und denen sage, hey, ich würde gerne den Dienst auf Debian Hardware hausten, dann sagen die, naja, zeig uns doch zuerst mal, dass das überhaupt irgendjemand benutzt. Und dafür sind diese Testimonials unter anderem wichtig, aber auch, weil sie eine schöne Motivation sind und das hat an dem Projekt was zu machen, hey, das hilft vielen Leuten. Schau mal, die Leute finden das gut. Und eins möchte ich hier kurz vorstellen, da schrieb Charles Plessie, ein weiterer Debian Entwickler, Code Search is becoming an essential part of the Debian infrastructure that allows one to quickly answer questions that would otherwise have needed tedious grabs in the LinkedIn Lab. Und das Zitat geht noch weiter und da sagt er dann noch, wie schön, dass Mailing-Listen-Diskussionen untermauert mit Daten. Und das ist natürlich was, was ich persönlich super finde, dass man nicht mehr Mailing-Listen-Diskussionen hat, die einfach subjektiv hin- und hergehen oder die Flamewurst sind oder mit Behauptungen, die niemand verrifiziert, sondern jetzt kommen die Leute tatsächlich und sagen so, hey, wir haben hier folgendes Problem und hier ist der Link auf Debian Code Search ums zu beweisen. Und das finde ich eine coole Sache. Und es ist auch noch wichtig zu erwähnen, finde ich, dass das Projekt nicht nur Leuten in Debian helft, sondern wir haben auch Testimonials von Leuten, die an Tor entwickeln, die an OpenBSD entwickeln, die einfach generell Libraries entwickeln. Also das ist wirklich, hat sich ein Problem. Gut, jetzt aber erstmal darum, warum muss man das überhaupt verbessern? Was stimmt da in der alten Version nicht? Der Top-Feature-Request, den wir bekommen haben, war, dass man Suchergebnisse nach Paketgruppieren können soll. Das heißt, das, was ich gerade gezeigt habe, dass man den Haken reinmachen kann und sagen kann, ich möchte nur wissen, diese Funktion in welchen Paketen wird die verwendet. Und dann überhaupt erst, schaue ich mir vielleicht an, okay, innerhalb dieses Paket ist jetzt welche Treffer habe ich da. Und das war sehr mühsam, da durchzugehen. Und das war eben der Top-Feature-Request. Der Top-Bug, den wir bekommen haben, war, dass wir am Anfang in 60 Sekunden Timeout hatten für Suchernfragen. Und einige Anfragen haben einfach länger als 60 Sekunden gedauert, um sie durchzuführen. Und das trotz der Einstrengungen, auf die ich gleich noch eingehen werde. Das heißt, es gab also viele Sachen, die Leute machen wollten, die sie einfach nicht machen konnten, mit der Software, so wie es damals war. Und deswegen haben wir uns überlegt, wie kann man das Ganze verbessern. So, zum Monitoring. Das Monitoring ist, wie ich schon angedeutet habe, Grundstein. Das hatte ich am Anfang nicht. Am Anfang habe ich einfach die Software gestartet und dann gehofft, dass alles läuft. Und meistens ist auch alles glatt gegangen. Aber mit Monitoring ist das Ganze viel besser. Zum einen kann man sich automatisch benachrichtigen lassen, wenn irgendwas gerade nicht stimmt. Und über die Art und Weise habe ich schon mehrfach die Sache eigentlich größtenteils rund. Ich habe seit Monaten schon keine Alerts mehr bekommen. Das ist eine gute Sache. Aber zum anderen kann man damit auch Messungen anstellen. Also nicht nur Alerting, sondern auch Messen. Wie ist die Performance des Systems? Wie lange Dauernsuchanfragen im Normalfall, im Mittel oder im 99. Percentile. Das ist wichtig, weil man da wirklich vorher- und nachher Vergleiche machen kann. Ich kann jetzt an der Softwareänderung durchführen. Ich kann sagen, okay, ich deploy das und wie haben sich die Queries, die die Nutzer tatsächlich absetzen, so verhalten. Deswegen finde ich das so wichtig. Und ich möchte kurz zeigen, wie das aussieht. Ich habe das implementiert mit Grafana. Ich zoom hier auch noch mal ein bisschen rein. Man sieht hier ein recht großes Dashboard. Also hier oben ist es ein bisschen schlecht zu sehen, weil das alles schwarz ist. Aber es sieht cooler aus. Queries Per Second sieht man, was eigentlich so los auf dem System ist. Currently Active Queries, hier würde man sehen, wenn hier einfach eine Flatline zu sehen ist, dann ist das System stecken geblieben an einem Query. Das wäre schlecht. Hier sieht man die Query Latents. Also man sieht, es gibt hier Ausreißer. 8,2 Minuten, das war eine sehr teure Suchanfrage. Aber das Allermeiste liegt eigentlich hier irgendwie mit, keine Ahnung, unter 100 Millisekunden. Das ist recht gut. Also unter 100 Millisekunden, das ist so die Grenze, wo Menschen das noch als das passiert sofort wahrnehmen. Also wenn ich in der Lage bin, wow, da bin ich der limitierende Faktor und nicht der Computer. Und das ist wo wir hin wollen. Also jede Suchanfrage sollte im Idealfall so sein. Und dann gibt es noch ein paar andere Sachen, auf die ich jetzt nicht genau eingehe. Also man kann sich zum Beispiel anschauen, die Readband with, wie viel hat das System gelesen für Suchanfragen, wie viel Freier Speicherplatz gibt es usw. Also wenn euch das interessiert, gibt es noch einen Vortrag von mir. Morgen um 17.30 Uhr über Prometheus, wie das funktioniert im Großen und Ganzen ist, dass ich verschiedene Prozesse habe, die zeige ich euch gleich noch in der Architekturübersicht und die exportieren einfach Metriken, also Anzahl an Quellpaketen und so weiter und das System scrape die dann und baut daraus diese schönen Grafen. Das ist ganz nett. Okay, zur Hardware. Ich habe am Anfang gesagt, am Anfang lief das Ganze auf meinem privaten Server. Der private Server hat irgendwie, ich habe 8 Gigabyte RAM reserviert und ich habe den ersten Preis mit. Deswegen habe ich dann zuerst bei DSR angefragt und dann ist es, nein, in Debian haben wir leider keinen Flash-Speicher zur Verfügung, den du benutzen könntest und dann habe ich mit Arbeitskollegen darüber geredet und die meinten dann irgendwann, hey, ich habe gehört, dass Rackspace eigentlich recht open source freundlich ist und fragt doch die mal an, ob da irgendwas geht. Und dann habe ich mit Rackspace Kontakt aufgenommen und die waren tatsächlich sehr freundlich und haben uns einen Deal gegeben, bei dem sie uns eine gewisse Menge an Credits geben, sozusagen auf ihrer Public Cloud Infrastructure und dort können wir dann beliebige Dienste benutzen. Ich habe dort jetzt einfach sieben verschiedene VMs am Laufen, erkläre gleich noch, wie die zusammenhängen und das passt in unser Budget und jetzt ist alles viel besser. Das Ganze läuft seit Ende 2013 damals noch mit der alten Generation an Hardware von Rackspace und mittlerweile auf der neuen Generation. Als ich das damals also gemacht habe, also als ich umgezogen habe von meinem privaten Server auf die Rackspace VMs, habe ich den Trigram Index, also den Index, der zunächst befragt wird, wenn du eine regular expression reingibst, der dir dann sagt, in folgenden Dateien könnten Suchergebnisse sein, den habe ich auf sechs Rechner verteilt. So war das auch am Anfang ursprünglich gedacht, also in meiner Bachelorarbeit habe ich das so beschrieben, aber ich konnte es bis davor eben einfach nicht umsetzen. Und was dann passiert, ist, dass die Suche also parallelisiert wird. Das heißt, er fragt alle diese sechs verschiedene VMs gleichzeitig an, bekommt die Ergebnisse mehr oder weniger synchron zurück und kann dann auf einem Blog-Storage-Volumen den kompletten Source Code durchsuchen. Das Blog-Storage-Volumen ist basierend auf Flash-Beicher, deswegen haben wir das genommen, also haben nicht den Source lokal auf die verschiedene VMs verteilt, weil die rotierende Festplatten hatten damals, sondern hatten uns einen so einen Blog-Storage-Volumen gemietet. Und das kann man immer nur an Einrechner anschließen. Das heißt, die Suche war am Anfang parallel auf den Index und ist dann aber wieder in den Flaschenhals gelaufen, nämlich das Blog-Storage-Volumen. Frage? Die Trigramme sind jeweils drei Zeichen hintereinander, also Wuchtstücke von einem Wort. Da kannst du dir gerne noch mal den alten Vortrag anschauen, da habe ich das on-detail erklärt. Oder auch die Bachelorarbeit anschauen. Oder später noch mal fragen, dann erklär ich es gerne noch mal. Okay, die Suche wurde also durch die neue Hardware parallel, hatte aber dann wieder ein Flaschenhals. Zudem war es auch so, dass ich jede Woche komplett neu deployte. Also ich hatte ja vorher gesagt, ich hatte, ich hatte, ich hatte, ich hatte, jede Woche einmal den Index aktualisiert. Das lief einfach so, ich hatte so einen Shell Script, ich hatte das ausgeführt. Das hat dann den Debian Mirror aktualisiert, den ich hatte. Das ist komplett durch die alle, durch alle Quelltext-Dateien durchgelaufen, hat den Index aufgebaut, hat danach den alten Index auf die Seite geschoben, den neuen Index an dessen Stelle gepackt, hat geschaut, wenn ich jetzt alle Tasksneustarte funktioniert, dann noch eine Suchanfrage und dann wurde das deployt. Und das ist zum einen blöd, weil es halt ein menschlicher Protokoll hat. Also ich muss da jede Woche wirklich dran sein. Und wenn ich mal eine Woche in Urlaub bin, dann ist Debian Code Search alt, das ist schlecht. Und zum anderen ist er häufig schiefgegangen. Also es ist immer mal irgendwas passiert. Zum Beispiel konnte er den Debian Mirror nicht updateen, weil irgendein Mirror einen Timeout hatte und der Mirror ist nicht schlau genug, um das dann nochmal zu probieren. Gut, da hätte ich jetzt irgendwie noch mehr Intelligenz in das Script stecken können und so weiter. Aber ich dachte, das ist eigentlich keine Lösung, an der ich festhalten möchte. Ich bin dann, als ich die neue Hardware von Rackspace bekommen hatte, umgestiegen auf ein Modell, in dem ich jede Woche komplett neu deployt hatte. Was ist der Vorteil davon? Vorher war es so, dass während ich den Index erstellt habe, ist alles andere langsam geworden. Weil das Index erstellen kostet halt CPU-Zeit und IO-Time und so was. Und deswegen haben wir das auch nur einmal in der Woche gemacht. Weil sonst schränkt man halt die Qualität der Suchmaschine ein, für die Nutzer, die sie benutzen wollen, während ich den Index aktualisiere. Das war also so ein Trade-off zwischen, wie oft können wir das machen? Aber theoretisch ist eigentlich das Idealmodell, dass es gar keinen so einen Delay gibt. Dass man direkt, wenn neue Pakete verfügt werden, die direkt durchsuchen kann. Bei Rackspace habe ich dann gesagt, jetzt können wir jede Woche neu deployen. Das heißt, ich habe mir automatisiert, jede Woche sieben neue Forms geklickt, habe dort die komplette Software installieren lassen über ein Programm, was das gemacht hat und habe dann einfach den DNS umgebogen. Von den alten Forms auf die neue Forms habe dann die alten gelöscht. Zum einen hatte man nie eine Abweichung zwischen Infrastruktur, wie sie sein sollte und dem Code, der sie macht. Man war immer in der Lage, von 0 auf 100 eine neue Deben-Code-Search-Instanz einfach zu erstellen, weil das ist eh jede Woche passiert und gäbe es da einen Fehler, wäre der Service halt kaputt. Und zum anderen ist das, was wir vorher hatten, dass die Suchmaschine langsam wird, während wir den Index erstellen, ist nicht mehr der Fall, weil das auf komplett separate Hardware läuft. Außerdem ist mir dann aufgefallen, dass in diesem neuen Deploy-Modell Depmirror ein Flaschenhals wurde. Also der Punkt ist, je länger ich in dem Deploy-Zustand bin, also je länger dieses Script dauert, desto mehr zahle ich am Ende des Monats. Ich zahle es zwar nicht effektiv, aber es geht in mein Budget mit ein und je weniger Budget ich verbrauche für den Normalzustand, desto mehr coole Hardware oder coole Features kann ich mir dazuklicken. Das heißt, ich bin schon daran interessiert, dass es schnell geht, diesen Mirror runterzuladen und mit Depmirror habe ich eben nur so um die 100 MBit erreichen können. Jetzt ist es aber so, dass bei Rackspace die VMs, die ich hatte, mit einem Gigabit ans Internet angebunden sind. Das ist natürlich Verschwendung und das Ärger dahin, wenn man nur 100 MBit benutzen kann. Und deswegen habe ich hier einen Blogpost verlinkt über einen Tool, was ich geschrieben hatte, was ein Ersatz ist für Depmirror und das ist in Go geschrieben und verwendet ein paar kleine Tricks, wie HTP Pipelining, eine geschickte Mirrorauswahl und so was. Ich finde an sowas zu arbeiten, wo man einfach schöne Hardware zum Spielen bekommt und dann kann man sie mal richtig auslasten. Okay, zur alten Architektur. Wie ist das eigentlich aufgebaut? Das ist hauptsächlich deswegen, damit ihr verstehen könnt, wie die neue Architektur sich von der alten unterscheidet. Es war so hier auf der rechten Seite ist diese Box, die nennt sich RSDeploy. Das steht für RackspaceDeploy. Also das war das Programm, welches die ganzen neuen Maschinen, die hier in der Mitte und auf der linken Seite sind, es gibt verschiedene Arten von Maschinen. Es gibt zum einen das Source-Backend. Das war die Maschine, die das Block-Storage-Volume angebunden hatte. Also dort ist der ganze Quelltext von Debian verfügbar. Der wurde also runtergeladen, entpackt, dort gespeichert. Dann gibt es das Webfrontend. Das ist die eigentliche Anwendungslogik sozusagen. Die hat zunächst die Index-Backends befragt. Das war das, was ich auf sechs verschiedene VMs verteilt hatte. Und der Index muss eben im Ramm liegen, deswegen auf die verschiedenen VMs verteilt, damit ich zum einen viel Ramm nutzen kann, ohne viel Geld zu bezahlen für eine VM, die viel Ramm am Stück hat. Also so konnte ich das aufteilen. Und zum anderen, damit der Parallel befragt werden kann, damit ich eine schnellere Suche implementieren kann. Also das Webfrontend fragt die Index-Backends an, sagt, hey, gib mir mal alle potenziellen Suchtreffer. Und mit der Liste geht es dann zum Source-Backend und sagt, okay, jetzt mit dieser Regular Expression durchsucht auch mal diese Dateien. Und das macht er dann und dann bereitet das Webfrontend die Ergebnisliste auf, schickt sie zurück an den EngineX, der hier als Reverse Proxy fungiert und beantwortet die Benutzeranfrage, um die es eigentlich geht. Das Schöne ist, dass wir in dem EngineX die ganzen statischen Assets ausliefern können und caching können, so wie man das halt so kennt von so einer Web-Infrastruktur. Und der Rest passiert dann halt hier. Okay, die neue Hardware, also das nennt sich Next-Generation-Hardware by Rackspace, das wurde eingeführt eine Weile, nachdem ich das ganze alte Modell fertig hatte, und dann dachte ich, oh, jetzt nicht schon wieder alles anpassen, und dann habe ich das noch nicht gelassen und mir überlegt, okay, wie kann man die neue Hardware ausreizen. Und was es sich hier behandelt, ist VMs, die einen Quadcore Intellyxeon E5 zur Verfügung haben, mit jeweils 4 GB RAM, mit 80 GB lokaler SSD, und das ist wirklich ein wichtiger Punkt, weil die lokalen SSDs größer als 5.000 IOPS erreichen, also gar nicht so schlecht. Und im Vergleich zu Block-Storage, was über das Netz angebunden war, ist die Latents viel, viel geringer. Also das Vorhandensein von diesen SSDs ist eigentlich das, was uns die komplette neue Architektur erlaubt. Ohne das hätte es nicht geklappt. Und die Netzanbindung ist 800M mit zwischen den ganzen VMs und auch ins Internet raus, aber das ist nicht mehr so wichtig. Gut, nach wie vor haben wir 6 Instanzen für den Index, aber der Unterschied ist, dass diese 6 Instanzen jetzt auch den Quelltext aufteilen. Also der Quelltext wird aufgeteilt, also es wird einfach gehasht, wie ist das Paket, also der Paketpfad, und dann wird entschieden, okay, du hast den Hashtone, so du kommst auf diese Maschine und so wird das relativ gleich verteilt. Weiterhin gibt es eine Instanz für das Frontend und es gibt eine Instanz für das Monitoring. Okay, die Idee hinter dem Instant Indexing ist jetzt, dass wir nicht wöchentlich oder täglich oder stündlich oder so den Index neu bauen, sondern dass wir paketweise den Index so häufig wie es geht aktualisieren. Und das Problem damit, warum ich das nicht von Anfang an so gestaltet habe, ist, dass das Indexformat, was das Co-Search-Paket benutzt, ausgelegt ist. Das ging also einfach nicht. Es war einfach nicht der Use Case, für den das Paket ursprünglich geschrieben war. Und weil so eine Bachelorarbeit irgendwann fertig werden muss, habe ich da keine Zeit für gehabt, das direkt richtig zu machen. Was jetzt aber der Fall ist, ist, dass wir, wenn ihr euch das mal ausrechnet, wenn ihr 6 x 80 Gigabyte habt, insgesamt an SSD Storage und ihr nur 140 Gigabyte speichern müsst, dann könnt ihr auch locker doppelt so viel speichern und stellen den Index so, dass wir für jedes Paket einen Index erstellen und dann merken wir diese Indizes am Ende zusammen in einen großen Index. Das heißt, man hat einen Storage Overhead, aber das ist okay, weil wir einfach genug Hardware haben, um das Problem zu erschlagen. Und damit wir überhaupt diese ganzen Indices merken können in einen großen Index, musste ich erstmal einen neuen Merch-Algorithmus implementieren in dem Co-Search-Paket. Die Idee war dann, dass er bei mehreren Dateien einfach immer eine mehr dazugemerkt hat und das dauert ewig, wenn man das auf diese Datenmenge macht. Und deswegen habe ich mir eine Zugfahrt genommen und ein paar Stunden gehackt an einem Algorithmus, der eben binnen fünf Minuten alle diese kleinen Index-Dateien zu einer großen Zusammenösch. Also wir reden hier von so ungefähr 2 Gigabyte Index-Datei. Und das kann man sicherlich noch effizienter machen, aber das ist jetzt erstmal effizient genug. Und dann können wir uns gleich noch überlegen, wie lange die komplette Latence ist und wie lange das Paket wird hochgeladen und ein neues Paket ist durchsuchbar. Von der Architektur her ist es jetzt so, dass ich mich entschlossen habe, einen neuen Baustein einzuführen, nämlich den DCS Package Importer. Was der macht, ist der Least-Eindebian-Paket. Entpackt das Debian-Paket indexiert ist und merkt am Ende dann auch noch in diesen vollen Index. Das heißt, es läuft ein Package Importer auf jeder Vm. Und wenn ich sage, er leist ein Debian-Paket, dann bedeutet es tatsächlich, das ist ein Debian-Paket. Über diese Schnittstelle schickt man ein komplettes Debian-Paket, also alle Dateien, die das Paket ausmachen, die DSC-Datei, den Original-Tarball und den Debian-Spezifischen-Tarball und dann, sobald der Package Importer alle Dateien hat, entpackt er das, indexiert es und merkt es. Das Index-Backend wurde dahingehend verändert, dass es ohne, dass man es neu starten muss, einen neuen, vollen Index laden kann. Das heißt, da gibt es jetzt eine Funktion, bei der man sagen kann, hey, wenn es nicht klappt, dann klappt es halt nicht und er ist noch auf dem alten Index, sodass wir also von der Verfügbarkeit kein Problem haben, wenn es mal Fehler in dem System gibt, ist nicht so, dass das unbeaufsichtig läuft und die ganze Zeit kaputt geht. Das ist quasi so als Safeguard der Mechanismus hier. Weiterhin gibt es einen neuen Baustein namens FIDER. Was der macht, ist der Pold stündlich neue Packages, also jede Stunde ruft er auf einem Debian-Mirror das Packages-File ab welche Pakete habt ihr schon auf euren Maschinen, schaut dann welche sind noch nicht geladen, lädt die runter und füttert sie in den Package-Importer, daher der Name FIDER. Damit der FIDER aber nicht nur stündlich pollen muss, sondern damit es noch mal ein Ticken schneller geht, gibt es jetzt noch einen Baustein, der nennt sich Tail-Fat Message und der schaut auf einem Message-Bus, der Fat Message heißt, das ist so ein Zero-MQ basierter Message-Bus, der ursprünglich aus Fedora kam, aber seit einem Summer-of-Code-Projekt auch in Debian verfügbar ist. Da werden neue Paket-Uploads bereitgestellt und diese Benachrichtigung nimmt dann das Tail-Fat Message auf und sagt dem FIDER, hey, hier habe ich gehört, da wurde gerade ein neues Paket hochgeladen, schaut doch mal, ob du das findest und der FIDER schaut dann, dass er im Debian-Mirror in der Incoming-Q noch das Paket direkt wieder daraus holt und dann indexiert er das eben direkt. Also es muss noch nicht mal in Debian offiziell aufgenommen sein, da können wir es schon durchsuchen. Okay, und das Source-Backend wurde dahingehend geändert, dass es jetzt in ein lokales Index-Backend anfragt, weil jetzt gibt es ja diese Zuordnung, also jedes Source-Backend läuft jetzt direkt mitten im Index-Backend auf derselben Maschine und dann muss man diesen blöden Network-Roundtrap nicht mehr machen. Also da muss nicht mehr das Frontend alle Index-Backends nachfragen und dann grad wieder mit denselben Maschinen reden, das wäre ja Verschwendung. Deswegen redet jetzt das Frontend nur noch mit dem Source-Backend und die fragen jeweils das Index-Backend an. So, so sieht das jetzt also aus, wenn man sich das nochmal komplett versucht vorzustellen, hier oben kommt wieder der Benutzerrequest rein, unverändert der EngineX liefert statische Assets aus, reicht dann die Anfrage weiter an das Webfrontend, das fragt jetzt sechs verschiedene Maschinen gleichzeitig an und sagt, hey, ich habe hier diesen Suchbegriff. Die Maschine, also das Source-Backend fragt dann das Index-Backend und schaut, okay, in welchen Dateien könnte das sein? Durchsucht dann direkt die Dateien und streamt dann die Ergebnisse zurück an das Webfrontend, was sie dann wiederum an den Benutzer ausliefert. Hier oben, wenn man von der anderen Richtung das Diagramm liest, dann ist hier den Tail-Fat-Message und das Schaut wurde neue Pakete hochgeladen, sagt dem FIDER Bescheid, hey, hier ist ein neues Paket, der FIDER holt das Paket, gibt es an den Importer auf der jeweilig passenden Maschine, der baut den Index neu, tauscht den aus und dann sind die Pakete aktualisiert. Gut, ich habe schon angedeutet, jetzt werden Ergebnisse zurückgestreamt, was bedeutet das? Früher war das so, dass wir, wenn wir eine Suchanfrage bekommen hatten, hat das Webfrontend je tausend Ergebnisse betrachtet, gerankt und dann angezeigt, seitenweise. Das heißt, das ist wahrscheinlich nie jemandem aufgefallen, aber wenn man weiter als tausend Ergebnisse blättert, dann hat man Ergebnisse bekommen, die nicht so ganz gepasst haben. Also die vom Ranking her war das nicht konsistent. Also es kann sein, dass das Tausend und Eins der Ergebnis tatsächlich besser war als das 999. Einfach weil die in verschiedenen Batches gerankt wurden. Aber wir mussten das eben machen, weil sonst die Suche viel zu langsam gewesen war. Heute machen wir das so, dass das Ranking global über alle Ergebnisse bestimmt wird, aber eben erst, wenn die Suche fertig ist. Damit man nicht so lange warten muss, also damit man nicht jedes Mal warten muss, bis alle Suche-Ergebnisse fertig sind, werden die 10 vermutlich besten Ergebnisse immer wieder live aktualisiert. Da komme ich gleich noch drauf. Und das Schöne daran ist, dass man jetzt nicht mehr warten muss, bis alle Indexrefer da sind, weil man nicht mehr vorher schauen muss, okay, die Dateien habe ich, jetzt muss ich die erst mal schauen. Sondern man sagt einfach allen Maschinen sucht mal und dann nimmt man alle Ergebnisse, wie sie gerade kommen, egal welche Reihenfolge. Und das ist eben wichtig, weil sonst die alte Architektur hätten, wenn nicht 1 zu 1 übernehmen können auf die neue Hardware-Struktur. Okay, wie funktioniert das Ganze? Wir verwenden dazu WebSockets, damit wir also Daten vom Kleint auf den Server pushen können sozusagen. Und wir schieben Meta-Infos, also Fortschritt, wie viele Dateien habe ich überhaupt zu durchsuchen und wie viele habe ich schon davon durchsucht und wie viele Ergebnisse gab es jetzt schon in der Suche und eben die jeweils 10 vermutlich besten Ergebnisse. Und die vollen Ergebnisse stehen dann hier unter so einer URL bereit. Da wird einfach eine Query ID vergeben für jede Suchanfrage. Das ist deswegen wichtig, weil wenn man viele verschiedene Clients behandelt und manchmal ist das so, dass wenn eine Suchanfrage sozusagen viral wird, also wenn jemand auf Reddit einen Link in der Search postet, bei dem irgendwie in den Suchquery drin ist, dann kommen da halt Hunderte von Leuten, die sich das Query zur selben Zeit anschauen. Und wenn man da jedes Query von Anfang bis Ende neu berechnet, dann ist das blöd. Man will das irgendwie caching, aber wenn das Query noch nicht fertig ist, kann man es auch noch nicht caching. Und deswegen verwenden wir eben diese Query ID, die ist einfach ein Hash über die eingehende Anfrage und streamen alle Ergebnisse zu allen Clients, die gerade auf diesem Query sind mit derselben ID. Jetzt die Frage, warum sind die vollen Ergebnisse von den Web-Sockets? Die vollen Ergebnisse werden also nach wie vor über HTTP geladen. Und das ist deswegen, weil man dann den Cash ausnutzen kann, das Browser. Also wenn ich einige Suchergebnisse Seiten habe, dann will ich, wenn ich die Seite nochmal neu lade, dass er nicht nochmal alle Suchergebnisse neu laden muss. Außerdem ist es so, dass wenn ich dieses Modelle einhalte, dass eine URL wirklich einen Ding bestreibt im Web, dann kann ich auch so Features benutzen wie das Pre-Fetching von Chrome. Also dann du bist gerade auf dieser Seite und der Link hier, ich habe eine hohe Wahrscheinlichkeit, dass der Benutzer als Nächstes auf diesen Link klickt und das ist eben einfach die nächste Seite jeweils. Und dann lädt Chrome schon mal die Ressource vor und kann sie dann direkt anzeigen, wenn man draufklickt. Also das merkt man wirklich, da ist nochmal eine schöne Performance-Optimierung drin. Gut, jetzt weiter zu den eigentlichen Optimierungen bzw. ich schaue mal gerade, ja wir haben genug Zeit, dass ich euch da mal kurz eine Demo zu zeigen kann. Ich gehe nochmal neu auf Code Search und suche mal nach was wirklich lange dauert. Jetzt sieht man das hier, jetzt sagt er hier oben ok, ich habe so und so viel Dateien von so und so viel möglichen durchsucht und so und so viel Ergebnisse habe ich. Und was man hier jetzt sieht, sind die Top 10 Results. Das heißt, es gibt noch keine Next-Page-Buttons oder so, aber man bekommt schon mal einen recht guten Eindruck davon, was sind eigentlich die Ergebnisse, die ich von dieser Suchanfrage bekomme. Und das ist eben deswegen gut, weil es oft so ist, dass wenn man eine Suchanfrage erwartet, man eine gewisse Anzahl von Ergebnissen und wenn man mehr bekommt, dann ist es eigentlich wahrscheinlich, dass man sich in der Suchanfrage vertan hat. Das Query ARS ist ein ganz besonderes Query, weil als ich damals die neue Version von Debian Code Search einem Freund von mir gezeigt hatte, um ihm ein bisschen Beta testen zu lassen, war das das erste Query, was er eingegeben hat. Er spricht British English und deswegen ARS und nicht S, aber stellt sich raus, dass ARS auf ganz viele andere Begriffe in Computer Science eben auch matcht, so was wie ARS oder Cores, oder lauter so Sachen. Das heißt, deswegen gibt es nach diesem vermeintlichen Schimpfwort so viele echte Ergebnisse. Und was eben passierte ist, dass diese Suchanfrage damals die Suchmaschine total overwärmt hat. Also die ist darunter zusammengebrochen unter der Last ist. Also hatte kein Speicher mehr übrig. Und das war die Motivation für diese Optimierungen. Also das erste Ziel war, dass wir auch größte Suchanfragen unterstützen können. Das heißt, wenn der Index durchsucht werden muss, das wollen wir auch machen können. Also es soll keinen Limit mehr geben, soll keine 60 Sekunden Timeouts mehr geben und keine Begrenzung in dem, was man durchsuchen kann. Das zweite Ziel ist natürlich, dass wir nicht nur große Suchanfragen unterstützen, sondern dass sie auch schnell genug funktionieren, weil wenn das zu lange dauert, dann schaut sich das auch keiner an und dann hätte man es gar nicht erst implementieren brauchen. Außerdem ist es angenehmer für den Benutzer. Also wir alle arbeiten lieber mit schnellen Tools als mit langsamen Tools. Also das ist das, was ich auf Pipsoft getan habe. Der führt zum Blog Post im Go Block darüber, wie man Go Programme profiled. Und wer mit Go zu tun hat und sich das noch nicht angeschaut, soll das auf jeden Fall machen, weil es ist wunderbar einfach und man kommt mit sehr wenig Aufwand, sehr schnell seine Bottlenecks raus. Und das habe ich einfach die ganze Zeit gemacht. Und hier zur Motivation jetzt vorher nachher. Also hier sieht man, das habe ich euch gerade und man sieht, also hier habe ich die neue Version deployed. Und jetzt kann man einfach mal gedanklich hier so eine Linie ziehen, dass es jetzt alles unter einer Minute und vorher ist das einfach alles darüber hinausgetragt. Und der Graph ist hier oben abgeschnitten. Ja, es ist nicht so, als würden die nur bis da umgehen, die gingen viel, viel weiter hoch. Das heißt, es hat sich wirklich gelohnt, da ein bisschen Arbeit reinzustecken, das zu optimieren, weil man jetzt sogar die langsamen Queries, also die großen Queries innerhalb von der Minute oder so beantwortet bekommt, was früher es kann auch länger dauern, aber das Allermeiste ist tatsächlich fertig in unserem Budget sozusagen. Gut, jetzt also dazu, wie wir das geschafft haben. Die erste Optimierung, die wir machen mussten, war Arbeitsspeicher. Also in dem Proof of Concept, den ich damals geschrieben hatte, den ich wie gesagt meinem Freund vorgestellt hatte, der das sofort gecrashed hat, alle Ergebnisse wurden einfach im Speicher gehalten. Und ganz am Ende wurden die dann sortiert und dann wurden sie ausgeliefert. Und das läuft eben zu einem Out of Memory bei großen Anfragen und was man machen kann als Abhilfe ist, dass man die Ergebnisse an sich nicht im Speicher behält, sondern dass man die Ergebnisse auf die SSD schreibt und dann eine Technik benutzt, die sich External Sorting nennt. Also man behält einfach einen Tupel mit Ranking und Offset im Speicher, wenn man später nach Ranking sortieren will und dann liest man von der SSD eben ab Offset wieder ein. Also man hat einfach eine große Datei und dann kann man das so machen. Und der Vorteil ist, dass Ranking und Offset einfach zwei Werte sind mit einer fixen Größe, also wenn man dann Flow32 Ranking und ein U in 64 für das Offset dann weiß man genau, wie viel Speicher das nimmt und kann das genau abschätzen und es verwendet auch viel, viel weniger Speicher, also wenn man die Ergebnisse an sich im Speicher hält, das ist denke ich klar. Okay, wenn man das jetzt also gemacht hat, dann war das zweite Problem, jetzt haben wir immer noch mehr als 70 Byte pro Ergebnis. Ich habe hier mal die Datenstruktur auf die Folie gepackt. Das ist also so ein Result Pointer, also ein Zeiger auf ein Ergebnis in dieser großen Datei, die ich auf die Platte speicherte. Zum einen mussten wir das Backend speichern, also von welcher vm das Ergebnis tatsächlich kam, damit wir wissen, in welcher Datei müssen wir dann suchen, weil die Dateien müssen natürlich unabhängig voneinander schreibbar sein, sonst kann man nicht alle Ergebnisse gleichzeitig zurück streamen, sondern muss immer locken auf die Datei und das wäre dann wieder ein Flaschenhals, das wollten wir ja gerade vermeiden. Deswegen müssen wir aber im Result Pointer ein bisschen was mehr mitspeichern. Dann das Ranking, wie gesagt Flow32, soweit klar, Offset in 64. Okay, die Länge mussten wir speichern. Den Pfad haben wir speichern müssen, weil wir den Pfad benutzt haben, um bei Ergebnissen mit dem gleichen Ranking Wert einen Tiebreaker zu haben, damit wir eine deterministische Ordnung hatten und wussten, okay, wenn jetzt die dass gleiche Ranking haben, muss der zuerst kommen, dann der, dann der. Den Package-Namen wiederum mussten wir speichern, damit man diese Gruppierung nach Package implementieren kann. Das war das, was ich euch am Anfang gezeigt hab. Und das wird jetzt halt schnell viel. Ja, wenn man einige Millionen von Ergebnissen hat, dann kann man sich das ja mal ausrechnen. 1 Million mal 70 Bytes, da kommt man dann langsam an die Grenze von den 2 Gigabyte, die unser Frontend hat. Jetzt könnte man natürlich sagen, okay, da müssen wir einfach mehr Gigabytes in das Frontend stecken und das kann man auch, aber dann verschiebt man nur das Problem. Also wenn man erstmal ordentlich optimiert und dann noch Hardware drauf wird, ist das die bessere Strategie. Okay, was kann man da machen? Man kann zum einen ein Sync.Pool verwenden, um die Packet-Namen nur quasi den String von den Packet-Namen in den String-Pointer um. Und den Sync.Pool funktioniert so, dass man also dort, dass man schaut, ist der Wert, den ich jetzt gerade speichern will, schon in dem Pool. Und wenn ja, dann nehm ich einfach ein Pointer auf den Wert. Und wenn nein, dann füge ich ihn rein und nehmt ein Pointer auf den Wert. Und dadurch, dass wir in Debian so ungefähr 17.000 verschiedene Source-Pakete haben, aber unglaublich viel mehr Suchtreffer, ist es quasi so, dass wir ab dem 17.000 Suchtreffer haben, weil dann wurden alle Pakete, die nur erdenkbar sind, einmal genommen und dann spart man Speicher. Und im normalen, praktischen Alltagsfall, spart man sogar schon viel früher Speicher. Gut, statt den kompletten Fahrtnamen zu speichern, haben wir einfach den FNV-Hash, weil das der einzig nicht kryptografische Hash ist in Go, der in der Standard Library mitkommt und schnell ist, genutzt. Damit wandeln wir also einen String Pointer, der Hash ist genauso gut immer noch als Tiebreaker nutzbar, damit kann man genauso gut immer noch sagen, okay, das kommt jetzt vor dem, ohne dass man den kompletten Fahrt braucht. Dann sind wir jetzt also bei 36 Byte Pro Ergebnis, jetzt haben wir immer noch Backend Index, Ranking, Offset, Länge sind wir los geworden, dazu gleich mehr, den Fahrt-Hash und den Packagenamen jetzt als String-Pointer. Das ist schon mal besser. Dann war das nächste Problem, CPU. Jetzt war es so, dass wenn man eine große Suchanfrage gestellt hat, war es so, dass die Suchergebnisseiten alle generiert wurden und alle auf die Platte geschrieben wurden und dann hat direkt der Engine XD ausgeliefert. Das Problem ist, das lief dann also so ab, man hat geschaut, okay, er hat die ganze Suche gemacht, er war dann irgendwann am Ende und dann hat er nochmal irgendwie 30 Sekunden lang einfach nichts Ersichtiges gemacht, bevor die Ergebnisseiten alle zur Firmung standen. Und was er in diesem Zeitraum gemacht hat, ist, er musste halt zum einen sortieren nach Ranking und dann musste er von der Festplatte die Suchergebnisseiten ausgeliefert werden. Und sie dann rausstreiben, geordnet in diesen Suchergebnest-Dateien. Und was wir jetzt einfach dann gemacht haben, ist, wir generieren die jetzt on-demand. Das heißt, wir lassen wirklich nur die Pointer im Speicher und schreiben die sogar noch raus, damit wir sie später wieder einladen können, wenn das Query gecached ist und schreiben die Suchergebnisseiten nie auf die Platte, sondern wir generieren die einfach immer nur, wenn der Engine X uns danach fragt und nutzen den Cache des Engine X und danach war es interessant, weil wir immer noch ein CPU-Boteln erkarten. Und dann habe ich geschaut, was ist im Profiler der größte Blockgrund, es war tatsächlich encoding JSON. Und bei signifikanten Mengen an Daten, also wenn man deutlich mehr als ein Mega bei diese Kunde redet, dann macht es tatsächlich einen Unterschied, welches encoding man hier verwendet. Und dann habe ich mich ein bisschen umgeschaut und es gibt verschiedene encodings, es gibt zum Beispiel Protobuf, aber Captain Proto hat die besten Benchmark-Werte. Und es war interessant, dass wir das Offset in dieser Datei, die wir auf die SSD speichern. Und am Anfang hatten wir gedacht, naja, da benutzen wir halt L-Seq und lassen uns von SIEG sagen, was gerade das Offset in der Datei ist. Stellt es sich aber raus, dass wenn man so ein Go-Programm hat, dann ist es eine ganz schlechte Idee für jeden schreibzugriffenden SIEG- Transponderer. Und dann haben wir dann noch ein bisschen ein bisschen ein bisschen ein bisschen einen SIEG reinzubauen, weil man einfach ganz ganz viele Sys-Calls hat. Und dann kann Go sein internes Scheduling nicht mehr ausleben und man ist die ganze Zeit auf Sys-Calls blockiert. Und stattdessen kann man natürlich einfach selber mitzählen. Also man weiß halt, okay, am Anfang fängt man bei Null an und dann merkt man sich, wie viel schreibt man da. Frage? Frage war, kann man es nicht einfach M-Mapen? Ja, kann man bestimmt, aber M-Mapen ist ein, also M-Map wird in Code-Sedge auch verwendet an anderen Stellen, aber es ist ein bisschen komplizierter, was die API angeht in Go. Also in Go ist es ideomatischer und einfacher, wenn man einfach Sachen schreibt, als wenn man M-Mapen dann direkt im Speicher malt. Okay, außerdem ist es so, dass wir beim deserialisieren, also ganz egal, ob man das jetzt mit JSON oder mit Captain Proto macht, hatten wir ganz viele Sys-Calls. Und jetzt denkt man sich, ja klar, die Daten müssen halt gelesen werden. Aber es stellt sich raus, dass Captain Proto halt zuerst die Länge encodiert und dann den Feldwert und beim Einlesen liest es halt zuerst mal die fixe Länge und dann haben wir ganz, ganz viele kleine Read-Calls hintereinander und das ist schlecht. Und stattdessen nutzen wir jetzt Buffered I.O., was halt einfach Buffered I.O. ist, wie der Name schon andeutet, um einen internen Buffer im Speicher zu haben, einen großen Read zu machen und dann die kleinen Reads direkt aus dem Speicher ohne ein Sys-Calls zu behandeln. Und durch diese zwei Optimierungen haben wir noch mal deutlich die Zeit drücken können. Gut, jetzt als Ausblick, die allermeisten suchen, wie sich rausstellt, wenn man sich mal die Verhauen einfach irgendwelche Fehlermeldungen rein, weil sie wissen wollen, in welchem Programm kommt die denn vor? Oder sie hauen irgendwelche Identifier rein, das war das erste Beispiel, was ich bei der Motivation gebracht habe, dass man schauen will, in welchem Programm ist diese Funktion eigentlich definiert und was macht die Funktion? Ich will den Quelltext lesen. Und die Zusammensetzung an Quarries ist, dass 74% der Suchanfragen Identifier sind und nur 26% Regular Expressions. Jetzt ist es so, dass wenn man so ein Regular Expressions ist, aber für Identifier gibt's eigentlich eine effizientere Datenstruktur und das sind Suffix Errays. Und die würden also die Identifier-Suche massiv beschleunigen. Der Nachteil, warum wir das bislang nicht gemacht hatten, war, wie schon das Thema des ganzen Talks eigentlich ist, es war teurer. Also von Disk und CPU hätten wir uns das nicht leisten können. Aber dadurch, dass wir jetzt die Hardware so effizient nutzen und so gute Hardware haben, könnte das eigentlich funktionieren. Also das ist so das Nächste, was ich auf meiner Liste stehen habe, dass ich jetzt noch mal die Architektur bisschen umgestalten und damit noch mal einen großen Speedup für 74% aller Anfragen erreichen. Okay, das war's soweit von dem Inhalt, den ich auch Folien vorbereitet habe. Zum einen habe ich hier noch eine Empfehlung. Es gibt einen Blog mit Beiträgen zu DBN Code Search, falls euch das jetzt gefallen hat und ihr ein bisschen auf dem Laufenden gehalten werdet, dann könnt ihr das Blog euch durchlesen und abonnieren. Und zum anderen würde es mich sehr freuen, wenn ihr mir Feedback dazu ein kleines Formular gemacht habt, das ist auch der QR Code, der hier oben auf der Slide zu sehen ist. Ich lasse das nochmal ein bisschen und wenn ihr mir da am Ende oder morgen oder irgendwann einfach gutes Feedback geben könntet, wäre ich euch sehr dankbar. Jetzt bin ich damit am Ende und wir haben noch Zeit für Fragen. Das ist eine gute Frage. Also die Frage, um für die Aufzeichnung das zu wiederholen, wonach geht das Ranking der Suchergebnisse? Und das setzt sich zusammen aus verschiedenen Sachen. Wir haben am Anfang, als wir haben eine gute Sachen, die wir zum Ranking verwenden können. Und ein ganz großer Faktor ist der sogenannte Popularity Contest, den es in DBN gibt. Das ist so ein Optin Mechanismus, bei dem ich sagen kann, dass alle Software, die ich auf meinem Rechner installiert habe, da will ich eine Auswertung darüber an DBN schicken und dann zählen die einfach mit, wie viele Leute haben die Software installiert, wie viele Leute benutzen die Software tatsächlich. Und darüber kann man schauen, wie beliebt ist ein Paket. Zum anderen die wir in DBN haben. Also wenn es eine Library gibt, ein Library Paket, welches von 50 verschiedenen Paketen benutzt wird, dann ist das sicherlich wichtiger als ein Library, die nur von einem Paket tatsächlich benutzt wird. Und das sind so zwei Faktoren. Es gibt noch ein paar andere. Zum Beispiel schauen wir auch in den Fahrt rein. Also wenn du nach einem Identifier suchst und der befindet sich schon im Dateinamen, zum Beispiel SDR-Fry, was ich am Anfang gesucht hatte. In der Gillip-C gibt es eine SDR-Fry.C. Wahrscheinlich ist das sehr relevant für deine Suchernfrage. Und so setzen wir zusammen ein gewichtetes Ranking und das wird dafür verwendet. Weitere Frage. Ja bitte. Die Frage war, aus welcher Version kommen die Suchergebnisse und wie kann man wählen, welche man haben will. Die Antwort ist, du kannst es nicht wählen, weil derzeit alles einfach aus unstable kommt. Also wir indexieren nur die Entwicklerversion. Das ist auch ein Punkt, der gelegentlich nachgefragt wird. Ich hatte auch in dem Blog, was ich hier gemacht habe, einen Post geschrieben, in dem es darum geht, wie viele Pakete kannst du damit effektiv durchsuchen. Also wenn du nur an stable immer indexierst, wie viel Überschneidung gibt es zu Testing und Stable. Und stellt sich raus, dass ungefähr 3 Viertel aller Pakete in der Suchmaschine enthalten sind und ein paar ältere Versionen eben nicht. Und die Frage ist, jetzt will man unbedingt die ältere Version durchsuchen, wahrscheinlich seltener als die neuen Versionen. Aber ja, ich gebe dir recht. Also eigentlich sollten wir uns mal anschauen, ob wir das noch mal machen können. Aber das erfordert halt dann doch nochmal eine Umstellung in dem Datenformat, was wir haben und ist damit ein recht komplexer Prozess. Ja, bitte. Ja, die Anmerkung war, dass es gar nicht so klar ist im User Interface, was genau durchsucht wird. Ich werde schauen, dass ich es noch direkt auf die Suchseite auch packe, dass es dort erwähnt wird. In der FAQ steht es aber. Ja, ja, bitte. Die Anmerkung war, die Caches, die ich angesprochen hatte, wann werden die invalidiert? Die Antwort ist nach 15 Minuten einfach. Also die Idee ist halt, dass binnen 15 Minuten sicherlich nicht jemand nochmal das selbe Paket in einer neuen Version hoch lädt. Das passiert tatsächlich sehr selten und selbst wenn, dann ist es wahrscheinlich nicht sehr relevant und 15 Minuten wird man verschmerzen können, alte Ergebnisse zu sehen. Aber auch da, also das wäre auch interessant, mal schaut und analysiert, okay, wie ist eigentlich die Hit Rate in diesem Cash und sollten wir den vielleicht runterdrehen oder hochdrehen. Aber im Moment habe ich da einfach gesagt, 15 Minuten, das passt. Okay, ja. Okay, nochmal die Frage nach dem Ranking. Es ist so eine gewichtete Mischung zwischen wie populär ist das Paket im Popularity Contest, wie viele Abhängigkeiten gibt es und noch ein paar andere kleinere Faktoren. Und je nachdem, wie hoch das Paket eben scored in dem Ranking, wird es als Erstes angezeigt oder nicht? Tatsächlich nicht. Wer aber auch eine interessante Idee, also vielleicht, vielleicht klingt erstmal intuitiv vernünftig, sollte man vielleicht machen. Also es gibt viel Potenzial an dem Projekt auch mitzuhelfen und ich stehe da auch gern zur Verfügung ein bisschen Guidance zu geben, wenn jemanden das interessiert. Es gibt auch eine Hacking Anleitung auf dem Github-Repro, wie man das aufsetzt und dann ein bisschen dran rum spielt. Vielleicht will das auch jemand einfach mal ausprobieren. Noch weitere Fragen? Okay, wenn euch noch irgendwas einfällt, ich bin noch auf der Veranstaltung bis Sonntag, dann könnt ihr mich einfach gerne ansprechen, ansonsten mir eine E-Mail schreiben. Ansonsten, danke und viel Spaß mit Quotset.