嘉宾|Wood(张木喜)
编辑|薛梁
1 写在前面
11 月 10 日,今日头条正式与北美知名短视频社交产品 musical.ly 签署协议,将全资收购 musical.ly,在此之前,musical.ly 的全球 DAU 超过 2000 万,但国内鲜有人知道这家公司和其业务。
2014 年初,从易宝离职的阳陆育 Louis 拉上同样热爱音乐的前同事朱骏一起创办了 musical.ly。这是一个强调音乐元素的短视频应用,用户可以先拍摄一段生活中的视频,然后在乐库中配上音乐,从而快速地创建时长 15 秒的 music video;或者从喜爱的歌曲中获得灵感,配上一段有意思的画面,然后分享给自己的朋友。
巧合的是,即将于 2017 年 12 月 8-11 日在北京举办的 ArchSummit 全球架构师峰会上,musical.ly 高级技术副总裁 Wood(张木喜)老师也是会议的联席主席之一并兼任出品人。
借此机会,InfoQ 很荣幸地在会前采访到他,请他聊聊 musical.ly 发展的这几年在架构上的迭代经历,以及未来支撑庞大业务背后的数据平台架构该如何搭建等思路。本文基于采访整理而成。
2 musical.ly 功能模块及架构
木喜老师首先简单介绍了 musical.ly。他说,musical.ly 是一个短视频社交应用,从某种角度看,可以类比为短视频的微博,包含视频发布,视频信息流,评论,关注,点赞,用户主页,私信,通知,话题等功能。
短视频社区是一个与娱乐内容分享和观看为主要特征的社区,所以短视频的信息流和推荐无疑是用户用得最多的功能,实际上用户进入应用直接就到信息流页面,musical.ly 是一个内容创建非常活跃的社区,平日每天创建的短视频数接近 1000 万,周末更超过 1500 万。视频的生产和消费是驱动社区发展的主干功能,而支撑社区互动的点赞,评论和关注则是紧随其后的用户用得最多的功能。
3 紧耦合架构的优势和劣势
我们关注到,musical.ly 最初的运营系统采用了传统的紧耦合架构,这样的架构固然存在优势和劣势,木喜老师回忆说,早期 musical.ly 的架构不是为大规模站点设计的,而且从今天的观点来看,这也是当时最能适应业务早期快速迭代和功能验证的架构。
当时采用的方案是经典的 tomcat 加上 SSH 架构,数据库用 MySQL,缓存用 memcached,简单可靠,不需要开发人员有复杂系统经验,所有的功能用一个 codebase,业务稍微成长也能通过简单扩机器解决。实际上,在创业早期进行复杂的架构设计带来了额外的成本,对快速推进业务有害无益。简单,快速,满足需要,是这种单一架构的优点。
musical.ly 这套架构一直支撑到接近 100 万日活,但是这样的架构劣势也比较明显:
随着业务的发展,功能变得更加复杂,人员也逐渐扩充,代码变动频繁,问题变得越来越多,各种功能同时在上面修改,发布导致的问题越来越多,代码极度臃肿;
用户规模的扩大,数据库不堪重负,各种问题导致线上故障频发甚至宕机。
正是在这样的情况下,musical.ly 团队开始进行全站微服务化改造。
现在回顾起来,这样的演进路径适合绝大多数的创业公司,就如软件工程强调“不过度、不过早设计”一样,早期在业务不确定性很大的情况下,把精力放在功能打造上,在业务成长起来后有足够的时间去做更适合当前要求的设计。况且一般的早期创业团队很难吸引高水平的技术人员加入,过早考虑规模问题更不可取。
4 微服务架构改造
musical.ly 技术团队都有 Java 背景,刚开始进行改造的时候框架选用的是 SpringCloud 框架:
一方面是该框架以 Netflix 的软件栈为基础,而 Netflix 则一直被奉为微服务实践的典范;
另外一方面 SpringCloud 框架的功能也相对全面,所以在跟 Dubbo 进行比较之后选择了前者。
在微服务架构基本成型之后,根据经验,团队对框架本身做了较多的改造,替换了更友好的注册中心 Consul,采用了 gRPC 作为远程调用框架,用 Protobuf 作为序列化框架,替换了熔断和限流方案,集成了故障诊断和追踪功能等等,这些改造对业务是透明的。
musical.ly 的应用层架构从上到下分为:
API 网关
API 接口层
聚合服务层
业务层
基础服务层
遵循的基本原则是:服务只能从上往下进行调用,同层之间不能互相调用,同层和底层业务对上层业务的耦合只能通过异步消息进行。这保证了接口调用深度的可控和最快的响应速度。
社交应用本质是事件驱动的系统。当用户出发一个动作,会在各个子系统之间形成一系列后续动作,就跟涟漪效应一样,事件会在系统范围内扩散。所以 musical.ly 的架构是面向异步的,尽可能简化同步调用所做的功能,而且尽量减少前端系统对后续动作的感知,把耦合的位置后置到数据库之后。
举个例子,用户对一个视频点了赞,对前端系统来说,做的是一个最简单的操作,就是简单验证用户对视频是否可以点赞,然后就直接添加点赞记录,这保证了用户操作的快速响应。
musical.ly 技术团队在系统中尽可能地使用变化捕捉技术 CDC,实际上就是尽可能地利用 MySQL 强大的 Binlog 功能,通过对 Binlog 的监控和处理,让前端业务无需关注后续业务。CDC 捕获变化后,会把数据库的变化转化为目标事件,注入消息队列,采用了 Kafka,其最好的特性之一是单一事件可由不同的消费者消费多次,这样无论扩展了多少种后续业务,只需要开发出不同的消费端即可,对原有系统不需做任何改变,很好地实践了单一责任原则,极大地提升了系统的扩展性和稳定性。
木喜老师说,技术团队在微服务的基础上,提出了泛服务的概念,提出一切皆服务,服务只有协议、功能和有无状态的不同,通过服务注册和发现完成耦合。数据库、缓存、中间件、业务服务都是微服务,这极度简化了 musical.ly 系统的概念模型。
5 基于云的系统高效部署和优化
目前,musical.ly 在系统运维上也尝试了 AIOps,并做了很多努力,目标是让系统在低风险的情况下尽可能地实现自动化运维,提高系统的可用性,降低手工干预的强度。
前面讲到泛服务,其实 musical.ly 内部还有另一个概念,叫融合架构,就是从系统设计上,把业务架构、平台架构、数据架构作为一个整体来考虑,把一切运行的程序都 API 化,这就为全面自动化和数据驱动以及更高大上的 AI 留下了切入的接口。
CI、部署、监控、伸缩容都是 API 化的,加上 musical.ly 的系统部署在云上,云本身也是可编程的(这是云最大的优点之一)。这样 musical.ly 系统可以分为两大类,业务服务和为业务服务提供支撑的系统服务。结合服务的全面 Docker 化,实践了 IaC(Infrastructure as Code)设计。通过 SPEC 来完成对部署和状态的定义,而非过程化的脚本。基于目前的系统服务,实现了两个比较有特色的功能:
一部分是泳道部署,通过把服务分泳道部署实现了前台服务,异步 consumer,核心和非核心服务对依赖服务的相对隔离,很好的实现了柔性和有损系统,极大提高了整站的可用性;
另一部分是系统动态伸缩容,云的特点是资源按使用付费,系统的高峰和低谷的资源需求量差别很大,整套服务可编程化之后,musical.ly 团队可以全动态的来实现资源的申请和编排,甚至充分利用 AWS spotinstance 来实现对保留实例的动态替换来追求成本的极致节约。
接下来,实现系统的单元化部署,使系统能快速实现在全球不同数据中心的快速部署和复制是技术团队的下一个目标。
6 国际化架构挑战
musical.ly 的用户遍布国内外,那么对于这种国际化业务场景,musical.ly 是如何克服网络、本地化、部署及架构优化等等困难的?
木喜老师说,在世界的不同国家和地区,网络情况差别很大,特别是新兴市场国家,有些地区网络情况非常复杂,运营商众多。主要问题包括 DNS 解析延迟高,跨境距离⻓导致天然延时长,TLS 握手时间过长,传统 TCP 缺陷导致的初始拥塞控制窗口小、存在慢启动、无线弱网环境丢包概率大等。
musical.ly 技术团队做了很多的努力来优化网络连接,以部分实践为例:
一、网络协议:
为了降低 DNS 解析延迟,增加 HttpDNS 部署节点来降低延迟,同时规避 DNS 劫持;
通过修改丢包重传算法,减少重传超时,自适应的初始窗口和更小的连接超时时间来改善弱网体验;
根据移动 App 的特点,预置公钥,去掉 RTT 交互来优化 TLS 握手;
另外,通过多供应商来进行 API 的动态加速和音视频的静态加速,同时在客户端埋点收集每次 API 和互联网访问的耗时都上报的服务器,全面了解各个地区网络的健康情况,对关键指标做实时监控,确保能及时处理网络故障。
二、本地架构:
在存储架构上支持多存储架构,把多媒体资源尽量存储到本地,确保最优的访问速度。
对图片资源和视频资源,根据数据分析,压缩成多个不同码率,提高压缩强度,降低了同样画质所需要的码率,而通过码率自适应,在网络状态不太好的情况下最大程度降低下载失败的比例和加载时间;
在客户端大量使用预加载和缓存,最大程度优化网络流量和提升起播速度,改善使用体验。同时,musical.ly 正在加快推进数据中心的全球异地多活部署,以进一步提升可用性,缩短网络时延。
7 如何能和 Facebook 一样支持 10 亿日活用户量?
木喜老师认为:支撑 10 亿日活,挑战来自于服务容量和数据处理能力两个方面。
最基础的还是业务的高并发以及大规模分布式数据服务,如何实现服务的可线性扩展和业务数据的海量存储。
这是泛服务的延续话题。微服务的可伸缩性,业务服务器是无状态的,理论上只有增加服务实例就可以实现业务容量的提升。所以关键在于实现有状态服务的可扩展。musical.ly 的数据库和缓存服务,在泛服务的理念下,也都是通过服务注册进行耦合的。在这块系统的设计上,团队遵循组合优先及尽可能避免重复造车轮的原则,使用一套功能分离的组合服务来实现一套功能完善的分布式数据服务。在几乎不改动开源软件源代码的情况下,通过胶水组件,完成系统的集成和耦合。
数据服务包含存储,分布式,动态伸缩,高可用等模块。以关系数据存储为例,存储是 MySQL,使用 Kinghsard 来实现分布式访问,MHA 用来做 HA,通过 musical.ly 自己开发的一些小组件来实现 MySQL 实例状态和分片信息再 Consul 的动态更新,以及集群信息更新监控和 Kingshard 配置文件的映射,实现每个组件都干自己最擅长的部分,彼此互不感知,彼此分离,因而实现了最好的稳定性。
努力减少与系统正常进行无关组件与线上系统的耦合,集群的伸缩几乎以离线的方式进行,只发生极短时间的切换,保证了系统的简单可靠。目前的架构设计满足支撑亿级日活没有太大问题,后续会随着日活的增长进一步改进。
8 嘉宾简介
张木喜(Wood),musical.ly 高级技术副总裁,2015 年底加入 musical.ly 蜜柚网络科技,任高级工程副总裁,主持进行全面技术转型。致力于高可用和柔性系统,以及从架构上促进业务和数据算法的融合,通过技术推动产品、运营。在此之前的工作经历是点评架构师,阿里音乐天天动听 CTO,有多年的系统架构、应用架构从业经验,在微服务架构,分布式缓存,数据库和大规模系统监控领域都有丰富经验。2014 年加入天天动听,领导产品技术团队,进行天天动听的基础技术架构改造和产品研发。
再次感谢木喜老师接受采访,期待木喜老师下周在 ArchSummit 策划的“架构升级与优化”话题,另外大会也荣幸地邀请到 Musical.ly 技术部高级 Java 架构师杜鹏老师前来分享《基于社交关系的 Smart Feed 架构》,可识别下方二维码或点击 阅读原文进一步了解。