Verlauf meines Startups: 500.000 Benutzer in 5 Tagen auf einem 100-Dollar-Server

Ursprünglicher Autor: Erik Duindam
  • Übersetzung
Anscheinend sind sich alle in der Startup-Welt einig, dass die ersten Versionen von Anwendungen ein Produkt mit minimaler Lebensfähigkeit (MVP, Minimal Viable Product) sein sollten, das Sie aus technischer Sicht nicht wirklich skalieren müssen. Ich habe oft gehört, dass es in solchen Angelegenheiten am wichtigsten ist, schnell etwas freizugeben, das funktioniert. Und solange das Geschäftsmodell im Kontext eines wachsenden Kundenstamms normal funktioniert, ist alles in Ordnung. Und es lohnt sich nicht, Zeit und Geld für die Entwicklung eines Systems aufzuwenden, das dem plötzlichen Zustrom von Benutzern standhält. Alles, worüber Sie sich Sorgen machen müssen, ist die Überprüfung Ihrer Annahmen, die Bewertung des Marktes und die Förderung Ihres Geschäfts. Die Skalierbarkeit kann auf einen späteren Zeitpunkt verschoben werden. Leider hat ein derart blindes Vertrauen in stereotype Ideen immer wieder zu ohrenbetäubenden Misserfolgen geführt. Pokémon GO und



Jonathan Zarra, der Entwickler von GoChat, wird diesen Fehler sicherlich nicht noch einmal machen. Innerhalb von 5 Tagen hat er eine Million Nutzer gewonnen und eine Chat-Anwendung für Pokémon GO-Fans erstellt. Anhand des oben genannten Materials können Sie feststellen, dass er mit Investoren über die Monetarisierung und Erweiterung der Anwendung gesprochen hat. Gleich danach stürzte GoChat ab. Viele Benutzer gingen verloren und es wurde viel Geld ausgegeben. Immerhin ist die Idee genial und damit eine echte Schande. Ja, ich habe übrigens ein paar Tage nach dem Schreiben die Originalversion dieses Artikels geringfügig überarbeitet, da GoChat noch bei Google Play läuft und mehr als zwei Millionen Nutzer hat. Es wird erwartet, dass die iOS-Version bald wieder hergestellt wird.

Zarra hatte es schwer: Er musste für die Server bezahlen, die zur Unterstützung einer Million aktiver Benutzer erforderlich waren. Er glaubte nicht, dass es ihm gelingen würde, ein solches Publikum anzuziehen. Er erstellte die Anwendung in den besten Traditionen von MVP und ließ die Sorge um eine spätere Skalierung hinter sich. Generell kann man sagen, dass er sein Vorhaben zunächst zum Scheitern verurteilt hat. Als sich Probleme mit der Anwendungsarchitektur zeigten, beauftragte Zarra einen Upwork-Programmierer mit der Behebung zahlreicher Leistungsprobleme. Er sagte, dass die Serverkosten in der Region von 4000 $ liegen. Es ist 2016, daher kann man davon ausgehen, dass es nicht um den Kauf von "eisernen" Servern geht. Diese 4.000 US-Dollar sind die Kosten für eine jährliche oder monatliche Anmietung von virtuellen Servern und für Verkehrsgebühren.

Fast mein ganzes Berufsleben lang habe ich Webplattformen für Hunderte Millionen aktiver Benutzer entworfen und gebaut. Und ich kann sagen, dass 4.000 US-Dollar pro Server zu viel für eine Million Chatter sind. Auch für MVP. Dies deutet darauf hin, dass die Serverseite der Anwendung schlecht gestaltet ist. Tatsächlich ist es nicht so einfach, ein kostengünstiges und dennoch skalierbares System für Millionen monatlich aktive Benutzer zu erstellen. Dies geht jedoch nicht über die menschlichen Fähigkeiten hinaus - Sie müssen eine Kombination von Software verwenden, mit der Sie ein seriöses Publikum auf kostengünstigen Cloud-Servern unterstützen können. Dies sollte bei der Auswahl der richtigen Komponenten bei der Erstellung von MVP berücksichtigt werden.


GoSnaps: 500.000 Benutzer an 5 Tagen auf dem Server für 100 US-Dollar pro Monat


GoChat erlaubte Spielern in Pokémon GO zu chatten, in der offiziellen Anwendung können sie dies nicht tun. Ich habe ein Projekt namens GoSnaps erstellt , das sich auch an Pokémon GO-Fans richtet . Dies ist eine mobile Anwendung, mit der Benutzer Screenshots und Bilder mit Bezug auf die Karte freigeben können. Dies ist so etwas wie Instagram oder Snapchat für Pokémon GO.

