History of my startup: 500,000 users in 5 days on a hundred-dollar server

Original author: Erik Duindam
  • Transfer
It seems that everyone in the startup world agrees that the first versions of applications should be a minimum viable product (MVP), creating one that you don’t really need to worry about scaling it from a technical point of view. I have heard many times that the most important thing in such matters is to quickly release something that works. And, as long as the business model functions normally in the context of a growing customer base, everything is fine. And you should not spend time and money on creating a system that can withstand the sudden influx of users. All you need to worry about is checking your assumptions, evaluating the market, and promoting your business. Scalability is something that can be postponed until later. Unfortunately, such a blind faith in stereotyped ideas has repeatedly led to deafening failures. Pokémon GO, and,



Jonathan Zarra, the developer of GoChat, certainly won’t make the same mistake again. He gained a million users in 5 days , creating a chat application for Pokémon GO fans. From the material mentioned above, you can find out that he communicated with investors on the subject of monetization and expansion of the application. GoChat crashed right after that. A lot of users were lost and serious money was spent. After all, the idea is brilliant, and as a result - a real disgrace. Yes, by the way, a few days after writing, I slightly edited the original version of this article, since GoChat is still alive on Google Play, and has more than two million users. It is expected that its iOS version will soon be restored again.

Zarra had a hard time: he had to pay for the servers necessary to support a million active users. He did not think that he would succeed in attracting such an audience. He created the application in the best traditions of MVP, putting aside the concern for scaling for later. In general, we can say that he initially condemned his project to failure. When application architecture issues became apparent, Zarra hired an Upwork programmer to fix many performance issues. He said that server costs are in the region of $ 4000. It’s 2016, so it’s safe to assume that this is not about buying “iron” servers. These $ 4,000 are the cost of an annual or monthly rental of virtual servers and traffic charges.

For almost my entire professional life, I have designed and built web platforms for hundreds of millions of active users. And I can say that $ 4,000 per server is too much for a million chatters. Even for MVP. This suggests that the server side of the application is poorly designed. In fact, it’s not so easy to create a cost-effective yet scalable system for millions of monthly active users. But this is not beyond human capabilities - to use a combination of software that will allow you to support a serious audience on low-cost cloud servers. This should be taken into account when choosing the right components when creating MVP.


GoSnaps: 500,000 users in 5 days on the server for $ 100 per month


GoChat allowed players in Pokémon GO to chat, in the official application they can not do this. I created a project, GoSnaps , also targeting Pokémon GO fans. This is a mobile application that allows users to share screenshots and pictures with reference to the map. This is something like Instagram or Shapchat for Pokémon GO.

On the first day, GoSnaps gained 60,000 users. In the second - there were already 160 thousand of them, on the fifth day (the moment of writing this material) there were already half a million of them. At this point, users uploaded about 200 thousand pictures to the system. At any time, about 1000 people use the application at the same time. I created an image recognition subsystem to automatically check whether the uploaded image has anything to do with Pokémon GO, and also means for resizing uploaded images. All this works on one completely normal server from Google Cloud, the rental of which costs $ 100 per month. Added to this is the low-cost Google Cloud Storage that hosts images. It's about a hundred dollars a month, not thousands. In this case, everything works fine.

GoChat vs GoSnaps Comparison


Compare GoChat and GoSnaps. Both applications are likely to perform many queries per second in order to display chats or images in a specific area of ​​the map. This is a geospatial search in a database (or in a search engine), performed either within a certain polygon on a map, or carried out for a certain point defined by latitude and longitude. We use a polygon, requests are executed every time the user moves the map. Such queries create a serious load on the database, especially in combination with sorting or filtering data. GoSnaps has to process such searches hundreds of times per second. Probably the same thing happens in the bowels of GoChat.

A feature of GoChat is that the application has to pull out from the database every second and send users a lot of chat messages. The GoChat article talks about approximately 600 requests per second for the entire application. These 600 requests are a combination of map requests and chat messages. Messages are small, you can (or even need to) work with them through simple sockets. But the messages appear often and they need to be distributed among the many users who are in the chat. It is quite possible to deal with this situation if the software part of the solution is organized correctly. If we are dealing with a poorly designed MVP application, chat support can be an overwhelming task.

