2016 年 9 月 23-24 日,由 CSDN 和创新工场联合主办的“MDCC 2016 移动开发者大会• 中国”(Mobile Developer Conference China)将在北京•国家会议中心召开,来自iOS、Android、跨平台开发、产品设计、VR开发、移动直播、人工智能、物联网、硬件开发、信息无障碍10个领域的技术专家将分享他们在各自行业的真知灼见。大会门票8折优惠中,五人以上团购更有特惠,限量供应(票务详情链接,8折优惠,欲购从速!)
作者简介:沈冠璞,熊猫TV高级应用开发工程师,近7年后端开发经验,曾任职新浪微博、360等互联网公司,负责短链接、微博Card对象、网游页游平台业务。对高并发海量数据业务设计有丰富经验;经历熊猫TV从0到1 海量PV和存储的快速扩张发展场景,有大中型互联网网站高可用设计架构经验。在MDCC 2016上,沈冠璞将结合自身经验,解析在热门时段大主播高峰值情景下优化礼物系统技巧,带来题为《百万弹幕下的直播礼物系统》的分享。
本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅2016年《程序员》
2015年开始的百播大战,熊猫TV是其中比较特别的一员。
说熊猫TV是含着金钥匙出生的公子哥不为过。还未上线,就频频曝光,科技号,微博稿,站上风口浪尖。内测期间更是有不少淘宝店高价倒卖邀请码,光内测时用户注册数量就达几十万,火爆程度可见一斑。笔者作为写下熊猫TV第二行代码的Coder,见证了熊猫TV成立以来的风风雨雨。直播技术坑不少,本文简单揭秘熊猫TV这一年的技术架构演进,分析各个阶段面临的主要问题和应对方案,给大家做直播系统提供一定的参考。
这个阶段最大的目标就是按预期时间上线。
组团队不表,10人左右的Web团队,从接需求,到上线,我们用了不到三个月。
这个阶段面临的最大难题:两个月就内测!
怎么办?找老战友刷刷刷!花钱买买买!作为一群经验丰富的老司机,我们用买零件翻新车的方法。网站内测公测阶段,需要满足用户登录注册、关注主播、看视频、发弹幕、加房管、领任务、送免费竹子等核心功能,采用了复用模块+主业务全新开发的策略。
复用模块得益于团队的前360技术背景,根据直播秀场类项目上的技术积累,利用PHP框架Pylon、发版工具Rigger,在老战友的帮助下,重新搭建了一套QBus消息组件,长连接系统,改进的Redis、MongoDB和MySQL集群,视频云服务,敏感词服务,搜索服务,这个项目才有了强大的基础支撑,才有可能在两个月时间就上线。
虽然是个新项目,我们并未做一个一篮子应用,把所有接口放在一个项目,而是按功能模块分好项目,每人负责一个,对主站panda.tv项目提供内网API,部署方便互不影响,开发效率也比较高。
熊猫TV架构第一原则是高可用
架构目标(SLA)
根据以往新项目经验,预估支撑1000TPS ,百万日活用户,单房间10万左右在线弹幕;平均响应时间在100ms,99.9%在1s内;千万级别数据量;99.9%的可用性(全年宕机在9小时以下)。
架构选型
四层负载均衡:LVS,目前基本是业界标配,如果使用云服务的话可以用厂商提供的负载均衡,如阿里云SLB和亚马逊ELB等,这种第三方依赖都需要严格引流压测确认DB层、缓存层、Web层是否
有坑;
设计实现
机器配置采用6核16G的虚拟机。服务部署单独的XEN虚拟机集群,互不影响,进行多机房互备,机房间光纤专线内网互通。
120台虚拟机分给十多个业务,主站用了40+,三个IDC——电信联通移动同时使用,流量大的主机房在电信,其他两个机房部署Redis、MySQL从库,写都在电信。预估的注册在线人数百万级,QPS万级。接口使用PHP-FPM对外服务,单机性能平均500QPS+,内测邀请制,内测一个月期间十几万人涌入,解决了一些小Bug,然后大家颇有信心迎接公测。
这个阶段属于填坑,最主要目标是网站稳定可用。虽然每个服务都有多机房灾备,微服务化也做了较好隔离,但0.1不到一个月便宣告夭折,我们低估了熊猫TV的明星效应,低估了黑色产业链的薅羊毛能力。公测一开始,熊猫就炸了(水友术语,指网站不可用)。
分析:网站因注册和用户信息、首页、房间页访问量过大导致FPM进程跑满,接口和模版渲染耦合,本身占的调用时长就会过多,服务间断性不可用,Redis缓存首页推荐位和用户信息只需几百MB,但连接数过多,内存占用到10G+,导致Redis响应缓慢不可用,垃圾号疯狂注册,第一天便破百万,用户中心出现服务异常,缓存命中率低,进而雪崩。
聊天弹幕爆发,时段非常集中,每日晚8点到凌晨2点为网站高峰时段,如图3所示。
这些也是直播网站会一直面临的核心稳定性问题,针对这些问题,大架构框架没有变动,加班加点,两周时间就上线了新一版架构优化。
主站重点接口Lua化:消息限制发送频率,并改造为Lua接口,十倍提速,避免占用主站PHP-FPM资源;赠送竹子也改造为Lua接口;用户中心取用户信息也改为Lua接口,直接从缓存读。
用户ID发号器改造,不依赖MySQL自增ID,提高并发性能。
首页和房间页静态化,Worker机抓取生成模版,分钟级别更新,然后rsync到各个服务器,Nginx直接读HTML文件生成首页、房间页,其他个人动态信息都走Ajax请求,保证不会出现白屏情况。
重点Redis增加到10+ Slave,Slave间树型同步,叶子节点从库从上级从库同步,避免一主多从传输数据延迟。从库的增加也避免主库网络负荷和连接数过多,导致响应延迟过大,服务不可用。
核心业务增加部署服务器,应对集中峰值访问。
安全性上:所有80接口做XSS校验,CSRF token防范,对接口做几十道安全检测,防止被拖库,防止Cookie被盗用;反垃圾反盗号反外挂:含敏感词聊天信息过滤,垃圾IP封禁;注册和任务都增加图片验证码,识别机器刷用户刷竹子;房间人气值采用复杂策略,用算法综合判断确认合理性,防刷防挂;主播审核更加严格,身份证银行卡姓名等信息都要求录入,可以追究责任到真人,甚至有视频验证,严防色情内容。
功能上:建立游戏娱乐户外等分类模块,运营自助增加分类;部署并自行运维第三方搜索服务,支持主播昵称、标题、房间号等维度搜索,过滤直播状态、主播地区、封禁状态等条件;礼物系统抽奖投票等系统上线,增加主播收益渠道,增加互动。
优化效果:全年未出现过白页、首页不可访问情况,支撑千万级PV,百万级日活,单房间最高达到百万级在线,视频流量近TB级;接口平均响应时间20ms左右,99.9%在1s内;各个系统数据存储量破千万,MongoDB、SSDB等大容量库很好地支持了业务。
到2.0阶段,初期的刷脸靠战友帮搭建基础服务和买第三方服务,已不能精细化、定制化地支撑业务快速发展,而此时人员配置也开始完善,熊猫TV开始了全新的2.0自主研发阶段。
本阶段也属于稳步发展阶段, 最主要的目标是视频流畅清晰、弹幕互动效果稳定。
接入决策上,接入更多家CDN,并对CDN稳定性做指标考核和严要求:根据卡顿率、延迟时间、首屏时间、声音视频同步率等指标,结合运营经验,创建了一套立体化多维度的CDN-SLA体系,决定给予流量多少,主播级别,主播数量。这样也增加CDN的危机感,更好服务用户。
视频流调度互备上,如图4所示。
主播推流区分默认配置和管理员配置,推向对他而言网络状况最好的CDN,CDN自身节点实现各地的复制,CDN之间实现推流互备,一个CDN挂掉,不影响使用,用户根据PC或手机端区分,从对应配置的CDN拉流看视频,从而实现最佳观看效果,Web端用户也可切换备用线路,当默认CDN出现问题,则选择从其他家CDN进行拉流。
这样就保证观看的流畅和视频的整体高可用。
建立连接:
下发消息:
使用Golang+Redis全新开发,对消息级别、消息发送和消息内容做了一定优化。级别上区分多种Level消息,在高峰期、网卡被打满极端情况下,丢掉部分不重要消息;消息发送进行打包方式发送,一个房间的消息一次批量推送几十条,减少TCP交互;消息内容去掉无用字段,减少长度,例如礼物消息一条减少了168字节,假设高峰期一个房间十万人在线,一条礼物消息能节16MB,大主播房间按1000个礼物一小时算,能节省16GB流量,非常可观,所以一定要注意消息内容的压缩和缩减。
整体架构上的改变:一年以来用户量爆炸式增长,达到日活用户近千万,PV上亿,同时直播主播近万间,流量峰值TB级别。技术人员也扩充了4倍,随着王校长驱动开发、尹素婉驱动开发(尹素婉是韩国第一女主播)、PDD驱动开发(PDD是前职业选手,著名LOL主播,弹幕量大,观众百万)等模式的驱动开发,熊猫快速步入2.0时代,技术架构也有了更稳固的改进,新的PHS(Panda High-Perfomace Service熊猫高性能服务体系)设计思路是增加架构层次,明确微服务边界,基础组件从外部依赖到内部自研,架构层次宏观层面分为端、接入层、平台服务化、中间层、基础层五个层次。
包括Web页、iOS、Android、各种Pad端、网吧弹窗合作、电视盒子合作App、游戏主机合作App,从各个渠道扩展业务。
从大而统一的panda.tv分流出mall.panda.tv、roll.panda.tv、pay.panda.tv、open.panda.tv等,保证各个接入业务互相隔离。接入层stars.panda.tv、pandagirls.panda.tv尝试使用NodeJS提供API,前端完全自行研发,提高效率,性能也比使用我们的Pylon-PHP框架提高了6倍左右,可以满足当前流量请求。
架构体系没有太大的变动,主要采用Golang技术栈做了整体升级。流量突发时PHP-FPM子进程新增缓慢,多进程模型切换代价较大,不能较好服务高峰请求,缓存和DB连接池复用困难,我们重点业务从PHP迁移到Golang;部署上,依赖Nginx+LVS探活实现不停机热部署;Gobase基础库,实现了一套特定业务场景Concurrent Map库;实现了配置读取模块;对MongoDB Client进行了封装,便于CRUD方式使用和对象映射;Redis连接池和CRUD操作封装,业务不需要协议命令细节,而是正常Get(key)、Set(key)即可;数据访问层结合配置服务封装分片与路由来支撑容量水平扩展;封装Log、HTTP请求和HTTP Param解析等基础类。
通过对Golang半年的使用,我们建立了自己的一套技术开发体系:Gvt创建项目和管理依赖,Ansible管理服务器和分发部署,Postman进行文档编排和代码测试, Teamcity实现持续集成。
业务上,CDN调度项目TrafficCoop,高性能,灵活配置Web端和移动端CDN信息;API-Proxy项目 ,原生Golang Router,使用OAuth 2.0,提供对外网关,中转内部服务;礼物系统全面使用Golang+Redis+MongoDB保证稳定性和高峰处理。新业务原则需要快速开发,性能要求较低的业务使用PHP,性能要求高的业务用Golang、NodeJS。
用户中心则持续演进:支持FaceBook等账号接入;电话语音验证码防外挂,异地IP重新登录机制防盗,个人身份指纹识别,做到彻底防盗号。另外为提高接口安全性,解决DNS劫持等问题对服务HTTPS化,各业务根据需要跟Ops申请HTTPS证书或SAN(多域名)证书。
视频效果优化:接入更多CDN厂商,进行评测对比,及时反馈问题,督促其合理设置缓存值,实现视频播放流畅化。
Flash调整弹幕展现策略:实现既能有满屏感,又不会因同屏弹幕过多卡住浏览器,达到观看和互动的平衡。
文本反作弊:机器学习训练房间弹幕内容,模型上对广告、色情、敏感词、黑白名单等进行打分评定。
增加图片墙鉴黄服务:30秒刷新房间截图,接入多家鉴黄API,合理评分,快速发现直播内容异常。
图床自建:图片存储从Cassandra迁移到公有云对象存储,节省运维成本,直接使用第三方CDN,加速图片访问。
Kafka队列自建:基础组专人开发维护,更快更好解决问题;竹子经验计数、用户关系等从SSDB迁移到Redis Cluster,保证性能无瓶颈,数据量暴增无压力。
Spark Streaming平台搭建:弹幕内容分析与舆情,CDN质量实时监控,用户行为实时感知。
另外一个比较大的架构变动是业务机房迁移。实现了DB迁移,公有云互备。二十多人演练数十次,按照两页的迁移清单,所有业务重新部署,DB重新导入,停机维护一整夜,所有服务从原有机房一次性成功迁移到两个公有云上。
熊猫TV架构改进思路是应对峰值流量高度集中的直播需求,总结几条经验:
熊猫TV因快速上线和爆炸式增长,从严重依赖外部服务,到自主自建核心业务,弯路走了不少,也对直播技术有了更深的理解,积累了丰富的经验,技术团队也从20人左右快速扩展到百人团队,为熊猫TV在百家直播平台中挺立飞奔奠定了技术基础。未来我们会在以下方面继续努力:
直播面临的核心问题是网站稳定可用、视频流畅清晰、弹幕互动效果稳定。直播技术看似简单,一家视频云可以帮助创业公司一两个月就构建出一个直播App,但其中的运营难点、技术难点、流量带宽问题都需要谨慎处理,希望本文能帮助直播行业技术人员跳过一些坑,架构设计时作为技术参考。
关于移动开发新技术,更多精彩尽在MDCC 2016,详情请查看大会官网:MDCC 2016移动开发者大会。