低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

微博春晚背后的技术故事

2014 年 3 月 12 日

前言

一年一度的春晚再次落下帷幕,而微博也顺利地陪伴大家度过除夕之夜。

谈及马年春晚,人们首先想到的不是春晚上精彩的节目,而是微博上的吐槽,边看春晚,边刷微博,边吐槽,已经成了国人的习惯。看春晚不再是为了看节目,而是为了能够在微博上吐槽,知道大家在吐槽什么,更有人戏称不是春晚成就了微博,而是微博拯救了春晚。

马年春晚又格外引人注目,不仅仅是因为冯小刚亲自坐镇,担当总导演,更值得一提的是本届春晚首次将社交平台作为其与观众互动的主要途径,而新浪微博更是成为官方二维码独家合作方。在节目播出时,用户通用手机客户端,扫描屏幕右下角的官方二维码,即可参与春晚的话题讨论。不仅如此,参与讨论的观众,还可以免费获得微博红包,抽大奖的机会。如此一来,大大的提升了微博的活跃度瞬间提升,同时在线人数翻了几倍,给微博系统带来前所未有的访问压力。

根据以往统计的数据,春晚期间微博的访问量将激增到日常水平的数倍之多,而瞬时发表量更是飙升数十倍,如此场景丝毫不亚于淘宝双 11 和 12306 抢票时的”盛况”。

而最后的统计数据结果表明,马年春晚直播期间,微博的访问量和发表量都再创新高,而我们系统也自始至终平稳运行,经受住了此次高峰的考验。这成功的背后,是我们的工程师将近一个月的努力。其间面临了哪些问题,又是如何解决的呢?下面,我们一一为大家揭秘。

挑战 1:如何应对数倍于日常访问量的压力?

每年春运抢票时,12306 都会崩溃;淘宝双 11 时,也会有短暂的购买失败的情况。究其原因还是,有限的服务器资源难以承受上千万人同时在线访问。同样,春晚的时候,微博的访问量也会激增,同时在线人数到达日常的数倍之多。面对突然增长的访问压力,大部分互联网公司都会临时扩容来加以应对,同样我们也需要进行扩容。那么如何进行扩容?哪些部分需要扩容?具体扩容多少?这都是厄需解决的问题。

需要提到一点的是,微博目前线上部署了几千台服务器,来保障日常的正常访问。假如面对原来数倍的访问压力时,如果简单粗暴通过线性扩容来应对的话,需要部署原来数倍的服务器,也就是需要上万台服务器。无论从硬件成本还是从管理成本上,这都是不可接受的。那么,又该如何做呢?

在线压测,找极限,最小化扩容前端机

众所周知,为了尽可能的保障线上运行的服务器的稳定,资源都是有一定冗余度的,一般安全值在 30% 以上。在面临 5 倍的访问量时,出于成本的考虑,单纯的扩容难以令人接受。这个时候,就要充分利用每台服务器,在不影响业务性能的前提下,使每台服务器的利用率发挥到极限,可以极大的降低资源扩容的数量。如何评估服务器的承受极限是其中的关键,为此我们在业务低峰时期,对线上的服务器进行了实际的压测。具体方法如下:

假如线上一个服务池里有 300 台 tomcat 服务器在提供 API 服务,正常情况下,每台服务器的负载都小于 1(为了简化模型,我们这里只提到了系统 load 这个指标,实际情况要比这个复杂的多,还要考虑 CPU 利用率、带宽、io 延迟等)。通过运维系统,我们以 10%、20%、30%、40%、50% 等比例逐步将该服务池里的 300 台 tomcat 机器 503,通过观察一台 tomcat 服务器的负载以及 API 服务的接口性能,当服务器的负载达到极限或者 API 服务的接口性能达到阈值时,假设此时服务池里正常状态的 tomcat 服务器的数量是 100 台,那么我们就可以推断出该服务池,极限情况下可以承受 3 倍与日常的访问压力。同理,为了承担 5 倍的访问量,只需再扩容一倍机器即可。

挑战 2:如何应对瞬时可达几万 /s 的发表量?

互联网应用有个显著特点,就是读多写少。针对读多有很多成熟的解决方案,比如可以通过 cache 来缓存热数据来降低数据库的压力等方式来解决。而对于写多的情况,由于数据库本身写入性能瓶颈,相对较难解决。

微博系统在处理发表微博时,采用了异步消息队列。具体来讲,就是用户发表微博时,不是直接去更新数据库和缓存,而是先写入到 mcq 消息队列中。再通过队列机处理程序读取消息队列中的消息,再写入到数据库和缓存中。那么,如何保证消息队列的读写性能,以及如何保证队列机处理程序的性能,是系统的关键所在。

