Wie ich eine App mit 500.000 Nutzern in 5 Tagen auf einem 100-Dollar-Server erstellt habe

In der Welt der Startups scheint es einen allgemeinen Konsens zu geben, dass Sie ein MVP (Minimum Viable Product) erstellen sollten, ohne sich zu sehr um die technische Skalierbarkeit zu kümmern. Ich habe oft gehört, dass die einzige Priorität darin besteht, das Produkt einfach auf den Markt zu bringen. Solange Ihr Geschäftsmodell skalierbar ist, sind Sie gut. Sie sollten keine Zeit und kein Geld damit verschwenden, ein technisch skalierbares Produkt herzustellen. Alles, worüber Sie sich Gedanken machen, ist, Ihre Annahmen zu testen, den Markt zu validieren und an Boden zu gewinnen. Skalierbarkeit ist ein Problem für später. Leider hat dieser etwas blinde Glaube zu einigen schrecklichen Misserfolgen geführt. Und Pokémon GO hat uns daran erinnert.

Eine Person, die diesen Fehler nicht noch einmal begeht, ist Jonathan Zarra, der Schöpfer von GoChat für Pokémon GO. Der Typ, der innerhalb von 5 Tagen 1 Million Benutzer erreicht hat, indem er eine Chat-App für Pokémon GO-Fans erstellt hat. Wie Sie im Artikel lesen können, sprach er letzte Woche mit VCs, um zu sehen, wie er seine App vergrößern und monetarisieren kann. Gleich danach fiel GoChat aus. Viele Benutzer haben verloren und viel Geld ausgegeben. Eine echte Schande für einen genialen Schachzug.

In dem Artikel heißt es, dass es Zarra schwerfiel, für die Server zu bezahlen, die für das Hosten von 1 Million aktiven Benutzern erforderlich waren. Er hätte nie gedacht, so viele Benutzer zu bekommen. Er baute diese App als MVP und kümmerte sich später um die Skalierbarkeit. Er hat es gebaut, um zu scheitern. Zarra beauftragte einen Vertragspartner mit Upwork, um viele Leistungsprobleme zu beheben. Der Auftragnehmer gab an, dass die Serverkosten rund 4.000 US-Dollar betrugen. Da in meinem Kalender das Jahr 2016 verzeichnet ist, geht er vermutlich nicht von 4000 US-Dollar Hardware aus, sondern von 4000 US-Dollar monatlichen oder jährlichen Kosten für virtuelle Server und Datenverkehr.

Ich habe die meiste Zeit meiner Karriere Webplattformen für Hunderte Millionen aktiver Benutzer entworfen und erstellt. Ich kann sagen, dass 4.000 US-Dollar für 1 Million Nutzer in einer Chat-App völlig unnötig sind. Auch für einen MVP. Dies bedeutet, dass die Servertechnologie der App schlecht konzipiert wurde. Es ist nicht einfach, ein kostengünstiges, skalierbares System für Millionen von monatlichen Benutzern zu erstellen. Es ist aber auch nicht sonderlich kompliziert, eine Einrichtung zu haben, die zumindest eine anständige Anzahl von Benutzern auf einigen billigen Servern in der Cloud unterstützt. Sie müssen dies nur beim Erstellen des MVP berücksichtigen, indem Sie die richtigen Entscheidungen treffen.

GoSnaps: 500.000 Benutzer in 5 Tagen auf einem Server mit 100 USD / Monat