On the other hand, GoSnaps has many images that are downloaded from storage every second and like. Images are saved on the server, as even old pictures do not lose their relevance. At the same time, obsolete chats from GoChat are no longer needed. Since the image files are stored in Google Cloud Storage, the number of requested image files does not bother me as a developer. All of this is done by the Google Cloud, and I'm sure of the capabilities of Google. But the requested images with reference to the map is already something that really bothers me.

GoSnaps has an image recognition subsystem that searches for patterns in user-uploaded images in order to check whether these images are related to Pokémon GO or not. In addition, this subsystem is engaged in resizing images and sending them to Cloud Storage. All this is resource-intensive, in terms of CPU load and traffic consumption, operations. These actions are much harder than distributing a certain number of small chat messages, but they are performed less frequently.

The above allows me to conclude that both applications are very similar in terms of complexity of scaling. GoChat processes more small messages, while GoSnaps works with larger images and performs more resource-intensive server operations. The design and architecture of these two applications require, with almost the same complexity, a slightly different approach.

How to create scalable MVP in 24 hours


GoSnaps was created as an MVP, not as a professional business product. He was completely ready in 24 hours. I took the Node.js template for hackathons and used the MongoDB database without any form of caching. Nothing else is used in the project: neither Redis, nor Varnish, nor the intricate Nginx schemas. The iOS application was written in Objective-C, some code for working with Apple Maps was taken from our main Unboxd application . How did I manage to make GoSnaps scalable? In fact - only because I was not lazy, following the harmful canons of MVP.

Say, I would consider the creation of MVP exclusively as a race against time, the purpose of which is to release a working application as quickly as possible, while not paying attention to the quality of the server side. Where, in this case, to store images? Of course, in the database, in MongoDB. This does not require additional settings, and the code is necessary - nothing at all. Very simple. In the spirit of MVP. How to request images from a certain area on the map with the most likes from the database? It is enough to complete a regular request to MongoDB, covering the entire volume of images stored there. One request to one data set in the database. Again - MVP. All this would destroy my application and make it impossible to use its functions.

Let's take a look at the query that I would have to fulfill in order to get the above images from the database. It would look something like this: “find all the pictures that belong to the region on the map [A, B, C, D], excluding those that are marked as invalid and those that are still being processed, sorted by the number of likes, by whether they are related to Pokémon GO, and sorted by newness. " On a small dataset, such a query would work just fine. But if we are talking about a serious load, such calls to the database will tumble down the whole system. This will happen even if you simplify the above request so that it includes only three conditions and sorting operations. Why? Because this approach is not what the database is designed for. Access to the database should be performed using only one index at a time, which is impossible in the case of geospatial queries. If the application has few users, such a design will be quite functional. But if the application suddenly becomes successful, it will kill him. As actually happened with GoChat.

What have i done instead? After performing resource-intensive image analysis and resizing operations, the processed images are uploaded to Google Cloud Storage. Thanks to this, my server and database do not experience the load associated with the issuance of images to users. The database should take care of the data, not the pictures. This, in itself, allows you to seriously save on servers.

From the point of view of organizing the database, I divided the images into several sets. These are all images, the most liked, the newest, the newest suitable for the theme of Pokémon GO, and so on. When users add new images, like them, mark them as invalid, the code checks that the images belong to one of the groups and acts accordingly.

With this approach, queries are performed on prepared datasets, rather than performing complex calls on one huge heap of unstructured records. This is the result of logically breaking the data into several simple blocks. Nothing complicated. But this allowed me to execute queries only on geospatial coordinates with one sorting operation, instead of the complex query described above. Simply put, this approach simplifies data sampling operations as much as possible.

How much time did I spend on all these improvements? 2-3 hours, no more. Why did I do this in the first place? Because I'm used to working in this way. I assume that my application is waiting for success. I would not be able to sleep if my development would gain popularity, and then fall under the load only because it is poorly designed. I have integrated minimally viable scaling principles into the application. This is the difference between happiness from success and hopelessness. This is what, in my opinion, should be made part of the ideology of MVP applications.

Choosing the Right Tools for Implementing MVP


If I created GoSnaps using a slower code execution environment, or based on a sluggish framework, I would need more servers. If I used something like PHP with Symfony, or Python with Django, or Ruby on Rails, I would either spend all day accelerating slow components, or just know what to add servers to. You can believe: I already had to go through this. These languages ​​and frameworks are great for a lot of scenarios, but not MVPs with a small server budget. This is mainly due to the many levels of code that are usually used to work with data from databases in programs and the unreasonably bloated functions of frameworks. All this loads the server too much. Let me give you an example showing how much this really means.

As I said, the server side of GoSnaps is based on Node.js. This platform is overall fast and efficient. I used Mongoose as an ORM to make programming easier with MongoDB. I do not consider myself to be Mongoose experts, and I know that this library has a huge code base. So I put a big question mark over Mongoose. But yes, we are talking about MVP. Once, more recently, 4 Node.js processes on our server consumed approximately 90% of the CPU resources each, which for me, with about a thousand concurrent users, is unacceptable. I realized that the thing is most likely that Mongoose is doing something with the received data. Obviously, I just needed to enable the Mongoose lean () function in order to get regular JSON objects instead of the ingenious Mongoose objects. After this change, Node.js processes began to load the server by about 5 - 10%. Simple decisions based on knowing what the code actually does are very important. In my case, it reduced the load by 90%. Now imagine that we have a really heavy library like Symphony with Doctrine. Such a colossus would need a pair of multiprocessor servers only for its own code to work, even considering the assumption that the bottleneck in the system is the database, not the software mechanisms.

Choosing an economical and fast code execution environment is important for scalability, if only paying for servers is not a problem for your project. Choosing a programming language with many useful libraries available is even more important since MVPs usually need to be created as quickly as possible. Node.js, Scala, and Go are environments and languages ​​that satisfy both conditions. They have both high performance and many libraries. Languages ​​such as PHP or Java are not necessarily slow in themselves, but they are usually used in conjunction with large frameworks and libraries that make applications heavier. These languages ​​are good for pure object-oriented development and well-tested code, but not for creating applications that can be scaled quickly and cheaply. I don’t want to start a holy war here, so just let me say that all this is my subjective opinion, not supported by a deep and complete analysis of all the details. For example, I love Erlang, but I would never use it for an MVP application, so I consider any debate on this issue pointless.

My previous startup, Cloud Games


A few years ago, I became one of the founders of the Cloud Games project.- platforms for publishing HTML5 games. When it all started, we were a B2C gaming site targeting the MENA region. We made great efforts to attract an audience, and in a few months we reached a million monthly active users (MAU). At that time, I used PHP, Symphony2, Doctrine, and MongoDB in a very simple and economical configuration. I worked at Spil Games with 200 million MAUs, using PHP at that time and then switching to Erlang. After Cloud Games reached approximately 100,000 MAU, we encountered server overload. The reason was Doctrine and MongoDB. I correctly configured MongoDB, indexes and queries, but the servers barely managed the code. I used the PHP APC cache and so on, but without much success.

Since cloudgames.comwas a fairly static site, I was able to transfer this MVP project to Node.js with Redis in just a few days. The result was similar functionality, but in a different environment. This led to an instant drop in server load by about 95%. I admit, the point here is that we managed to get rid of the heavy PHP libraries, and not in choosing the application runtime or language. But the minimal working configuration of Node.js is much more functional than the minimal PHP configuration. Especially considering that both MongoDB and the front-end part of the project are 100% JavaScript, like Node.js. PHP, without frameworks and libraries, is just one of many programming languages.

We needed such a lightweight configuration, since we were a self-funded startup at an early stage of development. Today Cloud Games shows good results. The project is still based on Node.js. We could not have succeeded if we used technologies that require large investments, given the fact that in the life of Cloud Games, as a startup, there were difficult times. Designing economical, scalable architecture has become one of the key conditions for success.

Summary: MVP and scalability can coexist


If your application has a chance of exponential growth due to explosive interest in it or possible media coverage, be sure to consider scalability as part of the MVP strategy. The principles of minimum viable product and scalability can coexist. There is nothing sadder than creating a successful application and being present at its failure caused by technical problems. And Pokémon GO itself had a lot of problems, but the project is so unique and PR that it did not really matter. Small startups cannot afford such luxury. Timing is everything . A million GoChat users and half a million GoSnaps users are likely to agree with me.

Also popular now: