Artikel mit Tag pc-kombo
Ein Update für pc-kombo während der Grafikkartenhölle
Ich kam dazu, einiges an Zeit in meinen Hardwareempfehler pc-kombo zu investieren. Er geht jetzt besser mit neuester Hardware um und warnt vor überteuerten Grafikkartenpreisen.
Anfang der Woche erwähnte ich noch, dass das Elend um die Grafikkartenpreisen für mich demotivierend war. Der Artikel war aber etwas im Voraus geschrieben. Das einmal ausformuliert zu haben half mir, die Situation neu zu bewerten. Denn tatsächlich ist die Lage mittlerweile etwas besser. Grafikkarten sind zwar immer noch dauernd überteuert, aber wenigstens sind fast immer wenigstens ein paar Modelle auf Lager – das war schonmal anders. Und mit der neuen Radeon RX 6500 XT und GeForce RTX 3050 gibt es zwei etwas günstigere Karten – mit Macken, die 6500 XT ist lahm, die 3050 schon wieder teurer; aber immerhin sind das Karten für deutlich weniger als 1000€ die man kaufen könnte. Einem System wie dem meinem, das auf verfügbare Grafikkarten angewiesen ist, hilft das enorm.
Das letzte Update an der Seite kümmerte sich also um eine bessere Anpassung an diese Situation:
- Die neuen Grafikkarten sind im System und passende Benchmarks eingelesen, sodass sie sauber platziert und empfohlen werden.
- Die Alderlake-Intelprozessoren sind jetzt samt ihren neuen nicht übertaktbaren Varianten im System, was insbesondere mit dem i3-12100F einen interessanten Budget-Prozessor, dem i5-12500 eine gute Standardwahl und mit dem i7-12700K einen starken High-End-Prozessor bringt.
- Passend zu den Prozessoren gibt es mehr Mainboards, auch mit den neuen H670- und B660-Chipsätzen. Das Empfehlungssystem wählt die auch für die nicht-übertaktbaren Prozessoren.
- Wenn der Empfehler vorher ein Mainboard mit DDR5-Speicher gewählt hätte, prüft er jetzt ob es eine günstigere DDR4-Variante gibt. DDR5 ist überteuert und nicht schneller, bisher.
- Bei einigen Prozessorkühlern habe ich manuell die Information hinzugefügt, dass sie (mit einem Nachrüstkit) mit dem Sockel 1700 der Alderlake-Prozessoren kompatibel sind.
- Bei der Grafikkartenauswahl werden hohe Preise rot markiert. Eine Hover-Einblendung zeigt dann über dem Preis an, wieviel teurer der aktuell beste Preis im Vergleich zur Preisempfehlung ist.
Zusätzlich habe ich mehrere kleine Bugs behoben. Darunter einen, der ein paar Benchmarkdaten blockierte. Der war vorher für mich unsichtbar und machte das Updaten der Benchmarksammlung schwierig, das gelöst zu haben war unheimlich angenehm. Das ganze System wirkte dann wieder beherrschbar.
Zuvor hatte ich bereits das System angepasst, damit es mehr Daten zu den integrierten Grafikkarten hat und die auch öfter empfiehlt (ich erwähnte es hier im Blog). Das erschien mir jetzt nochmal als superwichtige Änderung, die ich aber fast vergessen hatte. Mit ihr und jetzt dem Hinweis auf die hohen Grafikkartenpreise schon umgesetzt, gibt es noch mehr was pc-kombo machen könnte um mit den hohen Grafikkartenpreisen und ihrer schlechten Verfügbarkeit umzugehen?
Eine Anleitung zur Auswahl von PC-Hardware
Drüben bei pc-kombo habe ich eine Anleitung geschrieben. Sie erklärt, was bei der Auswahl von Prozessoren, Grafikkarten usw zu beachten ist und empfiehlt derzeit gute Hardware. Noch ist das nur auf englisch, und für den deutschen Markt würde ich ein paar Kleinigkeiten abändern, aber grundsätzlich könnte das auch jetzt schon für hierzulande hilfreich sein. Denn der Großteil der Empfehlungen passt auch hier und die Hintergründe ändern sich ja nicht.
Gedacht ist das als Ergänzung zum automatischen Hardwareempfehler. Ich schrieb ja schon bei der Vorstellung des neuen Designs:
Ich will mehr Funktionen haben, um bei der Komponentenauswahl zu helfen. Zum Beispiel ist jetzt schon neu, dass mittels eines kleinen Icons jeweils die Bestandteile eines [Referenz-]Builds empfohlen werden.
Wissen in einen Artikel zu verpacken ist da ein Ansatz für.
Wäre natürlich auch nicht schlecht, wenn die Anleitung von Google Suchenden gezeigt werden würde.
PC-Kombo bekam ein neues Design
Die Seite zum PC-Bauen - das ist was pc-kombo nun sein soll. Vorher nannte ich sie immer einen Hardwareempfehler, was auch stimmt. Aber ich hatte erkannt, dass die Seite aus mehr besteht, aus drei Teilen: Eben dem Empfehler (der auch ein Konfigurator ist), aber auch aus einer Hardwaredatenbank und einem nützlichen Benchmark. Das sollte nun besser gezeigt werden.
Generell gibt es ein neues Design, das – glaube ich – etwas hübscher und professioneller aussieht (auch wenn es sicher noch nicht 100% fertig ist). Strukturell sind die Bereiche klarer unterteilt, jeder Bereich hat zudem seine eigene Startseite mit Erklärungen. Die Hauptstartseite führt auch nicht mehr direkt zum Konfigurator, sondern erklärt die Seite im Ganzen
So sieht die Seite jetzt aus:
So sah sie vorher aus:
Die Überlegungen
Das waren meine Überlegungen beim jeweiligen Abschnitt:
Der Konfigurator
Das alte Design wirkte für neue Benutzer etwas kompliziert. Eine Liste mit Button statt den Blöcken macht die Komponentenliste einfacher zu verstehen und auch klarer, wie man sie anpassen kann. Das neue Design sollte es auch vereinfachen, weitere Funktionen wie das freie Hinzufügen neuer Hardwarekomponenten (z.B. drei SSDs) umzusetzen.
Es sind nun weniger Blöcke, weniger Rahmen, wodurch die Seite mehr wie ein zusammengehöriges Ganze wirkt. Für Ordnung sorgt stattdessen die Gruppierung. Die Linien zwischen den einzelnen Komponenten aber sind wichtig, um beim Listenlesen das Auge zu führen.
Da ist auch viel im Hintergrund passiert. So kann man jetzt problemlos Komponenten hinzufügen, die keinen Preis haben. Oder Konfigurationen basteln, die inkompatibel sind – da wird jetzt nur noch gewarnt. Das ist praktisch, wenn Daten in der Hardwaredatenbank falsch sind oder wenn man eben aus Versehen einen inkompatiblen PC gebaut hat und das nun mithilfe der Seite korrigieren will.
Die Hardwaredatenbank
Was erst eine eigene Seite werden sollte ist nun doch in pc-kombo beibehalten worden. Es wäre einfach zu viel doppelte Arbeit gewesen - Preise und Benchmarkdaten sind bei der Datenbank ja ebenso wichtige Daten, und im Benchmark und Konfigurator braucht man die PC-Komponenten. Warum das also komplett auftrennen?
Die Übersichtslisten haben sich zwar verändert, folgen aber dem gleichen Prinzip: Eine Liste, in der jeder Listenpunkt eine PC-Komponente ist und zudem ein paar Daten angezeigt werden, wie die Anzahl der Prozessorkerne zum Beispiel. Obendrüber gibt es einen Filter. Wichtiger als das komplett umzuwerfen war es mir, die Performance zu verbessern: Vorher konnten lange Listen schonmal den Browser zum Schnaufen bringen. Jetzt laden die Seiten schnell.
Die Einzelseiten sind massiv überarbeitet. Ich wollte erreichen, dass sie viel besser aussehen, und dass sie so nützlich wie möglich sind.
Vorher waren fast alle Inhalte verschiedene und unterschiedlich große Blöcke, verteilt in einem Grid. Jetzt sind deutliche Blöcke nur noch die Spezifikationen, die nur ein Teil der Seite sind. Bilder, wenn vorhanden, sind oben. Bei Prozessoren und Grafikkarten gibt es dazu eine automatisiert erstellte Beschreibung samt Leistungseinschätzung, was ich für total praktisch halte. Dann die Preise und das Preisverlaufsdiagram, erst jetzt die technischen Spezifikationen, und schließlich Reviews. Reviews gab es vorher schon, aber nur als eine Liste von Links. Jetzt tragen die meisten Reviews ein Logo und alle zeigen ein Zitat, welches das Review zusammenfasst.
Der Benchmark
Hier hat sich am wenigsten getan.
Ich setze darauf, dass die neue Startseite mit den Erklärungen Besuchern schon hilft, zu verstehen was der Benchmark ist. Die Vergleichsfunktion poppt nun beim Drüberfahren mit kurzem Anweisungstext auf und die Komponenten gehen daraufhin in eine Seitenleiste. Neu ist, dass auf der Vergleichsseite nur die Benchmarks angezeigt werden, in denen alle der Vergleichsprozessoren oder -grafikkarten vorkommen. Entweder es gibt einen guten Vergleich in der Datenbank oder eben nicht, das schafft Klarheit. Und das gruppierte Balkendiagramm mit den Einzelbenchmarkdaten sieht nun (dank des Umstiegs auf apexcharts) besser aus, es wird auch in keiner Situation mehr unten abgeschnitten oder unscharf.
Technische Hintergründe
Eigentlich wollte ich die drei Teile der Seite jeweils in eine eigene Seite verfrachten, mit statischen Seiten wo möglich. Zwei Dinge hielten mich davon ab: Als ich die Hardwaredatenbank als statische Seite gebaut hatte wurde deutlich, dass die anderen Informationen wie Preise und Benchmarkbewertungen auch hier praktisch wäre. Und ich hatte viel Erfolg, pc-kombo zu optimieren. Es stellte sich raus, dass die Performanceprobleme oft nur bestanden, weil hier und dort ein Datenbankindex fehlte, oder Funktionen unnötigerweise aufgerufen worden, oder schnellere gems wie FastGettext noch nicht benutzt wurden. Aber auch, dass die Komponentenlisten gar nicht auf der Serverseite langsam waren, sondern das Javascript (eine alte Version von jplist) den Browser blockierte.
Ich bin also die Seite durchgegangen, mit dem Firefox-Netzwerkinspektor und Flamegraphs bewaffnet, und habe jede Seitenart durchoptimiert. Und zwar das erste Laden, bevor der Cache befüllt ist. Weil das ja auch Seitenbesucher trifft und sicher massiv stören würde. Erst danach kam die Entscheidung pro Redesign und Beibehaltung unter einem Dach, aber klarerer Strukturierung.
Dementsprechend ist pc-kombo immer noch eine Ruby/Sinatra-Anwendung, mit SQLite als Datenbank. Es gibt aber eine Reihe von Verbesserungen, der Artikel zum effizienteren Speichern von Zeitreihen zum Beispiel kommt natürlich aus dieser Überarbeitung der Seite. Und das Datenbankschema ist etwas anders, wodurch zum Beispiel bei der Hauptdatenbankabfrage ein Join weniger gebraucht wird.
Eine große Änderung gab es bei den Sessions. Die waren vorher sehr wichtig, zentral für die Funktion der Seite. Wer /build?price=800
besuchte bekam in seine Session ein neues Empfehlungsobjekt gespeichert, und alle weiteren Funktionen wie das automatisierte Wählen eines neuen Prozessors griff auf dieses Objekt zu. Das bedeutete, dass geteilte URLs unbrauchbar waren, wenn nicht vorher ein Permalink erstellt wurde. Und der Code sehr zustandsabhängig wurde. Der neue Ansatz ist, dass /build?price=800
direkt auf einen Permalink weiterleitet, und weitere Funktionen dann von diesen Permalink ausgehen - also zum Beispiel /permalinkid1234/customize/cpu
. Struktur! Die hilft, Javascript zu vermeiden (dazu im nächsten Abschnitt mehr). Und ist ein Ergebnis aus dem Werkeln an dem statischen Seitengenerator, an der alternativen Hardwaredatenbank.
Ich habe auch Funktionen rausgeworfen, die nicht funktioniert haben. Statt Reviews gab es vorher auf Produktseiten unten eine Kommentarfunktion, die einfach nicht genutzt wurde. Upvoten und Downvoten, das wurde ein bisschen genutzt, aber nicht genug um mit den Daten die Listen nach Nutzervorlieben zu sortieren. Also ist sowas nicht mehr drin. Wobei nicht alles, was nicht mehr da ist, wegbleiben soll. Zum Beispiel fehlt das Löschen von Komponenten aus der Buildliste einfach noch.
Designprinzipien
Das Design ist diesmal nicht komplett handgemacht. Meinem Eindruck nach profitiert das Ergebnis deutlich davon, auf jeden Fall war die Arbeit dadurch viel einfacher. Es basiert auf dem CSS-Framework Spectre. Ich hatte mir ein paar Alternativen angeschaut, Spectre blieb über, weil es relativ simpel und vernünftig aussah, die Dokumentation klar war und die Komponenten sowie Beispiele hübsch. Außerdem, das war mir wichtig (und gleich mehr dazu), braucht das Framework kein Javascript. Die Wahl kann man hinterfragen, wäre das derzeit aktiver entwickelte Bulma vielleicht besser gewesen? Naja, wechseln kann man immer, auch wenn es Arbeit wäre.
Strukturschaffen war eines der Hauptziele. Es gibt die Startseite /
. Dazu kommen die Bereichsseiten /builder/
, /components/
und /benchmark/
. Die weiteren Unterseiten folgen dieser Struktur. Das war intern schon vorher so, wurde aber weniger gezeigt. Diese Struktur vorher klar zu definieren half auch beim Design. So war klar, dass es oben eine Hauptnavigation geben muss, für die drei Bereiche. Die Navigation innerhalb des Bereiches gehört da aber nicht wirklich rein, stattdessen habe sie jeweils eine Breadcrumbnavigation. Ich bilde mir ein, dass das hilft die Navigationsstruktur flachzuhalten und so weniger verwirrend zu machen.
Javascript wurde vermieden, indem mehr mit eigenständigen Seiten gearbeitet wird. Vorher war die Empfehlungsansicht fast schon eine SPA. Extrembeispiel: Wenn die Liste zur Komponentenauswahl geladen werden sollte, scrollte der Viewport nach rechts und dort wurde per Ajax die Auswahlliste hineingeladen. Jetzt gibt es dafür schlicht eine eigene Seite. Es gibt immer noch Javascript, natürlich: Apexcharts für die Benchmarkdiagramme, das neue jplist zum Filtern von Komponentenlisten, und 26 Zeilen handgeschriebenes Javascript für die Benchmarkvergleichsfunktion. Aber das wars. Auch ohne Javascript funktioniert der Großteil der Seite nun.
Weitere Pläne
Fehlende Funktionen nachzurüsten sollte jetzt wohl der Hauptfokus sein. Deaktivieren von Komponentenkategorien (wenn man z.B. keinen Arbeitsspeicher wählen will, weil der aus dem alten PC kommen wird), Filter für die Liste bei der manuellen Auswahl von Komponenten, die Sortierung verbessern. Und im Backend gibt es auch noch einiges zu tun, wie mehr Verwaltungsoberflächen, was dann mir die Arbeit erleichtert um z.B. Daten zu korrigieren, wodurch im Endeffekt die Seite für Besucher besser funktionieren wird.
Was wahrscheinlich ebenso wichtig ist: Ich will mehr Funktionen haben, um bei der Komponentenauswahl zu helfen. Zum Beispiel ist jetzt schon neu, dass mittels eines kleinen Icons jeweils die Bestandteile eines Builds empfohlen werden. Das sind die Bestandteile des PCs, den ich derzeit generell empfehlen würde, wenn das eigene Geld möglichst sinnvoll eingesetzt werden soll und es keine Spezialanforderungen gibt. Aber da kann noch mehr gemacht werden, denn generell gibt es in der Datenbank schon eine Liste von Komponenten, die berücksichtigt werden sollen – um zum Beispiel Grafikkartenmodelle auszuschließen, deren Kühler schlecht ist. Das könnte auch bei der manuellen Auswahl sichtbar gemacht werden.
Zukunftspläne für pc-kombo: 4 Aufgaben, 3 Seiten, mehr FOSS
Damit der Hardwareempfehler seine PC-Builds zusammenstellen kann muss pc-kombo vier Aufgaben auf einmal erledigen:
- Er muss sich eine Liste aller möglichen Komponenten zusammenstellen.
- Dann muss er herausfinden, was wieviel kostet.
- Um dann aus diesen Komponenten zu wählen zu können muss er wissen, welche Hardware wie schnell ist.
- Schließlich kann er zusammenpassende Builds zusammenstellen, also per Algorithmus optimieren und dabei bedenken, welche Hardware zusammenpasst (welche Prozessor in welches Motherboard, welche Grafikkarte in welches Gehäuse, welches Netzteil stark genug ist etc).
Ich sitze derzeit daran, das weiter aufzusplitten. Natürlich ist es jetzt schon in einer gewissen Weise aufeteilt: Die Webanwendung holt ja nicht bei jeder Anfrage alle Komponenten aus Crawlern und die Preise von den APIs, sondern erledigt vieles vorher im Hintergrund (die Preiserfassung gar per Micoservice). Aber letzten Endes ist es doch eine Seite, eine Interface, ineinander greifende Arbeitsschritte. Stattdessen möchte ich am Ende drei spezialisierte Seiten haben – eine namensgemäße Kombination von Anwendungen erschaffen.
Eine PC-Hardwaredatenbank
Sie soll alle Prozessoren, alle Grafikkarten, alle Motherboards usw umfassen, samt ihren Spezifikationen, Reviews und was sonst noch anfällt. Der Clou: Das soll offen werden. AGPL-lizenzierter Code, API-Zugriff auf die Datensammlung. Denn als ich pc-kombo startete war das Sammeln der Hardware eine unvermutete Mammutaufgabe, wofür es keinen guten Grund gibt. Das sind keine Geschäftsgeheimnisse, keine geheimhaltungswürdige Informationen. Und doch gibt es da eine kleine Industrie drumrum, die solche Daten sammelt und zu Mondpreisen verkauft.
Mit dieser Datensammlung und der API wäre nicht nur pc-kombo gedient, sondern viele andere Projekte könnten davon profitieren. Für pc-kombo und mich wäre es aber besonders praktisch: Ein zentraler Ort für die Hardwaredatensammlung. Wo ich nochmal Zeit und Arbeit darein investieren kann, die Datensammlung besser und einfacher zu gestalten. Gleichzeitig immer im Blick halten kann, auf jeden Fall auch das zu sammeln war das Empfehlungssystem mindestens braucht.
Für die Einzelansicht einer Grafikkarte habe ich bereits einen Entwurf:
Nebenbei: Statische Seiten zu generieren entstammt als Ansatzpunkt natürlich dieser Projektidee.
Falls jemand als Mitentwickler einsteigen will, gerne! Einfach in Kontakt treten. Softwaretechnisch wird das ein statischer Seitengenerator in Ruby; Das, sowie HTML, CSS und vielleicht Javascript muss geschrieben werden, und mit dem angedachten Backend und der Datensammlung gibt es nochmal eine ganz andere Aufgabe zu bewältigen.
Eine Metabenchmarkseite
Der Metabenchmark verdient mehr Aufmerksamkeit. So oft wollen Leute wissen, wie gut Prozessoren und Grafikkarten im Vergleich mit anderen sind, welche Spiele und Anwendungen sie wie gut bewältigen. Und viel zu oft schauen sie dabei auf die falschen Daten: Künstliche Vergleiche von Spezifikationen oder Ergebnisse artifizieller Benchmarks, die über die Praxis fast nichts aussagen. Echte Benchmarks der Zielanwendungen sind der viel bessere Weg, Prozessen und Grafikkarten zu vergleichen.
Gleichzeitig ist das nicht einfach. Verschiedene Benchmarks mit teils disjunkten Teilnehmerlisten vergleichbar zu machen ist komplizierter, als ich anfangs dachte. Doch mittlerweile meine ich, das Problem algorithmisch so gut gelöst zu haben wie möglich. Wenn es mal offensichtlich falsche Ergebnisse gibt, dann liegt das mittlerweile immer an fehlenden Daten. Was sehr selten geworden ist.
Und doch beobachte ich für den Benchmark wenig Popularität, außer ich stoße Leute drauf. Deswegen soll der Metabenchmark seine eigene Seite bekommen, mit einer besseren Oberfläche, und so besser sichtbar werden. Und ebenfalls eine API bekommen, sodass andere Projekte ihn benutzen können. Wobei er selbst seine Prozessoren und Grafikkarten aus der API der Hardwaredatenbank ziehen würde.
Und wie gehabt: Ein PC-Builder
An pc-kombo würde sich laut diesem Plan erstmal gar nicht viel ändern. Die Daten der anderen Seiten benutzt er ja jetzt schon und bräuchte sie auch weiterhin. Aber mit einem kleineren Kern, besserer Automatisierung und reduzierten Ansprüchen an die Datenbank kann ich vielleicht ein paar der Verbesserungen umsetzen, zu denen ich bisher nicht kam.
Im Grunde will ich nehmen, was pc-kombo sowieso schon macht, es besser kapseln, automatisieren und zugänglich machen. Dabei mir und anderen helfen, daher sind die APIs geplant und eine freie Lizenz für die Datenbank. Es muss sich natürlich erst noch zeigen, ob ich das wirklich gebaut kriege und dann auch so wird, wie ich mir das derzeit vorstelle.
Wie man mit AMQP Progammbestandteile unter Ruby/Sinatra auslagern kann
Bevor ich wie beschrieben die problematische Datenbankabfrage beim PC-Hardwareempfehler pc-kombo entdeckte hatte ich ja schon einige andere Verbesserungen probiert. Die anspruchsvollste war das Auslagern der Preisaktualisierung auf einen zweiten Server.
Ausgangssituation
Der Hardwareempfehler ist eine Ruby/Rails-Anwendung. Der reguläre Teil davon kümmert sich um das Berechnen der Empfehlungen, und natürlich um das Bauen des HTMLs der Webseite. Eine normale Web-App. Etwas ungewöhnlich ist der Threadpool. Er wird beim Start der Webanwendung erstellt.
In diesem Threadpool lief der Code, der regelmäßig die APIs der eingebundenen Shops abfragt um die Preise zu aktualisieren. Das ist superwichtig für die Software, denn nur mit aktuellen Preisen können die besten PC-Builds für das Wunschbudget zusammengestellt werden.
Aber hier lag auch ein Problem: Dieses Preisaktualisieren ist keine leichtgewichtige Operation. Denn sie beinhaltet das Herunterladen, Entpacken und Durchsuchen richtig großer XML- und CSV-Dateien. Das ist besonders problematisch in einer Sprache wie Ruby, in der trotz der Threads wegen des GIL kein echter Parallelismus möglich ist. Und der Threadpool läuft ja im gleichen Prozess wie der Servercode. Das war also eine durchaus wahrscheinliche Ursache für das gelegentliche Langsamsein der Anwendung.
Diese Aufgabe sollte also ausgelagert werden.
Die Lösung: Microservices und AMQP
Anstatt die Preisaktualisierung nur in einen anderen Prozess zu verfrachten wollte ich sie auf einen eigenen Server packen. Dort sollte ein Daemon laufen, der die Preise aktualisiert und die neuen Preise zum Hauptserver sendet. So ist sichergestellt, dass der Hauptserver nur die minimale Last hat, die fertig aktualisierten Preise anzuwenden. Doch das war vor allem aufgrund von SQLite einfacher gesagt als getan. Denn das ist die genutzte und inzwischen auch schwer auswechselbare Datenbank. Der zweite Server kann also keine Verbindung zum Datenbankserver aufbauen und direkt die neuen Preise eintragen, denn es gibt beim dateibasierenden SQLite keinen Datenbankserver.
Meine erste Idee war das Replizieren der Datenbank. Es gibt da mit rqlite eine interessant aussehende Lösung, mit der man eine oder auch mehrere SQLite-Datenbanken auf mehrere Server replizieren kann. Und Änderungen werden synchronisiert. Dann hätte der zweite Server die Datenbank aktualisiert und die Änderungen wären automatisch aktualisiert worden. Doch fehlt rqlite ausgerechnet ein Ruby-Client.
So landete ich als zweites bei Bedrock. Auch diese Software repliziert SQLite-Datenbanken. Und es umgeht ziemlich genial das Client-Problem, indem es den MySQL-Client für seine Zwecke umfunktioniert, und den hat wohl jede Sprache. Doch leider war Bedrock nicht zum Laufen zu kriegen. Es hängt von gcc-6 ab, was schon alleine ein schlechtes Zeichen ist. Und dann lief es einmal kompiliert trotzdem nicht. Zudem ist unklar, ob Bedrock mit bestehenden SQLite-Datenbanken initialisiert werden kann, oder ob die Daten nachträglich eingepflegt werden müssten. Dann hilft es auch nicht, dass es wie ein ziemlich sympathisches Projekt wirkt.
Also zurück zum Kernproblem: Im Grunde sollen nur Informationen von einem Server zum anderen transportiert werden. Dafür gibt es auch andere Lösungen. So ist Sinatra wunderbar geeignet eine REST-API zu betreiben, sodass dann der zweite Server die neuen Preise POSTen könnte. Doch läuft man dann in das typische Problem beim Umbau eines Monolith in eine Microservice-Architekturen: Was tun, wenn die Ziel-API mal down ist? Wie kann auf Fehler und Netzwerkprobleme reagiert werden?
Nun sind Microservices schon fast wieder aus der Mode und es gibt für so etwas natürlich fertige Lösung. Die meines Wissens beste: Setze eine Queue zwischen die Server, welche Daten Zwischenspeichern kann. Und genau das ist AMQP mit einem Broker wie RabbitMQ.
Neue Architektur
Wir landen also hier:
Au dem zweiten Server werden die Preise aktualisiert. Um nicht unnötig Daten zu senden werden diese auch lokal gespeichert, nur Änderungen werden an den Hauptserver gemeldet. Diese Änderungen werden an den auf dem gleichen Server laufenden RabbitMQ-Broker gepusht, über AMQP. Der Hauptserver macht ebenfalls eine AMQP-Verbindung zu diesem Broker auf. Und erhält dann über diese Verbindung über eine Queue die Preisaktualisierungen zugespielt.
Wir haben immer noch den Threadpool, aber der wird nur noch zum regelmäßigen Löschen des Datenbank-Cache genutzt und aktiviert so die Nutzung der neuen Preise.
Das tolle daran ist das Zwischenspeichern auf dem Broker. Ist pc-kombo oder die Verbindung zum Hauptserver down gehen keine Preisaktualisierungen verloren. Sie werden gesichert und dann später und geordnet gesendet, sobald die Verbindung wieder da ist. Das hat sich nun schon mehrfach als sehr praktisch erwiesen.
Der Code dafür ist relativ simpel. Genutzt wird der eine bekannte AMQP-Client für Ruby, bunny. Auf dem zweiten Server senden wir die Aktualisierung:
conn = Bunny.new("amqp://user:password@localhost:5672") conn.start ch = conn.create_channel @q = ch.queue('offers', :exclusive => false) @x = ch.default_exchange # Notify master of new offer or offer to be deleted, but only if it is necessary # For this to work offers.db has to be in sync on the two servers def notifyMaster(offer) changes = updateDB(offer) if changes @x.publish(offer.to_msgpack, routing_key: @q.name) end end
Zusätzlich und nicht zu sehen ist der Threadpool, der wieder genutzt wird um regelmäßig die Preise des Hardwaresortiments zu aktualisieren, woraufhin jedes mal notifyMaster
aufgerufen wird. Sinatra läuft hier aber nicht.
Auf dem Hauptserver bauen wir in Sinatras configure
ebenfalls eine Verbindung zum Broker auf, nur dass wir nichts senden, sondern empfangen:
configure do if settings.production? conn = Bunny.new("amqp://user:password@server2-ip:5672") conn.logger.level = Logger::INFO conn.start ch = conn.create_channel q = ch.queue("offers") q.subscribe do |delivery_info, metadata, payload| offer = MessagePack.unpack(payload) Database.instance.updateOffer(offer) end end end
MessagePack hat übrigens die Eigenheit, Hashes mit Symbolen in Hashes mit Strings zu verwandeln. Aus einem gesendeten offer[:abc]
wird auf dem Hauptserver offer["abc"]
. Darauf musste ich erstmal kommen. Ansonsten erschien es mit aber absolut logisch, für diesen Datentransport ein platzsparenderes binäres Format statt JSON zu nutzen, was wohl sonst meine übliche Wahl gewesen wäre. Ich hatte es zwischendurch auch mit protobuf probiert, kam mit der Logik dessen Ruby-Clients aber gar nicht zurecht.
Insgesamt funktioniert die neue Architektur. Und auch wenn die Preisaktualisierung schließlich nicht die Hauptursache des Performanceproblems war, hilft diese Auslagerung doch sicher dabei, die Performance nicht doch gelegentlich einbrechen zu lassen. Und auf dem zweiten Server kann ich nun besseres Monitoring einbauen, sodass ich mir der laufenden Preisaktualisierung sicher sein kann. Den ziemlich intransparenten Threadpool einzusehen war vorher nämlich schwierig.
Fazit: Nett, aber nicht ganz so ohne
Ich finde, das ist ein schönes Beispiel für den Einbau eines Microservices in einen bestehenden Monolith, bzw. die Auslagerung eines kritischen Programmbestandteils auf einen zweiten Servers. Es war allerdings auch eine größere Operation. Viele Probleme waren zu lösen: Welcher Code muss auf den zweiten Server dupliziert werden, um dort überhaupt Preise aktualisieren zu können? Ich wollte ja nicht alles neu schreiben. Letzten Endes liegt dort jetzt der gesamte Programmcode, nur wird er von einem neuen Ruby-Skript anders genutzt als vorher. Ähnliches Problem: Welche Daten müssen dupliziert werden? So war mir schnell klar, dass Benchmarkdaten nicht, dafür aber alle Hardwaredaten gebraucht werden. Dass es aber auch sinnvoll ist, die vorhandenen Preisdaten zu spiegeln um nur Änderungen zu senden (was das Datenaufkommen und damit die Last auf dem Hauptserver reduziert) wurde mir erst etwas später klar.
Von RabbitMQ habe ich einen gemischten Eindruck. Die Software funktioniert sehr solide, das Dashboard ist hervorragend gemacht. Doch war die Konfiguration gar nicht so einfach. RabbitMQ unterstützt verschiedene Arten von Queues, und mir war nicht ganz klar welche die passendste ist. Letzten Endes passte wohl der Standard. Hauptproblem der Software ist meinem Eindruck nach die Dokumentation: Sie erklärt zwar haarklein alles, schau dir nur die Installationsanleitung an! Aber sie erklärte nie genau das, was ich wissen wollte. Sie ist zu abstrakt und deckte nicht meine Fragen und Probleme ab, wie das richtige Nutzersetup um das Dashboard für einen Remotezugriff zu aktivieren, oder wie Letsencrypt-Zertifikate dieses absichern können.
Auch bunny entpuppte sich als Herausforderung. Der Client hat eine gute API und scheint angemessen ressourcenschonend zu funktionieren. Aber gelegentlich ist mir auf dem Hauptserver die Verbindung abgerissen und konnte nicht automatisch wiederhergestellt werden. Und ich finde es archaisch, zur Besprechung solcher Bugs auf Mailinglisten verwiesen zu werden. Dort konnte mir dann auch nur geraten werden, die automatische Verbindungsreparatur zu deaktivieren und sie manuell neu herzustellen, was keine tolle Lösung ist. Allerdings scheint die Verbindung stabiler zu funktionieren, seit das kernauslastende Performanceproblem gelöst ist. Vielleicht triggerte die Serverlast eine Race-Condition im Code von bunny. Das wäre natürlich ein schwer zu findender Bug.
Insgesamt war es eine lehrreiche Aktion, die glücklicherweise auch noch funktioniert hat.
Wenn ein fehlender Index den Server lahmlegt
In letzter Zeit hatte ich bei meinem PC-Hardwareempfehler pc-kombo mit Performanceproblemen zu kämpfen. Auf meinem Rechner lief die Anwendung lokal gut. Aber wenn mehrere Besucher auf dem Server waren brach desöfteren die Performance ein. Und zwar aller Seiten, die irgendwie auf die SQLite-Datenbank zugriffen oder kompliziertere Berechnungen durchführten.
Bis hierhin hatte ich schon einige Stellen der Serveranwendung optimiert. Die Preisaktualisierung – für die große XML-Dateien geparst werden müssen, was die Serverperformance beeinträchtigen konnte – wurde auf einen zweiten Server ausgelagert, das war die größte Aktion. Geschickter und ebenfalls mit großem Effekt: Ein Cache verhindert das unnötige Neuberechnen des besten PCs für einen bestimmten Preispunkt, solange sich die Komponentenpreise nicht geändert haben. Übersetzungen werden nun genauso im Arbeitsspeicher zwischengespeichert, was die Customize-Funktion beschleunigt. Die Berechnung der Durchschnittsgröße eines Gehäuses wird nur noch durchgeführt, wenn die Detailseite eines Gehäuses mit dem Größenvisualisierer angezeigt wird, und so weiter. All das half, doch es war nicht die Ursache des Grundproblems. Dafür wurde das nun sichtbar.
Schuld an den Performanceeinbrüchen war wohl eine einzelne Datenbankabfrage.
Der Debugweg
Nach all den vorherigen Verbesserungen stach eine Seite als noch besonders langsam heraus: Die Detailansicht einer Komponente, z.B. die des Prozessors i7-8700K. Auf dem lokalen Rechner mit Testdaten war diese Seite allerdings schnell. Ich entschloss mich, trotzdem erstmal dort zu debuggen, da der langsamste Abschnitt auf meinem Rechner ja auf dem Server noch problematischer sein und die längere Verzögerung verursachen könnte.
Zum Performance-Debuggen benutze ich ruby-prof
mit ruby-prof-flamegraph
. Über die Gemseite finden sich gute Erklärungen. Bei mir sieht der gekürzte Code so aus:
get '/:country/product/:type/:ean' do |country, type, ean| if settings.development? require 'ruby-prof' require 'ruby-prof-flamegraph' begin RubyProf.start rescue RuntimeError => re RubyProf.stop RubyProf.start end end html = doStuff() if settings.development? result = RubyProf.stop printer = RubyProf::FlameGraphPrinter.new(result) File.open("profiling/profile_data", 'w+') { |file| printer.print(file) } end html end
Die Datei profiling/profile_data kann ich dann mit flamegraph.pl
visualisieren:
flamegraph.pl --countname=ms --width=1920 < profile_data > product.svg
Und das sah so aus:
Mit 73% ging der größte Teil der Rechenzeit also in Hardware#priceHistory
verloren. Auf meinem Rechner war das weniger als eine Sekunde. Aber auf dem Server hatte das Laden der Seite vorher – unter Last – ~8 Sekunden gedauert. Dort würde diese Funktion wohl ebenfalls den größten Teil der Rechenzeit ausmachen, vermutete ich.
Was macht priceHistory
? In Grunde führt es diesen SQL-Query aus:
SELECT * FROM pmdb.priceHistory WHERE ean = ? AND (vendor = ? OR vendor = ?) ORDER BY date ASC
Ein ziemlich simples Select. Doch der Query-Plan sah nicht gut aus:
EXPLAIN QUERY PLAN SELECT * FROM priceHistory WHERE ean = "05032037108652" AND (vendor = "vendor1" OR vendor = "vendor2") ORDER BY date ASC; 0|0|0|SCAN TABLE priceHistory 0|0|0|USE TEMP B-TREE FOR ORDER BY
SCAN TABLE priceHistory ist der problematische Teil hier. Diese Erklärung bedeutet, dass zum Erfüllen dieser Abfrage die gesamte Tabelle gelesen werden muss. Aber wie groß kann eine solche Tabelle mit etwas Preishistorie schon sein?
du -sh /home/pc-kombo/www.pc-kombo.de/productMeta.db 823M /home/pc-kombo/www.pc-kombo.de/productMeta.db
Upps. Nicht alles davon sind die Preisdaten. Aber der größte Teil.
Um also die Detailseite anzuzeigen musste der Server jedes mal eine 800MB große Tabelle auslesen. Das führte dazu, dass ein Prozessorkern für ein paar Sekunden komplett ausgelastet war (was in Sprachen wie Ruby ohne echten Parallelismus besonders problematisch ist), und auch die Festplatte wurde dadurch natürlich komplett in Beschlag genommen. Kein Wunder, dass dann auch die anderen Seitenaufrufe langsam wurden.
Hier hilft normalerweise ein Index:
CREATE INDEX priceHistory_ean_vendor ON priceHistory(ean, vendor);
Und tatsächlich:
EXPLAIN QUERY PLAN SELECT * FROM priceHistory WHERE ean = "05032037108652" AND (vendor = "vendor1" OR vendor = "vendor2") ORDER BY date ASC; 0|0|0|EXECUTE LIST SUBQUERY 1 0|0|0|USE TEMP B-TREE FOR ORDER BY
Der Index wird direkt genutzt. Und so viel bringt das in Praxis:
Alleine durch diesen einen Index ist die Preishistorie nun nicht mehr der größte Zeitfaktor in der Berechnung, sondern mit 16% einer von mehreren. Und htop
bestätigt das, denn bei dem Seitenaufruf schießt die Prozessorlast des einen Kerns nun nicht mehr auf 100%, sondern bleibt irgendwo unter 10%. Dementsprechend werden auch die anderen Seiten nicht mehr ausgebremst.
Die eigentliche Ursache
Es ist fast immer problematisch, wenn ein Provisorium länger genutzt wird als geplant. Genau das ist hier passiert. Als ich die Preishistorie entwickelte wollte ich die Preise nur für wenige Wochen in der Datenbank speichern. Die eigentliche Lösung sollte eine Zeitseriendatenbank wie rrdtool sein. Solche Datenbanken können die Datenmenge begrenzen, in dem für längere zurückliegende Zeiträume Datenpunkte entfernt werden. Statt den Preis einer Grafikkarte von vor zehn Jahren alle 5 Minuten parat zu haben, speichert rrdtool dann eben nur den Durchschnittspreis einer zehn Jahre zurückliegenden Kalenderwoche. Und bestimmt wäre bei der richtigen Lösung dann auch der Index gesetzt gewesen.
Stattdessen blieb das Provisorium bestehen, bis die Datenmenge so sehr anstieg, dass der fehlende Index – dessen Fehlen beim Entwickeln mit den wenigen Datenpunkten ja noch kein Problem war – den Server ausbremsen konnte.
WebGL zum Größenvergleich von PC-Gehäusen
Ein neues Feature meines Hardwareempfehlers sind Übersichtsseiten für die einzelnen Komponenten. Jede Seite soll so nützlich wie möglich sein: So stehen dort neben den aktuellen Preisen die ganzen Spezifikationen, Bilder, Links zu Reviews und zur Herstellerseite, und bei Prozessoren und Grafikkarten auch die Benchmarkbewertung.
Mein Lieblingsfeature aber ist inspiriert von einem Reddit-Thread. Dort hatte ein Nutzer eine Reihe von Gehäusen mit CAD gerendert, und es war wirklich aufschlussreich die Dimensionen der Gehäuse im Vergleich zu sehen. Sowas wollte ich für die Übersichtsseiten der Gehäuse haben. Mit WebGL und three.js konnte ich es nun bauen.
Das ist das Ergebnis, als Beispiel die Übersichtsseite samt Größendarstellung des NZXT Source 340:
Was ich schon hatte waren die Dimensionen der Gehäuse: Höhe, Breite, Tiefe. Es geht hier nicht darum, detailgetreue Nachbildungen zu schaffen, sondern abstrakt die Größe darzustellen. Dafür reichen diese drei Werte, denn mit ihnen kann man einen Quader zeichnen. Diesen Quader des aktuellen Gehäuses stelle ich dann neben den Quader nach den Durchschnittswerten aller Mid-Tower in der Datenbank, und auf der anderen Seite den Quader nach den Durchschnittswerten aller Mini-Gehäuse.
Three.js erwies sich dabei als hervorragendes Hilfsmittel. Es ermöglicht das Programmieren von WebGL auf einer hohen Abstraktionsebene, dadurch wird es ziemlich einfach. Dazu gibt es für three.js einige Beispiele und eine hilfreiche Dokumentation.
Der gekürzte Code:
var scene = new THREE.Scene(); scene.background = new THREE.Color(0xE5E5E5); scene.fog = new THREE.FogExp2( 0xcccccc, 0.02 ); var camera = new THREE.PerspectiveCamera( 60, 400/300, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( 400, 300 ); document.querySelector('#visualize_size').insertBefore(renderer.domElement, document.querySelector('#case_explanation')); // current case var geometry = new THREE.BoxGeometry(WIDTH, HEIGHT, DEPTH ); var materialCurrent = new THREE.MeshPhongMaterial( { color: 0x156289, emissive: 0x072534, side: THREE.DoubleSide, flatShading: true } ) var cube = new THREE.Mesh( geometry, materialCurrent ); scene.add( cube ); var pointLight = new THREE.PointLight( 0xE6E6FA, 1, 100 ); pointLight.position.set( 10, 10, 10 ); scene.add( pointLight ); var light = new THREE.AmbientLight( 0x222222 ); scene.add( light ); camera.position.set(0.5, 0.5, 2) camera.lookAt(0, 0, 0) controls = new THREE.OrbitControls( camera, renderer.domElement ) var animate = function () { requestAnimationFrame( animate ); renderer.render(scene, camera); }; animate();
Zuerst erstellt dieser Code die Umgebung: Es gibt eine Szene, eine Camera, einen Renderer. Dann wird ein Objekt erstellt, ein Cube (=Quader), mit den Daten des Gehäuses. Das Objekt wird in die Szene gesetzt, dann noch Licht hinzugefügt, die Kamera positioniert und mit den OrbitControls steuerbar gemacht. Der Nutzer kann die Kamera später in alle Richtungen bewegen. Schließlich wird das alles gerendert.
Die Lichter waren knifflig für mich, und da meine Lösung dort wahrscheinlich nicht optimal ist habe ich das auch weitestgehend ausgelassen. Die Farben der Lichter beeinflussen ja die Farbe der Gehäuse, und man will gleichzeitig alle Seiten beleuchten, sie aber alle leicht unterschiedlich haben, sodass die Kanten sichtbar sind. Die Szene braucht dafür noch ein paar Lichter mehr, um die Gehäuse von der anderen Seite zu beleuchten.
In meinem echten Code kommen noch die zwei anderen Gehäuse dazu, um einen Größenvergleich zu haben, und ein Rasternetz unten zur Orientierung.
Ein Problem blieb: Mit den drei Gehäusen nebeneinander hatte man immer noch nicht wirklich eine Idee, wie groß sie in Wirklichkeit sind. Wer sich vorstellen kann, wie groß ein durchschnittliches PC-Gehäuse ist, für den funktionierte das. Doch selbst ich fand das schwierig. Deswegen baute ich eine Banane ein, die rechts neben dem aktuellen Gehäuse steht. Ist zwar ein halber Witz, macht es aber doch einfacher.
Ich bin ziemlich glücklich über das Ergebnis. Besonders die Größen von ITX-Gehäusen zu sehen finde ich interessant. Der Kolink Satellite z.B. ist deutlich kleiner als der Thermaltake Core V1, aber Fractals Node 202 hat nochmal einen ganz anderen Ansatz.
Mich hat es auch gefreut WebGL nutzen zu können. Bisher hatte ich mich immer gefragt, warum man solch eine Technik im Browser haben muss. Hier aber war es eindeutig praktisch, und viel einfacher als ich erwartet hatte.
Ein Blog für pc-kombo
Ich präsentiere - voller Stolz ;) - den pc-kombo Blog, auf dem Artikel über den Hardwareempfehler und sein Umfeld erscheinen werden. Mindestens ist das die Zusammenfassung des monatlichen Updates, so wie der Artikel zum April-Update.
Zwei Blogs gleichmäßig zu befüllen, dafür fehlt es mir eigentlich an Zeit und Material. Aber für einen separaten Blog für den Hardwareempfehler sprach einfach, dass ich dort all die News zeigen kann, die ihn direkt betreffen - ohne hierher verwiesen zu müssen. Gleichzeitig kann ich dort auch Artikel hin auslagern, die hier nicht passen würden. Und was an beiden Stellen passt, das werde ich hier und dort veröffentlichen.
Ich suchte außerdem eine Möglichkeit, meine Blogsoftware in der Praxis zu testen. Das lohnt sich, schon ihn unter /blog/ statt unter / laufen zu lassen brachte ein paar Bugs zutage.
Wer dem Blog eine Chance geben mag, möge doch bitte den Feed abonnieren.
pc-kombo nun vollständiger Hardwarempfehler
Nachdem letzten Monat Arbeitsspeicher dazukam, ist es bei diesem Update alles verbliebene gewesen: Festplatte, SSD, Gehäuse und Netzteil. Damit bin ich über einen jahrelangen Umweg an den Anfang zurückgekehrt: Der Hardwareempfehler empfiehlt nun einen vollständigen, funktionierenden PC.
Im Februar kam nicht viel neue Hardware hinzu. Ich habe mir vorgenommen, in Zukunft genauer zu protokollieren, was hinzugefügt wurde und welche Hardware wegfiel. Vielleicht kommt das in einen separaten Blog. Diesmal noch nicht, aber es waren besonders die Pentium G-Prozessoren, von denen einige Modell hinzugefügt wurden, samt günstigerem Mainboard.
Neue und neue alte Funktionen
Die beim letzten Update weggefallenen Funktionen wurden neu gebaut und wieder eingefügt. Mit den Icons an der Seite kann die Empfehlung modifiziert, also z.B. statt 4GB Ram 8GB ausgewählt werden. Das kleine x oben rechts deaktiviert eine Kategorie temporär, wodurch der Gesamtpreis ohne das jeweilige Hardwareteil neu berechnet wird.
An der Untergrenze wird pc-kombo eine 250 GB große Festplatte empfehlen. Das steigt dann je nach Budget erst auf 1, dann auf 4 TB. Bei höheren Budgets kommt dann eine SSD dazu, schrittweise von 128, 256 und 512 GB bis zur finalen 1 TB SSD. Das einfachste Gehäuse ist ein Sharkoon für 25€, dann kommt das Fractal Design Core 2500 und schließlich ein Fractal Design R4 für ~100€.
Am wackeligsten sind wohl die Empfehlungen des Netzteils. Für die momentanen Empfehlungen funktionieren sie - im Zweifel sind sie überdimensioniert - aber auf Dauer geht das so nicht. Dass teure Prozessoren nicht mehr unbedingt mehr Strom verbrauchen als billigere sorgt dafür, dass der genaue Stromverbrauch erfragt werden muss. Das ist eine der noch bestehenden Baustellen.
Es gibt interne Verbesserungen am Code, was spaßig war. Bei der Oberfläche ist Pace eingebaut, dessen Effekt beim Laden und Modifizieren der Empfehlungen auch wirklich hilft. Die Icons - das €-Zeichen, der Upgrade-Pfeil und das Minus-Zeichen zum Deaktivieren - sind aus Font Awesome.
pc-kombo empfiehlt Arbeitsspeicher
In den Hardwareempfehler pc-kombo habe ich beim monatlichen Update nun Empfehlungen für Arbeitsspeicher eingebaut.
Er empfiehlt DDR3-1600, für Billig-PCs ein 2GB-Modul, für PCs bis 500€ ein 4GB-Kit und für alles darüber ein 8GB-Kit. Man sieht an den harten Grenzen vielleicht: Völlig ausgereift ist das noch nicht, und die Empfehlung basiert auf Tests, subjektive Einschätzung und momentanen Preis, nicht auf Benchmarks. Aber es sind in meinen Augen dennoch sinnvolle Empfehlungen.
Mit der neuen Hardwarekategorie funktionierte das alte Design nicht mehr gut. Zusammen mit den Mainboardempfehlungen geht es jetzt mehr in Richtung vollständigen PC-Empfehler, daher gibt es jetzt eine Listensicht mit integriertem Link zu Amazon, statt wie vorher für die Links eine separate Sektion unten zu haben und den Prozessor neben die GPU zu setzen. Ich finds gut, so geht es langsam wieder zu der Ursprungsidee eines vollständigen PC-Konfigurators zurück. Nur fehlen mir immer noch gute Ideen für den Rest des Interface.
Edit Und der im Screenshot sichtbare kleine Dreher mit der Geforce GTX 690 ist nun auch behoben
Mainboards für pc-kombo
Mein Hardwareempfehler war kaputt. Die Updates liefen nicht und Google hatte etwas an der Chart-Library geändert, wodurch die Farbkodierungen invalid wurden und daher kein Graph mehr erstellt werden konnte. Über das Wochenende habe ich das nun gefixt, und dabei Mainboardempfehlungen eingebaut.
Mainboards zu empfehlen war ein Featurewunsch, der schon ganz am Anfang aufkam, den ich aber damals nicht realisieren zu können glaubte. Mir war nicht klar, wie langsam sich der Prozessormarkt bewegt und wie langlebig Mainboards sind, sodass es gar nicht nötig ist, die Empfehlungen vollständig zu automatisieren. Sie basieren jetzt auf einem Test von Toms Hardware, wobei ich das 990FXA-UD3 selbst habe und durchaus empfehlen kann.
Nun, da Mainbaords schon da sind, könnte es durchaus weiter Richtung vollständigen PC-Konfigurator gehen. Ram und Netzteile sind machbar, aber mir muss ein gutes Interface gelingen, um das deaktivierbar zu machen.
Hardwareempfehler verbessert: Empfehlung ändern
Mein Hardwareempfehler pc-kombo hat ein kleines Update bekommen: Man kann jetzt durch die empfohlene Hardware durchbrowsen. Ist beispielsweise die vorgeschlagene Grafikkarte zu schwach und doch noch Geld übrig, kann sie mit dem Pfeil nach rechts durch die billigste bessere Grafikkarte ausgewechselt werden. Alternativ durch die beste billigere, wenn sie zu teuer ist.
Die Buttons sind natürlich die skalierten Canvase, über die ich geschrieben habe.
Im Hintergrund ist das eine komplett neue Software. Statt Java mit handgeschriebenem Server ist es Ruby mit Sinatra. Anfangs nur ein Klon der alten Seite, ermöglichte es mir der Wechsel überhaupt erst, diese Ajax-Erweiterungen einzubauen, vorher wäre das viel zu kompliziert gewesen. Und so hielt ich die Hardwareerkennung auch das erste mal für solide genug, automatisch die Datenbank zu updaten. Wöchentlich wird jetzt Amazon nach neuer Hardware und Google nach neuen Preisen gefragt (die Beispiele sind immer aktuell).
Zuerst wollte ich die Oberfläche komplett über den Haufen werfen. Ich dachte erst an Punkte auf dem Performance-Balken, welche die verschiedenen Prozessoren/Grafikkarten anzeigen und auf die man klicken kann, um sie zu wechseln. Oder ein Slider auf einem Preis-Balken mit der Leistung als Säulendiagramm. Daraus wurde dann ein Karussell-artiges Widget, auf dem die Punkte platziert werden, da ich nicht wusste, wieviel Hardware er jeweils empfiehlt und ob der Platz auf einem normalen Balken ausreichen würde. Dazu sollte dann tooltipp-artig die gewählte Hardware angezeigt und im Hintergrund noch ein Balken die Leistung anzeigen. Auf Papier sah das ganz gut aus. Mitten im Bauen davon wurde mir bewusst, dass die wirklich wichtige Funktion davon ist, bessere und billigere Hardware zu wählen, was recht simpel in die alte Oberfläche zu integrieren sein müsste. Stimmte dann auch. Zum Glück, denn das Karussell-Widget in schön zu bauen hätte mich sehr viel Zeit gekostet.
Das gute an den ganzen Überlegungen ist, dass der Kernalgorithmus davon profitiert hat. Das war ein ziemlich wilder Optimierungsversuch aus allen möglichen Kombinationen. Durch ein Diagramm mit Leistung als y-Achse und Preis als x-Achse wurde mir klar, dass im Grunde nur die beste Hardware im Preisbereich ausgewählt werden muss. Dadurch wurde der ganze Algorithmus wesentlich weniger komplex (auch im Sinne der O-Notation) und so schneller. Überhaupt wurde das "wähle die nächstbessere Grafikkarte" durch diese Grundüberlegung erst wirklich möglich.
Wieder viele Änderungen im Hintergrund, wovon man die wenigsten direkt sieht. Aber die Ändern-Pfeile bemerkt man vermutlich schon direkt. Mich würde interessieren: Funktioniert die Seite mit den Pfeile so für dich?
APUs integriert
Obwohl der Hardwareempfehler möglichst automatisch ablaufen soll, sind manchmal manuelle Anpassungen nötig. So kamen die APUs in die Hardwaredatenbank, also Prozessoren mit integrierter Grafikkarte. Und es passierte prompt, was nicht passieren sollte: Die Prozessoren wurden manchmal mit Grafikkarten kombiniert, die schlechter waren als die integrierten. Ich habe jetzt Code eingebaut, das zu verhindern, bei der momentanen Empfehlung für 150€ sieht man das ganz gut:
PC-Kombo: Neue Hardware, neuer Benchmark
Das ist jetzt ein typischer Fall von Entwickler != Nutzer. Von meiner Position aus hat sich in der neuen Version des Hardwareempfehlers sehr viel verändert. So ist zum Beispiel die Architektur eine andere (an die jetzige Aufgabe zugeschnitten statt universeller Konfigurator) und die Datenbank SQL statt einer Objektdatenbank, was bessere Updates ermöglicht. Doch von außen? Sieht es erstmal gleich aus.
Also doch ein paar Worte zu eher internen Änderung.
Neue Hardware
Der Prozessor A8-3850 ist ziemlich neu, Amazon listet erst zwei Modelle der Reihe. Im Empfehler ist er schon drin.
Ich werde nicht jedes neue Update von Hardware ankündigen, es ist klar, dass regelmäßig neue Hardware eingepflegt werden muss. Aber man kann an diesem sehen, dass das Einpflegen neuer Hardware generell gut und potentiell schnell funktioniert.
Neuer Benchmark
Bisher basierten die Empfehlungen auf dem Benchmark Passmark. Die Performance von Hardware über generische Benchmarks zu ermitteln ist problematisch, denn das Benchmarkergebnis sagt nicht unbedingt etwas über die tatsächliche Leistung in echten Anwendungen (wie Spielen) aus. Manche der Passmark-Positionen sind auch eher fragwürdig (wenige, zum Glück).
Am liebsten wäre mir ein Spielebenchmarks der drei letzten Grafikmonster, jeweils eine CPU mit allen Grafikkarten und alle Prozessoren mit einer Grafikkarte.
Machbare Alternative ist ein Metabenchmark, die Ergebnisse mehrerer Benchmarks nehmen und kombinieren. Und deshalb basieren die Empfehlungen jetzt zusätzlich auf Futuremark, auch wenn die Seite das noch nicht anzeigt.
Das wars, zumindest mit den wahrnehmbaren Änderungen.
Wobei, eine optische Änderung gibt es doch noch. Unten rechts im Footer ist ein kleiner +1-Button eingebunden. Wäre toll, wenn auf den noch ein paarmal geklickt werden würde.
PC-Kombo in etwas neu
Der Hardwareempfehler hing auf einem Server fest, zu dem ich nicht mehr wirklich Zugang hatte, sodass die neue Version nicht erscheinen konnte. Dann war die Seite auch noch down. Nun ist die neue Version auf einem anderen Server mit neuem Design, kürzerer Ladezeit und frischer(er) Hardware:
Keine Mainboards, weil ich immer noch keine gute Datenquelle dafür gefunden habe. Die Amazon-Api hat sich dafür bisher als zu ungenau erwiesen.
Rückmeldung wie immer erbeten: Über einen Bug gestolpert? Gefällt das Aussehen?