Am ersten Tag gewann GoSnaps 60.000 Nutzer. In der zweiten - es gab bereits 160 Tausend von ihnen, am fünften Tag (dem Moment des Schreibens dieses Materials) gab es bereits eine halbe Million von ihnen. Zu diesem Zeitpunkt haben Benutzer ungefähr 200.000 Bilder in das System hochgeladen. Zu jeder Zeit nutzen ungefähr 1000 Personen die Anwendung gleichzeitig. Ich habe ein Bilderkennungs-Subsystem erstellt, um automatisch zu überprüfen, ob das hochgeladene Bild etwas mit Pokémon GO zu tun hat, und um die Größe der hochgeladenen Bilder zu ändern. All dies funktioniert auf einem ganz normalen Server von Google Cloud, dessen Miete 100 US-Dollar pro Monat kostet. Hinzu kommt der kostengünstige Google Cloud-Speicher, in dem Bilder gehostet werden. Es geht um hundert Dollar im Monat, nicht um Tausende. In diesem Fall funktioniert alles gut.

GoChat vs GoSnaps Vergleich


Vergleichen Sie GoChat und GoSnaps. In beiden Anwendungen werden wahrscheinlich viele Abfragen pro Sekunde ausgeführt, um Chats oder Bilder in einem bestimmten Bereich der Karte anzuzeigen. Dies ist eine räumliche Suche in einer Datenbank (oder in einer Suchmaschine), die entweder innerhalb eines bestimmten Polygons auf einer Karte oder - für einen bestimmten Punkt durchgeführt wird, der durch Breite und Länge definiert ist. Wir verwenden ein Polygon, Anforderungen werden jedes Mal ausgeführt, wenn der Benutzer die Karte verschiebt. Solche Abfragen belasten die Datenbank erheblich, insbesondere in Kombination mit dem Sortieren oder Filtern von Daten. GoSnaps muss solche Suchanfragen hunderte Male pro Sekunde verarbeiten. Wahrscheinlich passiert dasselbe im Darm von GoChat.

Eine Funktion von GoChat ist, dass die Anwendung jede Sekunde aus der Datenbank abrufen und Benutzern viele Chat-Nachrichten senden muss. Der GoChat-Artikel behandelt ungefähr 600 Anfragen pro Sekunde für die gesamte Anwendung. Diese 600 Anfragen sind eine Kombination aus Kartenanfragen und Chatnachrichten. Nachrichten sind klein, Sie können (oder müssen) mit ihnen über einfache Sockets arbeiten. Nachrichten werden jedoch häufig angezeigt und müssen auf viele Benutzer verteilt werden, die sich im Chat befinden. Es ist durchaus möglich, mit dieser Situation umzugehen, wenn der Softwareteil der Lösung richtig organisiert ist. Wenn wir es mit einer schlecht gestalteten MVP-Anwendung zu tun haben, kann der Chat-Support eine überwältigende Aufgabe sein.

Auf der anderen Seite hat GoSnaps viele Bilder, die jede Sekunde aus dem Speicher heruntergeladen werden. Bilder werden auf dem Server gespeichert, da auch alte Bilder nicht an Relevanz verlieren. Gleichzeitig werden veraltete Chats von GoChat nicht mehr benötigt. Da die Bilddateien in Google Cloud Storage gespeichert sind, stört mich die Anzahl der angeforderten Bilddateien als Entwickler nicht. All dies wird von Google Cloud ausgeführt, und ich bin mir der Funktionen von Google sicher. Aber die angeforderten Bilder, die mit der Karte verlinkt sind, stören mich schon sehr.

GoSnaps verfügt über ein Bilderkennungssubsystem, das nach Mustern in vom Benutzer hochgeladenen Bildern sucht, um zu überprüfen, ob diese Bilder mit Pokémon GO zusammenhängen oder nicht. Darüber hinaus ist dieses Subsystem damit beschäftigt, die Größe von Bildern zu ändern und sie an den Cloud-Speicher zu senden. All dies ist ressourcenintensiv, was die CPU-Auslastung und den Verkehrsverbrauch betrifft. Diese Aktionen sind viel schwieriger als das Verteilen einer bestimmten Anzahl kleiner Chat-Nachrichten, werden jedoch seltener ausgeführt.