按消息大小设置双重队列,保证写入速度。

众所知之,微博最大长度不超过 140 个字,而大部分用户实际发表的微博长度都比较小。为了提高写入消息队列的速度,我们针对不同长度的微博消息,写入不同大小的消息队列。比如以 512 字节为分界线,大于 512 字节的写入长队列,小于 512 字节的写入短队列,其中短队列的单机写入性能要远远高于长队列。实际在线结果表明,短队列的 QPS 在万 /s 级别,长队列的 QPS 在千 /s 级别,而 99% 的微博消息长度均小于 512 字节。这种优化,大大提高了微博消息的写入和读取性能。

堵塞队列,压队列机极限处理能力。

为了验证队列机处理程序的极限处理能力,我们在业务低峰时期,对线上队列机进行了实际的压测,具体方法如下:

通过开关控制,使队列机处理程序停止读取消息,从而堵塞消息队列,使堆积的消息分别达到 10 万,20 万,30 万,60 万,100 万,然后再打开开关,使队列机重新开始处理消息,整个过程类似于大坝蓄水,然后开闸泄洪,可想而知,瞬间涌来的消息对队列机将产生极大的压力。通过分析日志,来查找队列机处理程序最慢的地方,也就是瓶颈所在。

通过两次实际的压测模拟,出乎意料的是,我们发现系统在极限压力下,首先达到瓶颈的并非是数据库写入,而是缓存更新。因此,为了提高极限压力下,队列机处理程序的吞吐量,我们对一部分缓存更新进行了优化。

挑战 3:如何保证系统的可靠性?

无论是发微博,还是刷 feed,在微博系统内的处理过程都十分复杂,依赖着各种内部资源和外部服务,保证系统的可靠性显得尤为困难。

为此,我们内部开发了代号为试金石——TouchStone 的压测系统,对系统的可靠性进行全面检测。

首先,我们对微博的各个接口进行了服务依赖和资源依赖的梳理,并针对每个服务和资源定义了相应的 SLA 和降级开关。然后,模拟资源或者服务出现异常,再来查看其对接口性能的影响。以 redis 资源为例, 假设系统定义了 redis 的 SLA 是 300ms,相应的端口是 6379,通过 TouchStone,使该端口不可用,从而模拟 redis 资源出现异常,然后验证依赖该资源的接口的性能,确保 SLA 。同时,通过降级开关,对该资源进行降级,验证降级开关的有效。

基于以上方法,对系统进行了全面的检测,并对各个服务和资源的 SLA 和降级开关进行梳理,总结成业务降级手册,保证在出现问题时,运维人员无需开发的介入,也能第一时间根据降级手册进行降级,确保问题能够尽快解决。

挑战 4:如何保证核心系统的稳定性?

任何一个系统,都包含核心系统和非核心系统。在出现异常的情况下,弃车保帅,只保障核心系统的稳定性也是可以接受的。

为此,我们降核心接口和非核心接口拆分,部分部署到不同的应用池子当中,确保非核心业务不会影响核心业务。比如发微博和刷 feed 属于核心业务,而评论,赞属于非核心业务,所以两者应当部署到不同的应用池中。在评论或者赞出现异常时,发微博和刷 feed 就不会受到影响,从而保障系统核心业务的稳定性。

同样,对于一个业务,也要区分核心逻辑和非核心逻辑。以发微博为例,更新缓存和写数据库属于核心逻辑,而给其它业务部门推送数据则属于非核心逻辑。因此,可以将推送数据进行异步化处理,交给单独的线程池处理,在出现异常时,不会对更新缓存和写数据库造成影响。

挑战 5:如何做到异地容灾?

近些年来,异地容灾成为全球性互联网企业面临的难题之一。无论是在国内,以微信为例,还是在国外,以 twitter 为例,都曾经出现过全球性宕机的事故。由此可见,异地容灾仍旧是一个挑战。

微博早在 2010 年就开始了多机房的部署,如今已经具备三大机房(分别针对联通、电信和海外用户)。

由于人为或者天气等不可抗拒因素,网络故障近年来时有发生。微博的三个机房,各自独立承担了一部分用户的访问。在一个机房出现故障或者压力过大的时候,通过 DNS 切换等手段,将流量迁移到另外两个机房,从而确保该访问该机房的用户不受影响。一个现实的情况例子,在马年春晚直播期间,由于观看人群的地域分布的特点,出现了联通机房的访问量突增,同时在线人数的增长超过了电信机房和广州机房,我们通过切换一部分联通机房的流量到电信机房,使得联通机房的负载降到了安全值的范围。

