More Related Content
Similar to 门户级Ugc系统的技术进化路线
Similar to 门户级Ugc系统的技术进化路线 (20)
门户级Ugc系统的技术进化路线
- 1. ⻔门户级 UGC 系统的技术进化路线
新浪新闻评论系统的架构演进和经验总结
新闻⻔门户⺴⽹网站的评论系统,或者称为跟帖、留⾔言板,是所有⻔门户⺴⽹网站的核⼼心标准服务组件之⼀一。与论坛、
博客等其他互联⺴⽹网 UGC 系统相⽐比,评论系统虽然从产品功能⾓角度衡量相对简单,但是因为需要能够在突发热
点新闻事件时,在没有任何预警和准备的前提下⽀支撑住短短⼏几分钟内上百倍甚⾄至更⾼高的访问量暴涨,⽽而评论系
统既⽆无法像静态新闻内容业务那样通过 CDN 和反向代理等中间缓存⼿手段化解冲击,也不可能在平时储备⼤大量
冗余设备应对突发新闻,所以如何在有限的设备资源条件下提升系统的抗压性和伸缩性,也是对⼀一个貌似简单
的 UGC 系统的不⼩小考验。
(图 0:2008 年刘翔因伤退赛后的每分钟系统发帖量曲线)
本⼈人曾负责新浪⺴⽹网评论系统多年,新浪评论系统不仅服务于新浪的⻔门户新闻业务,还包括签名、调查、辩
论、投票等产品,我经历了系统从单机到多机再到集群,从简单到复杂再回归简单,从突发热点事件时经常宕
机到后来承受与新浪新闻静态池(新浪新闻业务的全国性内容分发与缓存系统)相近流量压⼒力的架构演变过程,
负责了前后多个版本的设计和开发⼯工作。有⼼心得收获也有经验教训,摘要总结⼀一下供各位同⾏行批评和参考。
另外我也希望能看到各位同⾏行更多的经验分享,在互联⺴⽹网系统架构设计领域,失败远⽐比成功更宝贵。
【新闻评论系统的起源】
新浪⺴⽹网很早就在新闻中提供了评论功能,最开始是使⽤用 Perl 语⾔言开发的简单脚本,⺫⽬目前能找到的最早具
备评论功能的新闻是 2000 年 4 ⽉月 7 ⽇日的(链接⻅见附录),经过多次系统升级,14 年前的评论地址已经失效了,
但是数据仍保存在数据库中。直到今天,评论仍是国内所有新闻⺴⽹网站的标配功能。
【评论系统 3.0】
⼤大约 2003 年左右,我接⼿手负责评论系统,系统版本 3.0。当时的评论系统运⾏行在单机环境,⼀一台 X86 版
本 Solaris 系统的 Dell 6300 服务器提供了全部服务,包括 MySQL 和 Apache,以及所有前后台 CGI 程序,使
⽤用 C++开发。
- 2. (图 1:3.0 系统流程和架构)
3.0 系统的缓存模块设计的⽐比较巧妙,以显⽰示⻚页⾯面为单位缓存数据,因为评论⻚页⾯面是依照提交时间降序排
列,每新增⼀一条新评论,所有帖⼦子都需要向下移动⼀一位,所以缓存格式设计为每两⻚页数据⼀一个⽂文件,前后相邻
的两个⽂文件有⼀一⻚页的数据重复,最新的缓存⽂文件通常情况下不满两⻚页数据。
(图 2:⻚页⾯面缓存算法⽰示意图)
上图是假设评论总数 95 条,每⻚页显⽰示 20 条时的⻚页⾯面缓存结构,此时⽤用户看到的第⼀一⻚页数据读取⾃自“缓存
⻚页 4”的 95~76,第⼆二⻚页数据读取⾃自缓存⻚页 3 的 75~56,以此类推。
这样发帖动作对应的缓存更新可以简化为⼀一次⽂文件追加写操作,效率最⾼高。⽽而且可以保证任意评论总量和
显⽰示顺序下的翻⻚页动作,都可以在⼀一个缓存⽂文件中读到所需的全部数据,⽽而不需要跨⻚页读取再合并。缺点是更
新评论状态⽐比如删除时,需要清空⾃自被删除贴⼦子开始的所有后续缓存⽂文件。缓存模块采取主动+被动更新模式,
发帖为主动更新,每次发帖后触发⼀一次⻚页⾯面缓存追加写操作。更新评论状态为被动更新,所涉及缓存⻚页⾯面⽂文件
会被清空,直到下⼀一次⽤用户读取⻚页⾯面缓存时再连接数据库完成查询,然后更新⻚页⾯面缓存,以备下次读取。这个
针对发帖优化的⻚页⾯面缓存算法继续沿⽤用到了后续版本的评论系统中。
此时的评论系统就已经具备了将同⼀一专题事件下所有新闻的评论汇总显⽰示的能⼒力,在很⻓长⼀一段时间内这都
是新浪评论系统的独有功能。
虽然 3.0 系统基本满⾜足了当时的产品需求,但是毕竟是单机系统,热点新闻时瞬间涌来的⼤大量发帖和读取
操作,经常会压垮这台当时已属⾼高配的 4U 服务器,频繁显⽰示资源耗尽的错误⻚页⾯面。我接⼿手后的⾸首要任务就是
尽量在最短时间内最⼤大限度的降低系统的宕机频率,通过观察分析确定主要性能瓶颈在数据库层⾯面。
3.0 系统⾥里每个新闻频道的全部评论数据都保存在⼀一张 MyISAM 表中,部分频道的数据量已经超过百万,
在当时已属海量规模,⽽而且只有⼀一个数据库实例,读写竞争⾮非常严重。⼀一旦有评论状态更新会导致很多缓存⻚页
⾯面失效,瞬间引发⼤大量数据库查询,进⼀一步加剧了读写竞争。当所有 CGI 进程都阻塞在数据库环节⽆无法退出
- 3. 时,殃及 Apache,进⽽而导致系统 Load 值急剧上升⽆无法响应任何操作,只有重启才能恢复。
解决⽅方案是增加了⼀一台 FreeBSD 系统的低配服务器⽤用于数据库分流,当时 MySQL 的版本是 3.23,
Replication 主从同步还未发布,采取的办法是每天给数据表减肥,把超过⼀一周的评论数据搬到⼆二号服务器上,
保证主服务器的评论表数据量维持在合理范围,在这样的临时⽅方案下 3.0 系统⼜又撑了⼏几个⽉月。
在现在看来相当简陋的系统架构下,新浪评论系统 3.0 与中国互联⺴⽹网产业的⻔门户时代⼀一起经历了南海撞机、
911 劫机、⾮非典、孙志刚等新闻事件。
(截图 1~4:南海撞机、911 劫机事件、⾮非典、孙志刚事件)
【评论系统 4.0 启动】
2004 年左右,运⾏行了近三年的 3.0 系统已经⽆无法⽀支撑新浪新闻的持续流量上涨,技术部⻔门启动了 4.0 计
划,核⼼心需求就是三个字:不宕机。
因为当时我还负责了新浪聊天系统的⼯工作,不得不分⾝身应对新旧系统的开发维护和其他项⺫⽬目任务,所以在
现有评论系统线上服务不能中断的前提下,制定了数据库结构不变,历史数据全部保留,双系统逐步⽆无缝切换,
升级期间新旧系统并存的⼤大⽅方针。
【评论系统 4.0 第⼀一阶段】
⽂文件系统代替数据库,基于 ICE 的分布式系统
既然 3.0 系统数据库结构不可变,除了把数据库升级到 MySQL 4.0 启⽤用 Repliaction 分解读写压⼒力以外,
最开始的设计重点是如何把数据库与⽤用户⾏行为隔离开。
- 5. (图 5:4.0 系统架构)
此时的 4.0 评论系统已从双机互备扩容到五机集群,进⼊入⼩小范围试⽤用阶段,虽然扛过了刘翔第⼀一次夺⾦金时
创记录的发帖⾼高峰,但是倒在了 2004 年亚洲杯中国队 1:3 败于⽇日本队的那个夜晚。
(截图 5:刘翔⾸首次夺⾦金)
当时系统在进⼊入宕机之前的最⾼高发帖速度⼤大约是每分钟千帖量级,在⼗十年前还算得上是业界同类系统的峰
值,最终确认问题出在⽂文件系统的 IO 负载上。
设计索引缓存模块时的设想过于理想化,虽然把单⼀一数据表的读写操作分解到了⽂文件系统的多个⽂文件上,
但是不可避免的带来了对机械磁盘的⼤大量随机定位读写操作,在 CentOS 默认的 ext3 ⽂文件系统上每个新闻对
应两个⽂文件的的设计(2004 年新浪新闻总量千万左右),虽然已经采取了 128x256 的两层⺫⽬目录 HASH 来预防
单⺫⽬目录下⽂文件过多隐患,但刚上线时还表现良好的系统,稍过⼏几个⽉月后就把⽂文件系统彻底拖垮了。
既然 ext3 ⽆无法应对⼤大数量⽂文件的频繁随机读写,当时我们还可以选择使⽤用 B*树数据结构专为海量⽂文件优
化的 ReiserFS ⽂文件系统,在与系统部同事配合反复对⽐比测试,解决了 ReiserFS 与特定 Linux Kernel 版本搭
配时的 kswapd 进程⼤大量消耗 CPU 资源的问题之后,终于选定了可以正常⼯工作的 Kernel 和 ReiserFS 对应版
本,当然这也埋下了 ReiserFS 作者杀妻⼊入狱后新装的 CentOS 服务器找不到可⽤用的 ReiserFS 安装包这个⼤大
隐患。(Wiki:ReiserFS)
【评论系统 4.0 第⼆二阶段】
全系统异步化,索引分⻚页算法优化
- 6. 直到这个阶段,新浪评论系统的前端⻚页⾯面仍是传统的 Apache+CGI 模式,随着剩余频道的逐步切换,新
浪评论系统升级为静态 HTML ⻚页⾯面使⽤用 XMLHTTP 组件异步加载 XML 数据的 AJAX 模式,当时跨域限制更少
的 JSON 还未流⾏行。升级为当时刚刚开始流⾏行的 AJAX 模式并不是盲⺫⽬目追新,⽽而是为了实现⼀一个⾮非常重要的
⺫⽬目标:缓存被动更新的异步化。
(图 6:异步缓存更新流程)
随着消息队列的普遍应⽤用,4.0 系统中所有的数据库写操作和缓存主动更新(即后台程序逻辑触发的更新)
都已经异步化了,当时已经在实践中证明,系统访问量⼤大幅波动时,模块间异步化通信是解决系统伸缩性和保
证系统响应性的唯⼀一途径。但是在 CGI ⻚页⾯面模式下由⽤用户动作触发的缓存被动更新,只能阻塞在等待状态,
直到查询数据和更新缓存完成后才能返回,会导致前端服务器 Apache CGI 进程的堆积。
使⽤用 AJAX 模式异步加载数据,可以在⼏几乎不影响⽤用户体验的前提下完成等待和循环重试动作,接收缓存
更新请求的⽀支持优先级的消息队列还可以合并对同⼀一⻚页⾯面的重复请求,也隔离了⽤用户⾏行为对前端服务器的直接
冲击,极⼤大提⾼高了前端服务器的伸缩性和适应能⼒力,甚⾄至连低硬件配置的客户端电脑在 AJAX 模式加载数据时
都明显更顺畅了。前端⻚页⾯面静态化还可以把全部的数据组装和渲染逻辑,包括分⻚页计算都转移到了客户端浏览
器上,充分借⽤用⽤用户端资源,唯⼀一的缺点是对 SEO 不友好。
通过以上各项措施,此时的 4.0 系统抗冲击能⼒力已经有明显改善,但是接下来出现了新的问题。在 3.0 系
统时代,上万条评论的新闻已属少⻅见,随着业务的增⻓长,类似 2005 年超⼥女专题或者体育频道 NBA 专题这样
千万评论数级别的巨⽆无霸留⾔言板开始出现。
为了提⾼高分⻚页操作时定位和读取索引的效率,4.0 系统的算法是先通过 mmap 操作把⼀一个评论的索引⽂文件
加载到内存,然后按照评论状态(通过或者删除)和评论时间进⾏行快速排序,筛选出通过状态的帖⼦子并且按照
时间降序排列好,这样读取任意⼀一⻚页的索引数据,都是内存⾥里⼀一次常量时间成本的偏移量定位和读取操作。⼏几
百条或者⼏几千条评论时,上述⽅方案运作的很好,但是在千万留⾔言数量的索引⽂文件上进⾏行全量排序,占⽤用⼤大量内
存和 CPU 资源,严重影响系统性能。曾经尝试改⽤用 BerkeleyDB 的 Btree 模式来存储评论索引,性能不升反
降。
为了避免⼤大数据量排序操作的成本,只能改为简单遍历⽅方式,从头开始依次读取直到获取到所需的数据。
虽然可以通过从索引⽂文件的两端分别作为起点,来提升较新和较早⻚页⾯面的定位效率,但是遍历读取本⾝身就是⼀一
个随着请求⻚页数增⼤大越来越慢的线性算法,并且随着 4.0 系统滑动翻⻚页功能的上线,原本⽤用户⽆无法轻易访问到
的中间⻚页⾯面数据也开始被频繁请求,所以最终改为了两端精确分⻚页,中间模糊分⻚页的⽅方式。模糊分⻚页就是根据
评论帖⼦子的通过⽐比例,假设可显⽰示帖⼦子均匀分布,⼀一步跳到估算的索引偏移位置。毕竟在数⼗十万甚⾄至上百万⻚页
的评论⾥里,精确计算分⻚页偏移量没有太⼤大实际意义。
- 7. (截图 6:4.0 滑动翻⻚页)
2005 年⾮非常受关注的⽇日本申请加⼊入联合国常任理事国事件,引发了各家⺴⽹网站的民意沸腾,新浪推出了征
集反⽇日⼊入常签名活动并在短短⼏几天内征集到 2000 多万签名。因为没有预计到会有如此多的⺴⽹网民参与,最开始
简单实现的 PHP+MySQL 系统在很短时间内就⽆无法响应了,然后基于 4.0 评论系统紧急加班开发了⼀一个签名
请愿功能,系统表现稳定。
(截图 7:反⽇日⼊入常签名)
【评论系统 4.0 第三阶段】
简化缓存策略,进⼀一步降低⽂文件系统 IO
到了这个阶段,硬件资源进⼀一步扩容,评论系统的服务器数量终于达到了两位数,4.0 系统已经达到了当
初的“不宕机”设计⺫⽬目标,随着⺴⽹网站的改版所有新闻⻚页⾯面包括⺴⽹网站⾸首⻚页都开始实时加载和显⽰示最新的评论数量和
最新的帖⼦子列表,此时 4.0 系统承受的 Hits 量级已经接近新浪新闻静态池的⽔水平。并且从这时起,新浪评论
系统再没有因为流量压⼒力宕机或者暂停服务过。
- 8. (图 7:4.5 系统架构)
前⾯面提到,新装的 CentOS 系统很难找到⾜足够新版本的 ReiserFS 安装包,甚⾄至不得不降级系统版本,⼀一
直困扰性能表现的⽂文件系统也接近了优化的极限,这时候 memcached 出现了。
2006 年左右 memcached 取代了 4.0 系统中索引缓存模块的实体数据部分(主要是评论正⽂文),索引缓存
模块在⽂文件系统上只存储索引数据,评论⽂文本都改⽤用 memcached 存储,极⼤大降低了⽂文件系统的 IO 压⼒力。因
为系统流量与热点事件的时间相关性,仅仅保存最近⼏几周的评论就⾜足以保证系统性能,极少量过期数据访问即
使穿透到 MySQL 也问题不⼤大,当然服务器宕机重启和新装服务器上线时要⾮非常留意数据的加载预热。
(图 8:4.5 系统流程)
之后 4.0 系统进⼊入稳定状态,⼩小修⼩小补,⼜又坚持服役了若干年,并逐步拓展到股票社区、签名活动、三⽅方
辩论、专家答疑、观点投票等产品线,直到 2010 年之后 5.0 系统的上线。
2008 年 5 ⽉月 12 ⽇日当天,我发现很多⺴⽹网友在地震新闻评论中询问亲友信息,就⽴立即开发了基于评论系统
的地震寻亲功能并于当晚上线。⼤大约⼀一周后为了配合 Google 发起的寻亲数据汇总项⺫⽬目,还专⻔门为 Google 爬
⾍虫提供了⾮非异步加载模式的数据⻚页⾯面以⽅方便其抓取。
- 9. (截图 8:汶川地震寻亲)
2004 年上线的 4.0 系统,2010~2011 年后被 5.0 系统取代逐步下线,从上线到下线期间系统处理的⽤用户
提交数据量变化趋势如下图。
(截图 9:4.0 系统流量图)
【⾼高访问量 UGC 系统设计总结】
纵观整个 4.0 系统的设计和优化过程,在硬件资源有限的约束下,依靠过度设计的多层缓冲,完成了流量
剧烈波动时保障服务稳定的最基本⺫⽬目标,但是也确实影响到了 UGC 系统最重要的数据更新实时性指标,数据
更新的实时性也是之后 5.0 系统的重点改进⽅方向。
总结下来,⼀一般 UGC 系统的设计⽅方针就是通过降低系统次要环节的实时⼀一致性,在合理的成本范围内,
尽量提⾼高系统响应性能,⽽而提⾼高响应性能的⼿手段归根结底就是三板斧:队列(Queue)、缓存(Cache)和分
区(Sharding):
l 队列:可以缓解并发写操作的压⼒力,提⾼高系统伸缩性,同时也是异步化系统的最常⻅见实现⼿手段;
l 缓存:从⽂文件系统到数据库再到内存的各级缓存模块,解决了数据就近读取的需求;
- 10. l 分区:保证了系统规模扩张和⻓长期数据积累时,频繁操作的数据集规模在合理范围。
关于数据库:
l 区分冷热数据,按照读写操作规律合理拆分存储,⼀一般 UGC 系统近期数据才是热点,历史数据是冷数据;
l 区分索引和实体数据,索引数据是 Key,易变,⼀一般⽤用于筛选和定位,要保证充分的拆分存储,极端情
况下要把关系数据库当 NoSQL ⽤用;实体数据是 Value,⼀一般是正⽂文⽂文本,通常不变,⼀一般业务下只按主
键查询;两者要分开;
l 区分核⼼心业务和附加业务数据,每⼀一项附加的新业务数据都单独存储,与核⼼心业务数据表分开,既可以
降低核⼼心业务数据库的变更成本,还可以避免新业务频繁调整上下线时影响核⼼心业务。
⺫⽬目前的互联⺴⽹网系统⼤大都严重依赖 MySQL 的 Replication 主从同步来实现系统横向扩展,虽然 MySQL 在新
版本中陆续加⼊入了 RBR 复制和半同步等机制,但是从库的单线程写操作限制还是最⼤大的的制约因素,⾄至少到
现在还没有看到很理想的⾰革新性的解决⽅方案。
关于缓存,从浏览器到⽂文件系统很多环节都涉及到缓存,这⾥里主要说的是应⽤用系统⾃自⼰己的部分:
l 最好的缓存⽅方案是不⽤用缓存,缓存带来的问题往往多于它解决的问题;
l 只有⼀一次更新多次读取的数据才有必要缓存,个性化的的冷数据没必要缓存;
l 缓存分为主动(Server 推)和被动(Client 拉)两种更新⽅方式,各⾃自适⽤用于不⽤用场景;
l 主动更新⽅方式⼀一般适⽤用于更新频率较⾼高的热数据,可以保证缓存未命中时,失控的⽤用户⾏行为不会引发系
统连锁反应,导致雪崩;
l 被动更新⽅方式⼀一般适⽤用于更新频率相对较低的数据,也可以通过上⽂文提到的异步更新模式,避免连锁反
应和雪崩;
l 缓存的更新操作尽量设计为覆盖⽅方式,避免偶发数据错误的累积效应。
⼀一个 UGC 系统流量刚开始上涨时,初期的表⾯面性能瓶颈⼀一般会表现在 Web Server 层⾯面,⽽而实际上⼤大多
是数据库的原因,但是经充分优化后,最终都会落在⽂文件系统或者⺴⽹网络通信的 IO 瓶颈上。直接承载⽤用户访问
冲击的前端服务器最好尽量设计为⽆无状态模式,降低宕机重启后的修复⼯工作量。
顺带提及,我在新浪聊天和评论系统的开发过程中,逐步积累了⼀一个 Web 应⽤用开发组件库,在新浪全⾯面
转向 PHP 之前,曾⽤用于新浪的内容管理(CMS)、⽤用户注册和通⾏行证、⽇日志分析和论坛等使⽤用 C++的系统,
⺫⽬目前发布于 github.com/pi1ot/webapplib。
【评论系统 5.0 ⽅方案】
2010 年后针对 4.0 系统的缺陷,启动了 5.0 系统⼯工作。因为⼯工作的交接,5.0 系统我只负责了⽅方案设计,
具体开发是交给其他同事负责的,线上的具体实现与原始设计⽅方案可能会有区别。5.0 系统极⼤大简化了系统层
次,在保证抵抗突发流量波动性能的前提下,数据更新的及时性有了明显的提⾼高。
- 11. (图 9:5.0 系统流程)
设计⽅方案上的主要变化有:
l 评论帖⼦子 ID 从数据库⾃自增整数改为 UUID,提交时即可确定,消除了必须等待主库写⼊入后才能确定评论
ID 的瓶颈,对各个层⾯面的缓存逻辑优化有极⼤大帮助;
l 重新设计数据库结构,通过充分的数据切分,保证了所有⾼高频业务操作都可以在⼀一个有限数据量的数据
表中的⼀一次简单读取操作完成,索引和⽂文本数据隔离存储,在数据库中实现了原 4.0 系统中索引模块的
功能,取消了 4.0 系统的索引缓存层;
l 改⽤用内存 NoSQL 缓存⽤用户频繁读取的最新 10 到 20 ⻚页数据,取消了原 4.0 系统⽂文件⽅方式的⻚页⾯面缓存层;
l 系统运⾏行环境迁移到新浪云的内部版本:新浪动态平台,设备资源富裕度有了极⼤大改善;
l 改为 Python 语⾔言开发,不⽤用再像 4.0 系统那样每次更新时都要等待半个⼩小时的编译过程,也不⽤用再打包
⼏几百兆的执⾏行⽂文件同步到⼏几⼗十台服务器上,⽽而语⾔言层⾯面的性能损失可以忽略不计。
【新闻评论产品总结】
新闻评论作为微博之前最能反映舆情民意的 UGC 平台,⻓长期承载了国内互联⺴⽹网⽤用户对时事新闻的匿名表
达欲望,曾经⼀一度成为上到政府下到⺴⽹网民的关注焦点。虽然⾯面临了相对其他社区系统更为严厉的管控⼒力度,也
错过了实施实名制改造时迈向社区化的最佳时机,但是⽆无论如何,在 21 世界的前⼗十年,国内⻔门户⺴⽹网站的新闻
评论服务,都是中国互联⺴⽹网产品和技术发展历史上绝对不能错过的⼀一笔。
【作者个⼈人信息】
刘⽴立,2000 年毕业于哈尔滨⼯工业⼤大学计算机系,2000 ⾄至 2013 年⼯工作于新浪⺴⽹网研发中⼼心和⻔门户技术部⻔门,
任⾼高级技术经理,具备⼗十年以上的⻔门户级别资讯和社区系统架构及项⺫⽬目管理经验,⺫⽬目前⼯工作于某社交电商平台
创业团队,任技术负责⼈人。
微博账号:@pi1ot
【附】历史新闻事件和评论地址
2000 年
新浪最早新闻评论
http://news.sina.com.cn/society/2000-4-7/79703.html
http://comment5.news.sina.com.cn/comment/skin/default.html?channel=sh&newsid=1-1-79703
2001 年