Das Obige lässt mich zu dem Schluss kommen, dass sich beide Anwendungen in Bezug auf die Komplexität der Skalierung sehr ähnlich sind. GoChat verarbeitet mehr kleine Nachrichten, während GoSnaps mit größeren Bildern arbeitet und serverintensivere Vorgänge ausführt. Das Design und die Architektur dieser beiden Anwendungen erfordern bei nahezu gleicher Komplexität einen etwas anderen Ansatz.

So erstellen Sie ein skalierbares MVP in 24 Stunden


GoSnaps wurde als MVP erstellt, nicht als professionelles Geschäftsprodukt. Er war in 24 Stunden komplett fertig. Ich habe die Node.js-Vorlage für Hackathons verwendet und die MongoDB-Datenbank ohne Zwischenspeicherung verwendet. Im Projekt wird nichts anderes verwendet: weder Redis noch Varnish noch die komplizierten Nginx-Schemata. Die iOS-Anwendung wurde in Objective-C geschrieben. Ein Teil des Codes für die Arbeit mit Apple Maps stammt aus unserer Unboxd- Hauptanwendung . Wie habe ich es geschafft, GoSnaps skalierbar zu machen? In der Tat - nur weil ich nicht faul war, den schädlichen Kanonen von MVP zu folgen.

Angenommen, ich würde die Erstellung von MVP nur als Wettlauf gegen die Zeit betrachten, mit dem Ziel, eine funktionierende Anwendung so schnell wie möglich freizugeben, ohne auf die Qualität der Serverseite zu achten. Wo sollen in diesem Fall Bilder gespeichert werden? Natürlich in der Datenbank, in MongoDB. Hierfür sind keine zusätzlichen Einstellungen erforderlich, und der Code ist erforderlich - überhaupt nichts. Sehr einfach. Im Geiste von MVP. Wie kann man aus der Datenbank Bilder aus einem bestimmten Bereich auf der Karte anfordern, die die meisten Likes haben? Es reicht aus, eine regelmäßige Anfrage an MongoDB zu stellen, die das gesamte dort gespeicherte Bildvolumen abdeckt. Eine Anforderung an einen Datensatz in der Datenbank. Wieder - MVP. All dies würde meine Anwendung zerstören und die Nutzung ihrer Funktionen unmöglich machen.

Werfen wir einen Blick auf die Abfrage, die ich ausführen müsste, um die obigen Bilder aus der Datenbank zu erhalten. Es würde ungefähr so ​​aussehen: „Finde alle Bilder, die zu dem Gebiet auf der Karte gehören [A, B, C, D], mit Ausnahme derer, die als ungültig markiert sind und die noch verarbeitet werden, sortiert nach der Anzahl der Likes, nach ob sie mit Pokémon GO verwandt und nach Neuheiten sortiert sind. " Bei einem kleinen Datensatz würde eine solche Abfrage problemlos funktionieren. Wenn es sich jedoch um eine schwerwiegende Belastung handelt, werden solche Aufrufe der Datenbank das gesamte System zum Erliegen bringen. Dies ist auch dann der Fall, wenn Sie die obige Anforderung so vereinfachen, dass sie nur drei Bedingungen und Sortiervorgänge enthält. Warum? Denn für diesen Ansatz ist die Datenbank nicht ausgelegt. Der Zugriff auf die Datenbank sollte jeweils nur mit einem Index erfolgen, was bei geografischen Abfragen nicht möglich ist. Wenn die Anwendung nur wenige Benutzer hat, ist ein solches Design sehr funktional. Aber wenn die Anwendung plötzlich erfolgreich wird, wird es ihn töten. Wie eigentlich bei GoChat passiert.

Was habe ich stattdessen getan? Nachdem ressourcenintensive Vorgänge zum Analysieren und Ändern der Größe von Bildern ausgeführt wurden, werden die verarbeiteten Bilder in Google Cloud Storage hochgeladen. Aus diesem Grund sind Server und Datenbank nicht mit der Ausgabe von Bildern an Benutzer belastet. Die Datenbank sollte sich um die Daten kümmern, nicht um die Bilder. Auf diese Weise können Sie erheblich an Servern sparen.

Im Hinblick auf die Organisation der Datenbank habe ich die Bilder in mehrere Sets aufgeteilt. Dies sind alles Bilder, die beliebtesten, die neuesten, die neuesten, die für das Thema von Pokémon GO geeignet sind, und so weiter. Wenn Benutzer neue Bilder wie diese hinzufügen und als ungültig markieren, überprüft der Code, ob die Bilder zu einer der Gruppen gehören, und handelt entsprechend.