挑战 6:如何实时监控系统状态?

我们都知道,地震的发生都是有前兆的,比如一些动物的异常反应。同样,系统中的任何问题出现之前,也是有线索可寻的。这就需要对系统的关键指标做实时的监控,当指标出现异常时,能够第一时间发出报警信息。

为此,我们基于实时流处理系统 Storm 开发了一套监控系统——dashboard。有别于以往的监控系统,它能实时处理系统产生的海量日志,绘制出更加直观的曲线,方便运维进行管理。通过 dashborad,我们能够了解系统的实时状态,主要包括 feed 的访问量、微博的发表量、队列机的处理性能,消息队列的堆积量等指标。当某个监控指标出现异常时,能够第一时间在 dashboard 中反映出来,从而第一时间采取措施,解决问题,避免问题扩大化。

后记

春晚已经过去一个月了,渐渐成为回忆。但春晚背后,我们的工程师所付出的巨大的努力所产生的价值,却是一笔宝贵的财富,希望这篇文章能给大家带来启发甚至帮助,也在此向为微博春晚默默贡献的工程师们致敬!

关于作者

胡忠想(微博昵称: @古月中心相心),目前任职于新浪微博的平台研发部门,主要负责微博 Feed 服务相关工作,曾先后参与微博 Feed 存储、微博计数器、微博阅读数等重大业务产品的开发。2012 年 3 月份毕业于北京航空航天大学计算系,同年 4 月份,加入新浪微博并工作至今。业余爱好户 外,曾徒步过贡嘎、雨崩,攀登过四姑娘三峰。


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014 年 3 月 12 日 06:076871

评论

发布
暂无评论
发现更多内容

解读 java 并发队列 BlockingQueue

猿灯塔

Java

六月我在工作中蜕变,勤奋小人打架终于赢了

程序员小跃

效率工具 加班 沟通 复盘

计算机操作系统基础(十一)---线程同步之互斥量

书旅

php laravel 线程 操作系统 进程

1.2w字 | 初中级前端 JavaScript 自测清单 - 1

pingan8787

Java 前端 Web

饿了么4年,阿里2年:我的总结与思考

程序员生活志

工作经验

SQLite你用对了吗

这小胖猫

sqlite 数据库 选型

如何搭建一个Zookeeper集群

Rayjun

大数据 zookeeper 分布式

Android架构组件-App架构指南,你还不收藏嘛

小吴选手

架构 架构师 架构总结 架构要素 P7架构师

什么时候不要用微服务?以 Istio 为例

无予且行

Java 微服务 后端

源码分析 | 数据异构Canal 初探

小新

【思考】互联网厂商争夺企业市场

superman

企业中台 互联网

农产品电商平台的S曲线分析

石云升

增长 S型曲线 破局点

为什么建议项目中统一线程池类?

张挺

架构师训练营 第 5 周作业

Lingjun

极客大学架构师训练营

今天来聊聊如何挑书

封不羁

读书 个人感想

面试官:既然CPU有MESI,为什么 JMM 还需要volatile关键字?

犬来八荒

Java JVM 硬件 java面试

专科程序员与本科程序员之间有什么区别?薪资待遇又差多少?

码农月半

spring 程序员 程序员人生 Java 面试 程序员成长

我是如何解决邮件焦虑的

vinkyqy

效率 职场 邮件

简直了!顶级架构师分享心得,如何在项目中兼容多种数据库

犬来八荒

Java MySQL 数据库 面试

Redis系列(五):你要的Redis集群搭建来了,实践与否你自己选!

z小赵

Java redis 分布式 高并发

锦囊篇|一文摸懂SharedPreferences和MMKV(二)

ClericYi

你真的理解透彻高并发了吗?来看看架构师眼里的高并发

小谈

Java 面试 高并发 高并发系统设计

深入理解编译优化之循环展开和粗化锁

程序那些事

JIT 编译优化 循环展开 粗化锁

18个Java8日期处理的实践,太有用了建议收藏

码哥小胖

MySQL SQL语法 sql查询

cms项目系列(一)——SSM框架搭建

程序员的时光

spring

spring 那点事儿——让你少走弯路

爱java爱自己

Spring Cloud Spring Boot

一个简单的技术选型心得

i风语

Java 架构

第四周

仪轩

程序员阿里、京东、美团面试整理的面试题,测试一下你都会了吗?

小谈

Java 阿里巴巴 面试

面试细节: i = i++和 i = ++i

Java小咖秀

JVM Java 面试 经验分享

编程核心能力之组合

顿晓

Java 学习 pipe

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

微博春晚背后的技术故事-InfoQ