返回 登录
0

GoSnaps:如何支持5天50万用户服务器只花100元

阅读7834

创业者们似乎有这样一个共识:初创公司应尽快推出MVP(最简可行产品)而不应该把扩展性这样的细节放在心上。总是有人给我说推产品是最高的也实际上是唯一的目标,扩展性这样的问题可以先停留在计划书和PPT上。他们认为在验证产品的市场接受度和融到钱之前搞什么扩展性纯粹是浪费时间。然而这种认识并不正确,而且最近Pokémon GO(宠物小精灵/口袋妖怪GO)的流行又给我们上了一课。

Jonathan Zarra为Pokémon GO开发的聊天应用GoChat只用了5天时间注册用户数就达到了100万。他确实抓住了一个发财的好机会,不过就在他找风投谈变现的时候GoChat的服务器挂了,损失了钱和用户不说,机会也白白浪费了。

他开发GoChat时就是一个MVP,压根没考虑扩展性的事,因为他从来没想过这么短时间就有这么多用户。他请了顾问来帮他解决性能上的问题,最后得出的结论是保持服务器不挂要再花4000美元,而且以后的开销还不清楚有多少。

其实从我的经验来看对于一个只有100万用户的聊天应用来说服务器绝花不了4000块。花这么多钱只能说明设计上面出了问题。虽然给几百万用户设计一个既经济扩展性又好的应用不简单但也并不是说都难得不得了了。借助云计算的廉价服务器这是绝对可行的,当然前提是在开发MVP时就将扩展性考虑到位。

GoSnaps: 5天50万用户服务器只花100元

我自己也开发了一个与GoChat类似的应用GoSnaps,用户可以在应用的地图中分享自己的游戏截图。发布的第一天就有了6万用户,第二天涨到了16万,5天之后涨到了50万。同时在线人数大概1000,已经上传的截图数目接近20万,应用中还包括一个图像检测和缩放工具。所有这些都部署在一个100美元的谷歌云服务器上,而且表现很不错。

GoChat vs GoSnaps

GoChat和GoSnaps有一个相似的地方就是会不停地对服务器发起请求以便更新聊天记录和截图。每一次请求在后台都是一个依据地理位置的查询或是搜索,这种查询搜索再加上排序和过滤对服务器的负担是很重的。

GoChat跟我们相比不同点在于聊天信息得发送给所有参与者,而且请求更频繁。设置得当的话是没什么问题的,不过对没考虑扩展性的MVP来说可就是灾难了。

GoSnaps的特点则是截图的时效比聊天信息长,不过所有的图片都存储在谷歌的云存储,所以作为开发人员我基本不用操心。我操心的是图像识别和缩放的部分,这些操作对CPU和带宽的消耗比聊天的文本大多了。

综合考虑的话GoChat和GoSnaps复杂程度差不多,但在架构的设计上分别有需要特殊考虑的点。

24小时开发出一个高扩展的MVP

我开发GoSnaps从头到尾只花了24个小时,典型MVP。我用了一个以前的NodeJS boilerplate项目和MongoDB作为数据库。没用Redis,没用Varnish,没用Nginx,连MongoDB都没用缓存。App本身是用Objective-C开发的,我从Unboxd项目借鉴了一些有关地图的代码。

如果不考虑扩展性就是要开发速度的话,把截图存储在MongoDB最方便了,基本什么都不用做。查询截图也可以对所有已上传的图片直接用查询语句,一个数据集,一个查询语句,够简单吧。

不过让我们来看看这个查询语句是什么样的。我们要查询输入的ABCD四点所包围的范围内所有的截图,但要剔除掉敏感的和没处理完的,而且要依据点赞的数目、截图的有效性和上传时间排序。对于小型数据集其实这样查询没什么问题,但如果在生产环境用就肯定不行了。就算将查询语句进行简化也还是不行,因为数据库根本就不该一次对多个索引进行查询。不幸的是Jonathan Zarra在发布应用之前没有看到我这篇文章。

我的做法是在图片进行识别和缩放操作之后将它存储到谷歌云存储上面,这样就避免了截图请求对服务器和数据库的直接冲击。数据库方面我则是按照搜索的条件预先对图片进行了分类,比如点赞最多的、最新上传的等等。有新上传的截图或者对截图有赞踩等操作时这些类别也会检查更新,所以查询搜索时就不用查询所有图片了。其实没什么复杂的地方,但确实避免了复杂的查询语句。

其实做这些提高扩展性的工作只多花了我两三个小时,区别在于一开始有没有考虑这些问题。我开发这款应用就是为了让它成功的所以必须考虑扩展性,如果开发一款应用是为了不要让太多用户用那干脆别开发了。就算是最简可行产品也得有最简可行扩展相对应。

选对工具

开发语言的运行速度和框架的重量级会影响所需要的服务器数目。无数次的经验告诉我,PHP配Symfony、Python和Django或者Ruby on Rails就是运行速度慢和框架太重量级的代表。我并不是说这些语言和框架不好,只是对于想省经费的MVP开发者来说不是最理想的选择。

我后台用的是速度较快的NodeJS,ORM工具则用了Mongoose来简化对MongoDB的操作。虽然我知道Mongoose代码挺多的而且我其实也不太精通,不过MVP么怎么方便怎么来。上周末有一次我的四个NodeJS进程让服务器CPU都飙到了90%以上而同时在线人数只有不到一千。我觉得是Mongoose的问题, 所以就把Mongoose的lean()函数打开了,这样传递的就是普通的JSON对象。这样一来CPU瞬间掉到了不到10%。试想一下如果我用的是Symfony和Doctrine恐怕光运行代码就得好几个服务器。

既要扩展性又要便宜的话很重要的一点就是选一个速度快又轻量级的语言,不过对MVP要求的开发速度来说可能更重要的是库要多些。我认为现在满足这些条件的语言有NodeJS、Scala和Go。PHP和Java可能就语言来说并不算慢,但框架一般对MVP都太重量级。

经验之谈

几年前我创办了一个叫Cloud Games的网页游戏广告网站,几个月活跃用户就达到了100万。这时候我们还在用PHP、Symfony2、Doctrine和MongoDB因为我之前的公司有两亿活跃用户也用的PHP。活跃用户到了十万的时候我们的服务器开始有压力了,虽然我设置都对,APC缓存等等也都用了但这些库确实太大太慢了。

不过这时候网站还比较简单所以我们用NodeJS转写配合Redis也没花几天时间。架构没变,只换了个语言和数据库瞬间把负载降低到了之前的5%。其实归根结底只有一个原因就是创业艰难缺钱,好在Cloud Games现在经营得很不错。我想当时语言的转换对成功是起到了很大作用的。

MVP和扩展性矛盾吗?

如果你能预见你的app可能会哪天突然火起来,请一定在开发MVP时考虑扩展性的问题,因为MVP和扩展性两者并不矛盾。如果因为技术问题像Jonathan Zarra一样眼睁睁看着用户和钱从指间流走就太可惜了。虽然Pokémon GO自己问题也不少,但我们这种小app是没法跟他拼用户的容忍度的。对初创公司来说时间就是一切啊!

原文:medium.com
译者:刘旭坤

评论