Ähnlich wie GoChat habe ich letzte Woche auch eine Pokémon GO-Fan-App namens GoSnaps gestartet. GoSnaps ist eine App zum Teilen von Pokémon GO-Screenshots und Bildern auf einer Karte. Das Instagram / Snapchat für Pokémon GO. GoSnaps wuchs am ersten Tag auf 60.000 Benutzer, am zweiten Tag auf 160.000 Benutzer und nach 5 Tagen auf 500.000 eindeutige Benutzer (was jetzt der Fall ist). Es wurden jetzt 150–200.000 Schnappschüsse hochgeladen. Es hat ungefähr 1000 gleichzeitige Benutzer zu einem bestimmten Zeitpunkt. Ich habe eine Bilderkennungssoftware entwickelt, um automatisch zu überprüfen, ob ein hochgeladenes Bild mit Pokémon GO zusammenhängt, und um die Größe von Tools für hochgeladene Bilder zu ändern. Wir führen das gesamte Setup auf einem mittelgroßen Google Cloud-Server für 100 US-Dollar pro Monat sowie (günstigem) Google Cloud-Speicher für die Speicherung von Bildern aus. Ja, 100 US-Dollar. Und es funktioniert gut.

Technischer Vergleich von GoChat und GoSnaps

Vergleichen wir GoChat und GoSnaps. Beide Apps lösen wahrscheinlich viele Anfragen pro Sekunde aus, um Chats / Bilder in einem bestimmten Bereich der Karte abzurufen. Dies ist eine räumliche Suche in der Datenbank (oder Suchmaschine), entweder nach einem Polygon von Breiten- / Längengradpositionen oder nach einem bestimmten Punkt. Wir verwenden ein Polygon und lösen diese Anforderung jedes Mal aus, wenn jemand die Karte verschiebt. Diese Abfragetypen sind schwere Vorgänge in einer Datenbank, insbesondere in Kombination mit dem Sortieren oder Filtern. Wir erhalten diese Art von Suchanfragen hunderte Male pro Sekunde. GoChat hat es wahrscheinlich auch getan.

Einzigartig für GoChat ist, dass es jede Sekunde viele Chat-Nachrichten abrufen und veröffentlichen musste. Der Artikel über GoChat spricht über 600 Anfragen pro Sekunde für die gesamte App. Diese 600 Anfragen sind eine Kombination aus Kartenanfragen und Chatnachrichten. Diese Chatnachrichten sind klein und können / sollten über eine einfache Socket-Verbindung erfolgen, kommen jedoch häufig vor und müssen an andere Chatter verteilt werden. Dies ist mit dem richtigen Setup machbar, aber mit einem schlechten, MVP-ähnlichen Setup katastrophal.

Auf der anderen Seite werden bei GoSnaps jede Sekunde viele Bilder abgerufen und „gemocht“. Die Snaps häufen sich auf dem Server an, da alte Snaps relevant bleiben. Alte Chats nicht. Da die eigentlichen Bilddateien im Google Cloud-Speicher gespeichert sind, ist die Anzahl der angeforderten Bilddateien für mich als Entwickler kein Problem. Google Cloud kümmert sich darum und ich vertraue Google. Aber die angeforderten Schnappschüsse auf der Karte sind mein Anliegen. GoSnaps verfügt über eine Bilderkennungssoftware, die bei allen Uploads nach Mustern sucht, um festzustellen, ob ein Bild mit Pokémon zusammenhängt oder nicht. Es ändert auch die Größe der Bilder und sendet sie an den Cloud-Speicher. Dies sind alles schwere Vorgänge in Bezug auf CPU und Bandbreite. Viel schwerer als das Verteilen einiger kleiner Chat-Nachrichten, aber weniger häufig.

Mein Fazit ist, dass sich beide Apps hinsichtlich der Komplexität der Skalierbarkeit sehr ähnlich sind. GoChat verarbeitet mehr kleine Nachrichten, während GoSnaps größere Bilder und schwerere Servervorgänge verarbeitet. Das Entwerfen einer Architektur für diese beiden Apps erfordert einen etwas anderen Ansatz, ist jedoch ähnlich komplex.

Wie ich in 24h ein skalierbares MVP gebaut habe

GoSnaps ist als MVP und nicht als professionelles Geschäftsprodukt konzipiert. Es wurde komplett in 24 Stunden gebaut. Ich nahm ein NodeJS-Boilerplate-Projekt für Hackathons und verwendete eine MongoDB-Datenbank ohne jegliche Form von Caching. Keine Redis, kein Lack, keine ausgefallenen Nginx-Einstellungen, nichts. Die eigentliche iOS-App wurde in nativem Objective-C-Code erstellt, mit etwas ausgeliehenem Apple Maps-Code von Unboxd, unserer Haupt-App. Wie habe ich es skalierbar gemacht? Indem ich nicht faul bin.