Bei diesem Ansatz werden Abfragen für vorbereitete Datasets ausgeführt, anstatt komplexe Aufrufe für einen großen Haufen unstrukturierter Datensätze auszuführen. Dies ist das Ergebnis der logischen Aufteilung der Daten in mehrere einfache Blöcke. Nichts kompliziertes. Dies ermöglichte mir jedoch, Abfragen nur für Geokoordinaten mit einer Sortieroperation anstelle der oben beschriebenen komplexen Abfrage auszuführen. Einfach ausgedrückt vereinfacht dieser Ansatz die Datenerfassungsvorgänge so weit wie möglich.

Wie viel Zeit habe ich für all diese Verbesserungen aufgewendet? 2-3 Stunden, nicht mehr. Warum habe ich das überhaupt gemacht? Weil ich es gewohnt bin, auf diese Weise zu arbeiten. Ich gehe davon aus, dass meine Bewerbung auf Erfolg wartet. Ich würde nicht schlafen können, wenn meine Entwicklung an Popularität gewinnen würde, und dann nur unter die Last fallen, weil sie schlecht gestaltet ist. Ich habe minimal realisierbare Skalierungsprinzipien in die Anwendung integriert. Dies ist der Unterschied zwischen Glück aus Erfolg und Hoffnungslosigkeit. Dies sollte meiner Meinung nach Teil der Ideologie von MVP-Anwendungen sein.

Auswahl der richtigen Tools zur Implementierung von MVP


Wenn ich GoSnaps in einer langsameren Codeausführungsumgebung oder auf Basis eines schleppenden Frameworks erstellen würde, würde ich mehr Server benötigen. Wenn ich PHP mit Symfony oder Python mit Django oder Ruby on Rails verwenden würde, würde ich entweder den ganzen Tag damit verbringen, die langsamen Komponenten zu beschleunigen, oder nur wissen, welchen Servern ich hinzufügen soll. Sie können glauben: Ich musste das schon durchmachen. Diese Sprachen und Frameworks eignen sich hervorragend für viele Szenarien, jedoch nicht für MVPs mit einem kleinen Server-Budget. Dies liegt hauptsächlich an den vielen Codeebenen, die normalerweise für die Arbeit mit Daten aus Datenbanken in Programmen verwendet werden, und an den unzumutbaren Funktionen von Frameworks. All dies belastet den Server zu sehr. Lassen Sie mich Ihnen ein Beispiel geben, wie viel dies wirklich bedeutet.

Wie gesagt, die Serverseite von GoSnaps basiert auf Node.js. Diese Plattform ist insgesamt schnell und effizient. Ich habe Mongoose als ORM verwendet, um die Programmierung mit MongoDB zu vereinfachen. Ich betrachte mich nicht als Mungo-Experten und weiß, dass diese Bibliothek eine riesige Codebasis hat. Also habe ich Mungo mit einem großen Fragezeichen versehen. Aber ja, wir reden über MVP. In jüngerer Zeit haben 4 Node.js-Prozesse auf unserem Server jeweils ungefähr 90% der CPU-Ressourcen verbraucht, was für mich bei ungefähr tausend gleichzeitigen Benutzern inakzeptabel ist. Mir ist aufgefallen, dass Mongoose höchstwahrscheinlich etwas mit den empfangenen Daten macht. Offensichtlich musste ich nur die Mongoose Lean () - Funktion aktivieren, um reguläre JSON-Objekte anstelle von genialen Mongoose-Objekten zu erhalten. Nach dieser Änderung wurde der Server von Node.js-Prozessen um etwa 5 bis 10% geladen. Einfache Entscheidungen basierend auf dem Wissen, was der Code tatsächlich tut, sind sehr wichtig. In meinem Fall wurde die Last um 90% reduziert. Stellen Sie sich nun vor, wir hätten eine sehr umfangreiche Bibliothek wie Symphony with Doctrine. Ein solcher Koloss würde ein Paar Multiprozessor-Server benötigen, um seinen eigenen Code zum Laufen zu bringen, selbst wenn man berücksichtigt, dass der Engpass des Systems die Datenbank und nicht die Softwaremechanismen ist.

