12

从头搭建一个“微博”有多难

 4 years ago
source link: http://www.cnblogs.com/techflow/p/12727713.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

今天是 分布式专题的第13篇 ,今天的文章我们不讲空洞的理论,来聊一个实际点的问题。

众所周知,微博的程序员经常不定期加班。和别的程序员不同,别的岗位的程序员可能加班是可控的,但是微博的程序员不是。为什么呢?因为程序员们无法预知明星们什么时候有新的大料产生,一旦有新料,微博崩溃是妥妥的。甚至很多粉丝用微博有没有崩溃来衡量一个明星的知名度。

这当然只是个段子,但是对于我们搞技术的来说总忍不住问一个问题,微博也算是一个蛮大不小的公司,不缺钱也不缺人, 为什么系统这么不稳定呢?

当然我没有在微博呆过,为了严谨起见,我们假设我们现在开了一个类似的新的app,就叫做微特好了。我们来看看微特这个app从0开始成长的过程当中究竟会遇到哪些问题。通过微特这个虚假的项目,我们多少也可以推测一下微博不稳定背后的原因。

微特的诞生

某年某月某天,微特诞生了,为了简化问题,我们假设微特只有两个功能,就是 发微特和看微特

刚刚诞生的小企业嘛,请不起知名的架构师,当然是 怎么简单怎么来 。我们拆分一下功能,会发现一共只有三个功能,用户发微特、关注其他用户和查看微特,这三个功能都很简单,几乎就是裸的增删改查,我们一个一个看。

先看用户发微特,用户发微特我们只需要用一张表记录微特的内容即可。这个表呢大概长这样:

mUjYnuz.jpg!web

第二个功能是关注用户,我们再用一张表记录一下用户之间的关注关系即可,这也非常简单:

vea2AbR.jpg!web

有了这两张表之后,我们要查看微特就简单了,我们只需要通过userid去关注表里面去关联关注的用户,然后在用关注的用户的id去关联发过的微特即可。

我们用SQL来表示一下这个查询关系。

select wetwi.*
from (
  select followeeid
  from follower
  where followerid = curid
)a join wetwi
on a.followeeid = wetwi.userid

经过一番测试之后,微特顺利上线,老板试用了一下,觉得很满意。新用户也涨得很快,负责的程序员A得到老板的赏识, 一路晋升上去变成管理层 ,不再直接负责项目的技术问题了。

此人的一个手下B被委以重任,负责起了项目,但是就在这个时候,问题出现了。

微特一阶段

随着用户数量的增大,用户们关注的数字开始了迅速增长,很快平均一个用户都关注了好几十个其他用户。每次用户刷新的时候,都会同时加载这好几十人发布的微特内容。加上微特支持图片,最多的时候一时刻需要加载好几十张图片和大量文本, 服务器来不及传输这么多数据 ,频繁的有用户反馈说刷新的时候总是超时。

B想了想,这个简单啊,我们可以分成开源和节流两步。

首先我们需要开源,除了 加大机器 数量之外,我们需要 租借CDN ,将用户上传的图片放到CDN上而不存储在数据库里,从而加速数据传输的速度。

节流怎么办呢,也简单我们再用一张表来 存储用户最近一次刷新的时间 。这样我们在查询的时候,只需要查询这个时间点之后的数据就行了。于是我们多了一张记录时间的表。

FvINNfJ.jpg!web

这么一搞,系统总算稳定住了,用户抱怨的人数进一步变少。很快用户量又有了爆炸式的提升,终于有一天,热点事件一个接着一个,系统终于扛不住了,接二连三地宕机。

为什么会宕机呢?

因为 数据库的查询需要时间 ,本来就比较慢,加上了join操作之后,系统变得更慢。现在由于要判断微特发送的时间来做过滤,额外增加了一次查询,到达瓶颈之后自然就扛不住了。

B绞尽脑汁,终于想到了办法,就是缓存。他缓存了用户最后一次刷新的时间,这样就可以减少一次数据库的查询。系统稍微变快了一点,但是并没有坚持多久,终于老板忍无可忍开除了B,花大价钱从大公司挖来了一个架构师C。