Nehmen wir an, ich würde einen MVP als einen Wettlauf gegen die Zeit betrachten, um eine funktionierende App so schnell wie möglich zu erstellen, unabhängig von der Qualität des technischen Backends. Wo hätte ich meine Bilder hingelegt? In der Datenbank: MongoDB. Es würde keine Konfiguration und fast keinen Code erfordern. Einfach. MVP. Wie hätte ich die Schnappschüsse in einem bestimmten Bereich abgefragt, der am meisten gefallen hat? Durch einfaches Ausführen einer MongoDB-Abfrage für den gesamten Stapel hochgeladener Snaps. Nur eine Datenbankabfrage für eine Datenbanksammlung. MVP. All dies hätte meine App und die App-Funktion zerstört.

Schauen Sie sich die Abfrage an, die ausgeführt werden musste, um diese Snaps zu erhalten: „Finde alle Snaps innerhalb des Positionspolygons [A, B, C, D] Likes, zuerst nach gültigen Pokémon GO-Schnappschüssen und dann nach den neuesten zuerst sortiert “. Dies funktioniert hervorragend mit einem kleinen Datensatz, großartig, MVP. Dies wäre jedoch bei jeder ernsthaften Belastung eine Katastrophe gewesen. Selbst wenn ich die obige Abfrage so vereinfacht hätte, dass sie nur drei Bedingungen / Sortiervorgänge enthält, wäre sie katastrophal gewesen. Warum? Denn so soll eine Datenbank nicht verwendet werden. In einer Datenbank sollte jeweils nur ein Index abgefragt werden, was mit diesen geografischen Abfragen nicht möglich ist. Sie werden damit durchkommen, wenn Sie nicht viele Benutzer haben, aber wenn Sie erfolgreich sind, werden Sie ausfallen. Wie GoChat.

Was habe ich stattdessen gemacht? Nach dem Anwenden der CPU-teuren Bilderkennung und dem Ändern der Größe werden die Bilder mit geänderter Größe in Google Cloud Storage hochgeladen. Auf diese Weise werden der Server und die Datenbank nicht zum Anfordern von Bildern aufgerufen. Die Datenbank sollte sich um Daten kümmern, nicht um Bilder. Dies spart viele Server für sich. Auf der Datenbankseite teile ich die Snaps in einige verschiedene Sammlungen auf: alle Snaps, die beliebtesten Snaps, die neuesten Snaps, die neuesten gültigen Snaps und so weiter. Immer wenn ein Fang hinzugefügt, gemocht oder als Missbrauch markiert wird, prüft der Code, ob er (noch) zu einer dieser Sammlungen gehört, und handelt entsprechend. Auf diese Weise kann der Code aus vorbereiteten Sammlungen abfragen, anstatt komplizierte Abfragen auf einem großen Haufen Chaos auszuführen. Es wird einfach die Daten logisch in einige einfache Bereiche aufgeteilt. Nichts kompliziertes. Es ermöglicht mir jedoch, mit einem Sortiervorgang anstelle einer komplexen Abfrage, wie oben beschrieben, nur die Geokoordinaten abzufragen. In einfachen Worten: Es macht es einfach, Daten auszuwählen.

Wie viel zusätzliche Zeit habe ich dafür aufgewendet? Möglicherweise 2 bis 3 Stunden. Warum habe ich das überhaupt gemacht? Denn so habe ich die Dinge eingerichtet. Ich gehe davon aus, dass meine Apps erfolgreich sein werden. Es macht keinen Sinn, eine App zu erstellen, wenn sie nicht erfolgreich ist. Ich würde nicht schlafen können, wenn meine App an Bodenhaftung gewinnt und dann aufgrund schlechter Technologie stirbt. Ich habe in meine App ein Prinzip der minimalen Skalierbarkeit eingebaut. Es ist der Unterschied zwischen Glück und totaler Panik. Das sollte meiner Meinung nach Teil eines App-MVP sein.

Wählen Sie die richtigen Tools für Ihr MVP

Wenn ich GoSnaps mit einer langsameren Programmiersprache oder einem großen Framework erstellt hätte, hätte ich mehr Server benötigt. Wenn ich PHP mit Symfony oder Python mit Django oder Ruby on Rails verwendet hätte, hätte ich meine Tage damit verbracht, langsame Teile der App zu reparieren oder Server hinzuzufügen. Vertrauen Sie mir, ich habe es schon oft getan. Diese Sprachen und Frameworks eignen sich in vielen Szenarien, jedoch nicht für einen MVP mit geringem Serverbudget. Dies liegt hauptsächlich an den vielen Codeschichten, die normalerweise zum Zuordnen von Datenbankdatensätzen zu Logik und unnötigem Framework-Code verwendet werden. Es trifft die CPU einfach zu stark. Lassen Sie mich Ihnen ein Beispiel geben, wie wichtig dies tatsächlich ist.

Wie bereits erwähnt, verwendet GoSnaps NodeJS als Backend-Sprache / -Plattform, die im Allgemeinen schnell und effizient ist. Ich benutze Mongoose als ORM, damit die MongoDB als Programmierer unkompliziert funktioniert. Ich bin keineswegs ein Mungo-Experte, und ich weiß, dass die Bibliothek selbst eine riesige Codebasis hat. Deshalb war Mungo eine rote Fahne. Aber ja, MVP. Eines Tages am vergangenen Wochenende liefen die 4 NodeJS-Prozesse unseres Servers mit jeweils 90% CPU, was für mich für 800-1000 gleichzeitige Benutzer nicht akzeptabel ist. Mir wurde klar, dass es Mungo sein musste, der Dinge mit meinen abgerufenen Daten erledigte. Anscheinend musste ich einfach die "lean ()" - Funktion von Mongoose aktivieren, um einfache JSON-Objekte anstelle von magischen Mongoose-Objekten zu erhalten. Nach dieser Änderung sanken die NodeJS-Prozesse auf etwa 5–10% der CPU-Auslastung. Nur die einfache Logik zu wissen, was Ihr Code tatsächlich tut, ist sehr wichtig. Es reduzierte die Last um 90%. Stellen Sie sich eine wirklich umfangreiche Bibliothek vor, wie Symfony with Doctrine. Es wären ein paar Server mit vielen CPU-Kernen erforderlich gewesen, um nur den Code alleine auszuführen, obwohl die Datenbank der Engpass sein soll, nicht der Code.

Die Wahl einer schlanken und schnellen Sprache ist wichtig für die Skalierbarkeit, es sei denn, Sie haben viel Geld für Server. Die Auswahl einer Sprache mit vielen nützlichen verfügbaren Bibliotheken ist noch wichtiger, da Sie Ihr MVP schnell erstellen möchten. NodeJS, Scala und Go sind gute Sprachen, die beide Anforderungen erfüllen. Sie bieten eine Menge guter Werkzeuge mit einer Menge guter Leistung. Eine Sprache wie PHP oder Java an sich ist nicht unbedingt langsam, wird aber normalerweise zusammen mit großen Frameworks und Codebasen verwendet, die die Anwendung schwer machen. Diese Sprachen eignen sich hervorragend für eine saubere objektorientierte Entwicklung und bewährten Code, nicht jedoch für eine schnelle und kostengünstige Skalierbarkeit. Ich möchte kein großes Argument für die Programmiersprache anführen. Lassen Sie mich daher nur feststellen, dass dies subjektiv und unvollständig ist. Ich persönlich liebe Erlang und würde es niemals für einen MVP verwenden, daher sind alle Ihre Argumente ungültig.

Meine vorherigen Startup-Cloud-Spiele