Die Wahl einer wirtschaftlichen und schnellen Umgebung für die Codeausführung ist für die Skalierbarkeit wichtig, wenn die Bezahlung von Servern für Ihr Projekt kein Problem darstellt. Die Wahl einer Programmiersprache mit vielen nützlichen Bibliotheken ist umso wichtiger, als MVPs in der Regel so schnell wie möglich erstellt werden müssen. Node.js, Scala und Go sind Umgebungen und Sprachen, die beide Bedingungen erfüllen. Sie haben sowohl eine hohe Leistung als auch viele Bibliotheken. Sprachen wie PHP oder Java sind an sich nicht unbedingt langsam, werden jedoch normalerweise in Verbindung mit großen Frameworks und Bibliotheken verwendet, die Anwendungen schwerer machen. Diese Sprachen eignen sich für die reine objektorientierte Entwicklung und bewährten Code, nicht jedoch für die Erstellung von Anwendungen, die schnell und kostengünstig skaliert werden können. Ich möchte hier keinen heiligen Krieg beginnen, also lass es mich einfach sagen Das alles ist meine subjektive Meinung, die nicht durch eine gründliche und vollständige Analyse aller Details gestützt wird. Zum Beispiel liebe ich Erlang, aber ich würde es nie für eine MVP-Anwendung verwenden, daher halte ich jede Debatte zu diesem Thema für sinnlos.

Meine vorherigen Startup-Cloud-Spiele


Vor einigen Jahren wurde ich einer der Gründer des Cloud Games- Projekts.- Plattformen für die Veröffentlichung von HTML5-Spielen. Als alles begann, waren wir eine B2C-Spieleseite für die MENA-Region. Wir haben große Anstrengungen unternommen, um ein Publikum anzuziehen, und in wenigen Monaten haben wir eine Million monatlich aktiver Benutzer (MAU) erreicht. Zu dieser Zeit verwendete ich PHP, Symphony2, Doctrine und MongoDB in einer sehr einfachen und wirtschaftlichen Konfiguration. Ich habe bei Spil Games mit 200 Millionen MAUs mit PHP gearbeitet und bin dann zu Erlang gewechselt. Nachdem Cloud Games ungefähr 100.000 MAU erreicht hatte, kam es zu einer Serverüberlastung. Der Grund war Doctrine und MongoDB. Ich habe MongoDB, Indizes und Abfragen korrekt konfiguriert, aber die Server haben den Code kaum verwaltet. Ich habe den PHP-APC-Cache verwendet und so weiter, aber ohne großen Erfolg.

Seit cloudgames.comWar die Site ziemlich statisch, konnte ich dieses MVP-Projekt mit Redis in nur wenigen Tagen auf Node.js übertragen. Das Ergebnis war eine ähnliche Funktionalität, jedoch in einer anderen Umgebung. Dies führte zu einem sofortigen Rückgang der Serverlast um etwa 95%. Ich gebe zu, der Punkt hier ist, dass wir es geschafft haben, die schweren PHP-Bibliotheken loszuwerden und nicht die Laufzeit oder Sprache der Anwendung zu wählen. Die minimale Arbeitskonfiguration von Node.js ist jedoch viel funktionaler als die minimale PHP-Konfiguration. Insbesondere, wenn man bedenkt, dass sowohl MongoDB als auch der Front-End-Teil des Projekts zu 100% aus JavaScript bestehen, wie Node.js. PHP ohne Frameworks und Bibliotheken ist nur eine von vielen Programmiersprachen.

Wir brauchten eine so leichte Konfiguration, da wir zu einem frühen Zeitpunkt der Entwicklung ein selbstfinanziertes Startup waren. Cloud Games zeigt heute gute Ergebnisse. Das Projekt basiert immer noch auf Node.js. Wir hätten keinen Erfolg haben können, wenn wir Technologien verwendet hätten, die große Investitionen erfordern, da es im Leben von Cloud Games als Start-up schwierige Zeiten gab. Der Entwurf einer wirtschaftlichen, skalierbaren Architektur ist zu einer der wichtigsten Voraussetzungen für den Erfolg geworden.

Zusammenfassung: MVP und Skalierbarkeit können gleichzeitig vorhanden sein


Wenn Ihre Anwendung aufgrund des explosionsartigen Interesses an ihr oder einer möglichen Medienberichterstattung ein exponentielles Wachstum aufweisen kann, sollten Sie die Skalierbarkeit als Teil der MVP-Strategie berücksichtigen. Die Prinzipien des Minimums an Produktlebensfähigkeit und Skalierbarkeit können nebeneinander existieren. Es gibt nichts Traurigeres, als eine erfolgreiche Anwendung zu erstellen und anwesend zu sein, wenn sie aufgrund technischer Probleme versagt. Und Pokémon GO selbst hatte viele Probleme, aber das Projekt ist so einzigartig und PR, dass es nicht wirklich wichtig war. Kleine Startups können sich solchen Luxus nicht leisten. Timing ist alles . Eine Million GoChat-Benutzer und eine halbe Million GoSnaps-Benutzer werden mir wahrscheinlich zustimmen.

Jetzt auch beliebt: