我如何使用每月100美金服务器支撑5天内5百万用户

GoSnaps是目前最流行应用口袋妖怪Pokemon GO的粉丝应用,用于分享口袋妖怪的屏幕截图和地图图片。GoSnap在第一天增长到6万用户,第二天16万,5天后50万独立用户,任何时间都有1000个并发用户,该应用有一个自动识别软件自动检查上传图片是否和口袋妖怪有关,重新缩放图片大小。

这是运行在Google Cloud服务器的每月100美金配置上。而之前支持聊天的口袋妖怪粉丝应用GoChat在5天内达到一百万用户,结果当机了,损失了很多用户和金钱,业内认为建立这样一个支持一百万用户需要4000美金。

GoSnaps是作为一个最小可行产品MVP方式建立的,不是专业的业务产品,在24小时鼓捣出来,采取NodeJS模板项目hackathons和MongoDB数据库,没有任何缓存,没有Redis,没有Varnish,没有时髦的Nginx设置,都没有。

实际iOS应用是使用原生Objective-c代码编制,借用了Unboxd的地图相关代码,那么如何使之性能扩展呢?不懒惰。

图片存储在MongoDB中,无需配置和代码,MVP建立很容易,那么查询怎么办?复杂的筛选查询非常耗时,解决办法是:将缩放图片上传到Google云存储,这样自己的服务器和数据库不会接受图片请求,自己的数据库只关心图片,这就节约很多服务器。

在数据库这边,分离快照到几个不同集合:所有快照,最像快照,最新快照,最新有效快照等等,无论什么时候一个快照加入,被标记为喜欢或讨厌,代码检查它是否属于这些集合并采取相应行动,这样代码能够从事先准备的集合中查询,而不是对数据库运行全局复杂查询,这只是将数据逻辑地划分到几个区域,没有复杂性了,允许单独查询一个排序操作的地理空间坐标,也就是能够直接查询数据。

如果我选择更慢编程语言或更大框架来建立GoSnaps,会花费更多服务器,比如PHP的Symfony,Django的Python,Ruby on Rails等等,我会花很多时间解决应用缓慢问题或增加服务器,这以前我经常做。

由于使用Mongoose 作为MongoDB的ORM,上个周末4个NodeJS进程耗费了90%CPU,意识到Mongoose抓取数据问题,激活了"lean()"功能来获得普通JSON对象,而不是魔术Mongoose对象,这样改变以后,NodeJS进程的CPU占用下降到5-10%。想象我有一个重型库包比如带有Doctrine的Symfony,需要很多服务器很多CPU核执行代码,即使数据库是瓶颈,而不是代码。

选择一个精益和快速语言对于扩展性是很重要的,除非你有很多钱买服务器。选择一个语言是否带有可用库包更重要,因为这事关你是否能快速构建MVP。

NodeJS,Scala和Go都是满足这些需求的好语言,它们都提供好的性能,PHP和Java就是不必要地慢了,但是通常用于构建大型框架和代码系统,用于建立干净面向对象开发和良好测试代码是很好的,但不适合快速和廉价地扩展。

MVP最小可行产品和扩展性可以共存。

How I built an app with 500,000 users in 5 days on