与此同时,微特的用户量进一步增长,到了第二个阶段。

微特二阶段

C熟悉了环境之后,气得直骂娘,不从架构考虑问题,只会修修补补要不得啊。怎么可以直接用DB存储数据呢,搞成这样不崩溃才有鬼。

新官上任三把火,搞走了几个混吃等死的老白兔,C又招来当年的几个手下,开始大张旗鼓地 重构系统 。在分布式系统当中,DB往往都是瓶颈,能不用DB的就不应该用DB。而且微特的模式非常明显,用户发布了新内容之后,最关心的就是他的粉丝,那么我们直接在他更新的时候,就 把内容推送到粉丝的缓存里 ,当用户刷新的时候,直接从缓存拉取数据,这不是要方便得多吗?

C画出了新的架构图(可见C也是灵魂画手):

3iaa6bA.jpg!web

微特直接通过kafka等消息系统推送给用户, 效率要比DB高多了 ,C的一帮手下也给力,很快就完成了架构升级。上线之后,果然效果非凡,系统立刻变得稳定了许多,用户抱怨大幅减少。

在这几年里,公司声名鹊起,积累了大量的资源,一举去美国上市了。公司的高管都财富自由了,C来得晚没分到多少,并且看到当年埋了大坑的A混的风生水起,加上长久以来的不和,气不过跑路了。

就在这风生水起的时候,意想不到的事情又发生了。而我们的微特也来到了阶段3。

微特三阶段

C走了之后,系统从此再也没有大的改动,大家都只想把眼前 修修补补 的工作做好。反正公司也上市了,老板也自由了,底层的员工只想安安稳稳赚点工资。加上系统也稳定得很,没有人觉得有什么改动的必要。

但是由于微特现在太火了,使用的用户越来越多,除了普通用户之外,还把明星艺人吸引来了。这些明星艺人,一个个都有好 几千万的粉丝 。不是之前升级了架构,改成了通过kafka推送消息而不是去DB查询吗?这下好了,这些明星每次一发微特,都需要发送好几千万次消息。

有几天不知道是过节还是碰巧,这些明星艺人偏偏一起发推,直接就 把发送消息的系统挤压挂了 。这一挂,虽然微特整个系统没有崩溃,但是吃瓜群众发现再也搜索不到微特了。于是一起在网上骂微特,这一骂,需要发送的消息更多,系统更加扛不住,彻底成了死循环,公司的口碑急转直下。

公司也想解决这个问题,奈何之前做了太多修修补补的工作,整个 系统变得非常复杂 ,很多模块耦合在了一起,加上也没有一个很好的方案,一直也没有一个人下得了决心整个重构, 反而往上加了更多补丁

直到后来,A离职了之后,公司 新来的CTO 招来了一个业内技术骨干D。D提出了新的想法,将前面两种方案作了折中。大V发送的时候,并不推送到所有粉丝,而是 只推送给当前在线的粉丝 。离线的粉丝还是通过查询来获取数据。这样一来对流量进行了分流,微特系统变得稳定了许多。

但是这并没有真正彻底解决问题,系统仍然有时候会宕机,但是一时半会也没有什么特别好的办法,系统也变得极为臃肿彻底经不起折腾。于是微特就这样修修补补,变成了程序员加班不规律的公司。

后续

所谓的微特当然是个段子,故事也不是真的,但是技术架构的变迁还是很有参考意义。一个看似简单的问题,真正落地到应用场景当中,往往没有那么简单。 系统眼前的稳定也不能代表长远 ,这也是我们在开始一个项目的时候就需要眼光长远做好规划的原因。更是一个优秀的 架构师的价值所在 ,只不过可惜的是,世上的道理总是这样,知道的人太多,做到的太少。

希望今天这个的这个故事在博君一笑的同时也能给大家一点启发,一个成功的优秀的系统背后,究竟藏着多少思考和心血呢?

今天的文章就是这些,如果觉得有所收获,请顺手点个 关注或者转发 吧,你们的举手之劳对我来说很重要。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK