两三年前做了一个不是很大的项目,代码级也不大,数量级也不大,只是突发流量稍微大些,先是拖垮了数据库服务器,后来又拖垮整个Web服务器,优化后,服务器没啥问题了,但是带宽……好了不说这个了,先大概说一下个人理解的这三者的区别吧。

三者区别

       memcached 和redis 都属于缓存系列的,也就是说缓存的事你找它就对了,但是想长期保存数据是不成的。而 memcached 更是内存级缓存,限于内存的物理特性,断电即丢失数据,因此存在 memcached 里的数据要确保丢失后没有太大影响。Redis 配置好后可以把数据持久化到磁盘存储,但它根上还是一个缓存级数据库,不适合大数据存储。

       MongoDB 是一种非关系型数据库,可以在磁盘上保存大数据,同时具有大部分数据库该有的功能,如:查询、索引、聚合、复制等多种功能,但同样的,它是为数据库级设计的,因此缓存不是它所擅长的。作为一个非关系型数据库,MongoDB保存数据的形式不再是二维表的格式,取而代之的是更为灵活的文档(document)模型。

大概的理解就是这些了,如果认真总结的话应该还有很多,不再多说了。下面就简单描述一下,以前用memcached完成的一个小项目。

memcached项目实践经过

        这个项目是一个小型投票专题,本来没什么大流量,业务逻辑也很简单,就是给候选人点击增加票数,有IP限制,每个IP每小时只能投票一次,不过没有验证码,领导说,有验证码会让投票的人觉得麻烦而放弃投票,于是整个系统就暴露给了刷票者。刚开始还比较顺畅,平均一分钟也就是几十个投票,对于任何服务器、任何构架来说都是小菜一碟。可后来事情有了本质的变化,因为该投票是跟候选者利益相关的,票数高的话能拿奖的,也不知道那些刷票公司从哪里获得了这些人的联系方式,悄悄的联系那些候选者提供有偿的刷票服务,于是服务器流量陡增。最开始单纯的投票,服务器还是撑得住的,毕竟只是去数据库里检查一下这个IP有没有投过票,有的话并且时间在1小时以内的话就放弃掉此次投票,否则给投票数加1,并记住此次投票的IP、时间等信息。

        然后随着刷票越接近尾声,刷票越是疯狂,第一个撑不住的是Web服务器,原因是数据库那边记录IP库的数据行数太大了,快接近百万行了,这时候,从百万行里Select出一小时内的数据,并检查IP情况,对数据库来说是有点压力了,虽然每次读取时间也就是几百毫秒到1秒,但是毕竟同一时间刷票请求多啊,导致投票请求递增迟延,最后给的apache 2000的连接数很快就不够了,然后发生了雪崩效应,等待的请求越多,服务器越慢,然后整体宕机了,很多的投票请求很快就因为超时而断开了。

话说这也怪我了,我本来以为只是一个小小的投票,以前总票数都不会超过10w,哪想到这次来的这么疯狂。

       禁不住一个个咨询电话的轰炸,决定试着处理下。首先既然是数据库的问题,先从数据库下手吧,把IP从字符串形式还成了long型,把时间从常见的时间格式也改成了int型的时间戳,这样查询起来毕竟是快些。然后是给投票页读票数那里改成非实时的,每隔5分钟生成一下静态页,这样释放了一些读取的压力。结果上线不到半小时,WEB服务器又宕了,比较系统的连接数发现,连接数是上去些了,但是抵不住刷票公司啊,他们那边应该是集群式刷票,都是机器干的事儿,等多久无所谓,我这边优化好了,他们那边继续刷呗,就像是流着水的橡胶管,原来有只手掐着,水流就那么大,后来我优化了一下,手放松了些,但是水流量大,虽然水管粗了些,但仍然是满的。

后来很无奈,决定使用缓存。

      我分析了一下,发现缓存很适合放到WEB服务器和数据库之间作为验证IP逻辑。

      大致流程是:

      接过WEB服务器给的投票请求,先把IP Hash成字符串作为Key值,然后去memcached里去查询,如果key值是存在的,那么扔到此次的投票请求。

如果发现没有此条记录,那么将此key存到memcached,值任意,比如是1,有效期设为1小时,这样我都不用去管时间的问题了。接着再把投票请求交给正常逻辑继续完成投票过程,同时改掉投票逻辑不在验证IP,但是也会把此次投票数据以记录形式存到数据库,方便后期分析投票详情(虽然这些数据意义不大)。

我大概用一天的时候完成了这个构架的转变,遗憾的是,本次投票接近尾声了,还没验证出来此次的成果。

第二年同期,又有相同类型的投票,我是直接把前一次的思路直接用上了,详细观察了一下整个服务器的负载,数据库压力几乎可以忽略不计(因为只有可投票的请求才回到数据库端,即使请求到了数据库端也只剩下了一次Insert和一次update),数据库迟延小了后,Apache 那端也就没什么压力了,只有memcached占的内存稍微多些,但是整体一直很稳定。整个服务器在投票期间运行稳定,没有宕机,但是快尾声的时候还是接到电话轰炸了,原因还是投不了票,检查了一下,发现服务器没问题,再一看流量明白了,30M的带宽跑满了(当时这30M不是都给这一台服务器的,员工上网也共享这些带宽),同时也接到投诉说是上不了网了。但是已经接近尾声了,领导说坚持坚持过去吧……

       你可能会问,为啥不加个验证码啊,为啥不把服务器流量和上网带宽分开啊,为啥不…… 因为领导说不啊,领导也是综合了各种情况包括money原因考虑的啊。

第三年的时候,为了不被自己人数落,为了保证访客能投票,把项目迁到阿里云去了,同时增加了验证码。最后算是撑下来了。

写在项目最后

       我一直还不知道那些刷票公司是怎么刷的,真的有那么多的机器(或者“肉鸡”)来分布式刷的么?或者是伪造了IP?

甚至加了验证码也能刷,只不过是稍微慢了些,当然如果我验证码足够复杂,可能他们也刷不了了,不过访客估计也会打电话说投不了了。

如果有懂他们是怎么刷的,亦或者有人在刷票公司工作,望不吝赐教一二,满足一下好奇心。