聚光灯下的熊猫TV技术架构演进
作者简介:沈冠璞,熊猫TV高级应用开发工程师,近7年后端开发经验,曾任职新浪微博、360等互联网公司,负责短链接、微博Card对象、网游页游平台业务。对高并发海量数据业务设计有丰富经验;经历熊猫TV从0到1 海量PV和存储的快速扩张发展场景,有大中型互联网网站高可用设计架构经验。在MDCC 2016上,沈冠璞将结合自身经验,解析在热门时段大主播高峰值情景下优化礼物系统技巧,带来题为《百万弹幕下的直播礼物系统》的分享。
本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅2016年《程序员》
2015年开始的百播大战,熊猫TV是其中比较特别的一员。
说熊猫TV是含着金钥匙出生的公子哥不为过。还未上线,就频频曝光,科技号,微博稿,站上风口浪尖。内测期间更是有不少淘宝店高价倒卖邀请码,光内测时用户注册数量就达几十万,火爆程度可见一斑。笔者作为写下熊猫TV第二行代码的Coder,见证了熊猫TV成立以来的风风雨雨。直播技术坑不少,本文简单揭秘熊猫TV这一年的技术架构演进,分析各个阶段面临的主要问题和应对方案,给大家做直播系统提供一定的参考。
熊猫架构 0.1- 来不及了,老司机快上车
这个阶段最大的目标就是按预期时间上线。
图1 项目规划时间表
组团队不表,10人左右的Web团队,从接需求,到上线,我们用了不到三个月。
这个阶段面临的最大难题:两个月就内测!
怎么办?找老战友刷刷刷!花钱买买买!作为一群经验丰富的老司机,我们用买零件翻新车的方法。网站内测公测阶段,需要满足用户登录注册、关注主播、看视频、发弹幕、加房管、领任务、送免费竹子等核心功能,采用了复用模块+主业务全新开发的策略。
复用模块
复用模块得益于团队的前360技术背景,根据直播秀场类项目上的技术积累,利用PHP框架Pylon、发版工具Rigger,在老战友的帮助下,重新搭建了一套QBus消息组件,长连接系统,改进的Redis、MongoDB和MySQL集群,视频云服务,敏感词服务,搜索服务,这个项目才有了强大的基础支撑,才有可能在两个月时间就上线。
视频模块——从新搭建视频云,RTMP推流拉流,接入三家CDN作为互备。这其中需要自己实现统一调用接口和服务,方便切换CDN: 推流地址、拉流地址、转码规定、开播断流回调、一键断流、连接数查询、流截图、直播时长查询。基本上每个接口都很重要!例如一键断流万一失效,则可能面临停业整顿风险;人数不准,主播挂人气刷榜,则可能导致不公平竞争而影响平台的体验与口碑。
分布式基本组件:复用Syslog-ng日志收集系统、Kafka消息队列QBus、MySQL主从库、Redis主从库、MongoDB、SSDB大容量存储。
长连消息:单机百万长连,支持千万用户同时在线,性能够用,保证聊天弹幕稳定性。
图床:很重要的一环,房间截图,用户头像。
CMS系统:配置各种推荐位,直播间的CDN调度。
主业务开发
虽然是个新项目,我们并未做一个一篮子应用,把所有接口放在一个项目,而是按功能模块分好项目,每人负责一个,对主站panda.tv项目提供内网API,部署方便互不影响,开发效率也比较高。
Flash播放器:ActionScript开发、视频播放、弹幕展现。
主站pandaren:页面展现,各个子服务的串联整合;Daemon Worker负责截图更新。
用户体系ruc:用户注册登录、用户信息。
房间服务vill:包括房间信息、房间列表、更新房间人气。
关系服务uprofile:包括订阅关系、观看历史、主播申请、内测邀请码 。
数值服务count:竹子赠送、主播身高、用户经验。
消息服务homer:用于房间划分,长连Session ID和熊猫TV房间用户ID的转换。
权限系统buffon:房间管理、房管、黑名单。
任务服务bee:新手任务、观看定时奖励。
主播直播时长bloodstone:主播固定工资需要按每月直播时长计算。
架构哲学和设计
熊猫TV架构第一原则是高可用
网络:需要应对国内复杂的网络环境,使用内网光纤互联的多IDC来覆盖多运营商。
资源:DB和缓存都是集群化,配置Virtual IP方便切换。
隔离性:不同业务不同机器,防止雪崩效应;核心和非核心业务隔离,流量扛不住情况保重点业务。
降级:从Nginx和API层设置接口开关、Cache开关、DB开关,出问题一键切换。
超时控制:主站每个依赖业务设置5秒超时,并有报警和错误日志。
异步:用户不关心实时结果的大写入量业务使用异步方式更新,提高核心服务性能。
监控:服务器错误设置log监控、接口监控报警,随时处理线上异常。
架构目标(SLA)
根据以往新项目经验,预估支撑1000TPS ,百万日活用户,单房间10万左右在线弹幕;平均响应时间在100ms,99.9%在1s内;千万级别数据量;99.9%的可用性(全年宕机在9小时以下)。
架构选型
四层负载均衡:LVS,目前基本是业界标配,如果使用云服务的话可以用厂商提供的负载均衡,如阿里云SLB和亚马逊ELB等,这种第三方依赖都需要严格引流压测确认DB层、缓存层、Web层是否
有坑;
Web层:Nginx+PHP-FPM,开发迅速,适合团队技术现状,但需要针对服务器,做一定的调优配置。
缓存层:Redis主从库、SSDB大容量存储,会在各个业务块儿使用,增加系统性能。
存储层:MySQL主从库存储重要业务数据,属性变化不大。MongoDB数据库存储字段不固定变更较多的数值明细记录。SSDB存储观看记录关注等列表较长,且性能要求较高的数据。分表分库上考虑用户注册量和主播播放频率,用户中心、主播播放时长采用了按用户ID Sharding和 按年Sharding两种策略。业务初期暂时没有分库需求。
消息队列:实现业务解耦,使用当前较流行的Kafka队列。
设计实现
机器配置采用6核16G的虚拟机。服务部署单独的XEN虚拟机集群,互不影响,进行多机房互备,机房间光纤专线内网互通。
图2 整体架构
120台虚拟机分给十多个业务,主站用了40+,三个IDC——电信联通移动同时使用,流量大的主机房在电信,其他两个机房部署Redis、MySQL从库,写都在电信。预估的注册在线人数百万级,QPS万级。接口使用PHP-FPM对外服务,单机性能平均500QPS+,内测邀请制,内测一个月期间十几万人涌入,解决了一些小Bug,然后大家颇有信心迎接公测。
熊猫架构1.0——一只穿云箭,千军万马来相见
这个阶段属于填坑,最主要目标是网站稳定可用。虽然每个服务都有多机房灾备,微服务化也做了较好隔离,但0.1不到一个月便宣告夭折,我们低估了熊猫TV的明星效应,低估了黑色产业链的薅羊毛能力。公测一开始,熊猫就炸了(水友术语,指网站不可用)。
重点问题
网站首页和房间页不可用,无法进房间看视频;
已经在直播间的用户直播卡、弹幕卡、弹幕发不出去。
分析:网站因注册和用户信息、首页、房间页访问量过大导致FPM进程跑满,接口和模版渲染耦合,本身占的调用时长就会过多,服务间断性不可用,Redis缓存首页推荐位和用户信息只需几百MB,但连接数过多,内存占用到10G+,导致Redis响应缓慢不可用,垃圾号疯狂注册,第一天便破百万,用户中心出现服务异常,缓存命中率低,进而雪崩。
聊天弹幕爆发,时段非常集中,每日晚8点到凌晨2点为网站高峰时段,如图3所示。
图3 某个Redis端口QPS情况
这些也是直播网站会一直面临的核心稳定性问题,针对这些问题,大架构框架没有变动,加班加点,两周时间就上线了新一版架构优化。
高性能
主站重点接口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 - 新视界,大不同
到2.0阶段,初期的刷脸靠战友帮搭建基础服务和买第三方服务,已不能精细化、定制化地支撑业务快速发展,而此时人员配置也开始完善,熊猫TV开始了全新的2.0自主研发阶段。
本阶段也属于稳步发展阶段, 最主要的目标是视频流畅清晰、弹幕互动效果稳定。
视频优化
接入决策上,接入更多家CDN,并对CDN稳定性做指标考核和严要求:根据卡顿率、延迟时间、首屏时间、声音视频同步率等指标,结合运营经验,创建了一套立体化多维度的CDN-SLA体系,决定给予流量多少,主播级别,主播数量。这样也增加CDN的危机感,更好服务用户。
视频流调度互备上,如图4所示。
图4 视频流调度互备上
主播推流区分默认配置和管理员配置,推向对他而言网络状况最好的CDN,CDN自身节点实现各地的复制,CDN之间实现推流互备,一个CDN挂掉,不影响使用,用户根据PC或手机端区分,从对应配置的CDN拉流看视频,从而实现最佳观看效果,Web端用户也可切换备用线路,当默认CDN出现问题,则选择从其他家CDN进行拉流。
这样就保证观看的流畅和视频的整体高可用。
全新开发长连接系统riven来提供弹幕服务
图5 riven 整体流程
建立连接:
通过房间ID获取网关IP;
根据网关IP建立长连接;
更新网关上房间ID和长连接的对应关系。
下发消息:
同步消息;
生成消息机房对其他机房进行同步;
同步消息的机房不在进行同步行为;
根据房间ID获取房间所在的网关地址列表;
向网关列表下发消息投递通知;
网关查询本地房间对应的所有连接,并进行消息投递。
使用Golang+Redis全新开发,对消息级别、消息发送和消息内容做了一定优化。级别上区分多种Level消息,在高峰期、网卡被打满极端情况下,丢掉部分不重要消息;消息发送进行打包方式发送,一个房间的消息一次批量推送几十条,减少TCP交互;消息内容去掉无用字段,减少长度,例如礼物消息一条减少了168字节,假设高峰期一个房间十万人在线,一条礼物消息能节16MB,大主播房间按1000个礼物一小时算,能节省16GB流量,非常可观,所以一定要注意消息内容的压缩和缩减。
整体架构上的改变:一年以来用户量爆炸式增长,达到日活用户近千万,PV上亿,同时直播主播近万间,流量峰值TB级别。技术人员也扩充了4倍,随着王校长驱动开发、尹素婉驱动开发(尹素婉是韩国第一女主播)、PDD驱动开发(PDD是前职业选手,著名LOL主播,弹幕量大,观众百万)等模式的驱动开发,熊猫快速步入2.0时代,技术架构也有了更稳固的改进,新的PHS(Panda High-Perfomace Service熊猫高性能服务体系)设计思路是增加架构层次,明确微服务边界,基础组件从外部依赖到内部自研,架构层次宏观层面分为端、接入层、平台服务化、中间层、基础层五个层次。
图6 架构层次
端
包括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架构改进思路是应对峰值流量高度集中的直播需求,总结几条经验:
不能依赖单个CDN。可自建,可用第三方,但中国网络环境太复杂,必须高度重视容灾。海外推拉流也需要十分关注。
弹幕消息一定要做策略优化。广播蝴蝶效应明显,峰值可能将机房整体带宽打满。区分弹幕优先级,做好降级预案。
提高金钱敏感度。直播网站由于有很清晰的变现模式,要严防褥羊毛,严防色情内容,火速响应监管,支付礼物交互一定是高可用、严监控。
N个大主播 = 半个网站峰值。必须考虑某些特殊主播的火爆人气,做好视频弹幕房间信息上的峰值应对。
熊猫TV因快速上线和爆炸式增长,从严重依赖外部服务,到自主自建核心业务,弯路走了不少,也对直播技术有了更深的理解,积累了丰富的经验,技术团队也从20人左右快速扩展到百人团队,为熊猫TV在百家直播平台中挺立飞奔奠定了技术基础。未来我们会在以下方面继续努力:
自助式运营处理:帮助运营自助处理问题,直接和CDN对接,帮助技术人员从简单重复问题处理中脱身。
反作弊:基于大数据处理体系的用户画像、设备画像、IP画像、内容画像,多维度构建反垃圾反盗号功能 。
长连优化:支撑千万用户在线的高并发实时弹幕和聊天。
礼物商城:优化计数对账,幂等处理整个支付到特效抽奖、弹幕消息、消费记录、统计等流程。
Golang、NodeJS服务化:替代性能较差需要各种优化的PHP,服务端接口全面Golang化,前端也在合适的场景使用NodeJS提高服务性能。此外需针对KV存储做value压缩,节省流量,提高接口速度。
数据挖掘和机器学习:渠道分析、用户分析等便于产品和高层决策,甚至开发出机器人主播互动。
推荐:在综艺化娱乐化多元化的内容基础上,个性化推荐用户感兴趣的直播内容。
搜索:自建搜索,从用户维度、聊天维度更好服务用户。
日志收集分析:高性能日志方案探索,更快更迅速发现业务问题,分析流量变化。
广告系统:友好娱乐化的广告展现,精准推送,严禁的计费系统。
支付:国际化支持,多种银行卡信用卡接入,多种货币支持。
NewSQL:引入TiDB等新SQL技术到某些业务,替换Redis、MongoDB、MySQL,更方便友好地进行技术开发。
直播面临的核心问题是网站稳定可用、视频流畅清晰、弹幕互动效果稳定。直播技术看似简单,一家视频云可以帮助创业公司一两个月就构建出一个直播App,但其中的运营难点、技术难点、流量带宽问题都需要谨慎处理,希望本文能帮助直播行业技术人员跳过一些坑,架构设计时作为技术参考。