Vor einigen Jahren war ich Mitbegründer von Cloud Games, einem HTML5-Spiele-Publisher. Als wir anfingen, waren wir eine B2C-Gaming-Website, die sich auf die MENA-Region konzentrierte. Wir haben uns sehr bemüht, Benutzer zu gewinnen und erreichten nach einigen Monaten 1 Million aktive Benutzer pro Monat. Zu der Zeit habe ich PHP, Symfony2, Doctrine und MongoDB in einem ziemlich einfachen und schlanken Setup verwendet. Ich habe für Spil Games mit 200 Millionen MAU gearbeitet, die zu dieser Zeit PHP verwendeten und dann zu Erlang wechselten. Nachdem Cloud Games ungefähr 100.000 MAU erreicht hatte, stellten wir aufgrund des enormen Overheads dieser PHP-Bibliotheken echte Serverprobleme bei Doctrine und MongoDB fest. Ich habe MongoDB, Indizes und Abfragen richtig eingerichtet, aber die Server hatten Schwierigkeiten, den gesamten Code zu verarbeiten. Und ja, ich habe den APC-Cache von PHP verwendet und so weiter.

Da cloudgames.com noch sehr statisch war, konnte ich das MVP in wenigen Tagen mit Redis auf NodeJS migrieren. Ähnliches Setup, andere Sprache. Dies führte zu einer sofortigen Verringerung der Belastung um etwa 95%. Zugegeben, dies hatte mehr mit der Vermeidung von PHP-Bibliotheken zu tun als mit der eigentlichen Sprache. Ein minimalistisches NodeJS-Setup ist jedoch sinnvoller als ein minimalistisches PHP-Setup. Zumal MongoDB und Frontend-Code wie NodeJS ebenfalls zu 100% aus JavaScript bestehen. PHP ohne seine Frameworks und Bibliotheken ist nur eine andere Sprache.

Wir brauchten dieses billige Setup, da wir ein selbstfinanziertes Startup in der Frühphase waren. Cloud Games macht sich jetzt gut und basiert immer noch auf einer kostengünstigen NodeJS-Architektur. Wir hätten es möglicherweise nicht geschafft, mit einem teureren technischen Setup erfolgreich zu sein, da wir als Startup einige wirklich schwierige Zeiten durchgemacht haben. Der Entwurf einer kostengünstigen, skalierbaren Architektur war entscheidend für den Erfolg.

MVP und Skalierbarkeit können koexistieren

Wenn Ihre App aufgrund von Hype oder möglicher Medienberichterstattung möglicherweise exponentiell wächst, sollten Sie die Skalierbarkeit als Teil Ihres MVP berücksichtigen. Die Prinzipien von minimal lebensfähigen Produkten und skalierbarer Technologie können koexistieren. Es gibt nichts Traurigeres, als eine erfolgreiche App zu erstellen und zu sehen, dass sie aufgrund technischer Probleme fehlschlägt. Pokémon GO selbst hatte viele Probleme, ist aber so einzigartig und gehypt, dass es keine Rolle spielt. Kleine Startups haben diesen Luxus nicht. Timing ist alles. Eine Million GoChat-Benutzer und eine halbe Million GoSnaps-Benutzer stimmen mir wahrscheinlich zu.

Bearbeiten am 21. Juli 2016

Ich habe den Artikel geringfügig bearbeitet, da GoChat noch im Google Play Store verfügbar ist. Auf der Google Play-Seite heißt es "100% zurück" mit "über 2 Millionen Nutzern". Eine iOS-Version soll bald wieder kommen.

Bitte liken und folgen!

Wenn Ihnen dieser Artikel gefallen hat, finden Sie ihn hier auf Medium. Das würde mir sehr viel bedeuten. Sie können sich gerne zu Fragen der Skalierbarkeit äußern. Bei Unboxd freuen wir uns immer, wenn andere Apps wachsen! Und New Yorker: Schauen Sie sich unsere App Cuisine an! Vielen Dank!