云原生之下,视频云业务的10大实践经验分享
大家好,很高兴能有机会和大家去分享华为在云视频 Cloud Native(云原生)实践过程中的一些经验。
我的分享主要分为三个部分:前两个部分和大家一起回顾关于 Cloud Native 本身具有哪些的特征以及架构;第三部分是我重点想和大家分享的,即我们的视频云业务在探索和实践 Cloud Native 的过程当中具体是怎么做的,以及遇到了哪些问题,希望本次分享能够对想要或者正在使用云原生的小伙伴带来帮助。
一、Cloud Native 的前世今生
1. 业界对 Cloud Native 的描述 我们先来回顾一下,在2010年,Paul(Paul Fremantle)提出了云原生的概念,起初只提出了关于弹性、分布式、多租户等基本特征;随着实践和发展,Adrian(Adrian Cockcroft,2013)和 Matt(Matt Stine,2015)相继对关键特征进行完善,逐渐提出了反脆弱性、DevOps、持续交付等更新的认识。这就是 Cloud Native 最初的发展。 从团队来看,CNCF 提出了 Cloud Native 的特征和目标,Gartner 也同样做出了重要的规范。
2. 对云原生的定义和要求 华为公司早在2016、17年,就开始通过内部发文的方式,统一云原生定义并规范语言,便于各部分和业务之间对齐语言,包括(微)服务化、弹性伸缩、分布式等,同时对这些关键特征的定义和范围,也都做了非常详细的规范。
3. Cloud Native定义及关键特征
整个云原生,我们认为应该分成三大部分。基于康威定律,组织决定其所成就的业务。对实践云原生而言,组织的变化最能使我们感同身受,尤其是对每一个人的能力要求发生了非常明显的变化。例如,对研发人员不再像以前传统模式下的要求,即根据需求按要求实现就可以;现在,从前端需求讨论,到需求分析,再到开发、参与测试、参与灰度的过程,最后到上线以及在线网运行的情况,包括监控、告警等,都需要端到端的关注。所以,对团队的要求提高了。
今天,我重点和大家分享的是关于云原生的架构和工程方面。各个公司根据不同的业务,都会涉及到这两个方面,所以更有参考价值。架构方面的核心是微服务架构,其后还有弹性伸缩和分布式等特征;工程能力有 DevOps、持续交付、灰度上线等。最终的目标是让云应用能够快速高效地部署和规模化,以及实现整个服务的高可用性。这是云原生的整体概述,下面我将围绕架构和工程两个方面和大家展开分享。
二、Cloud Native 的基本特征和架构
1. 微服务架构的定义及优势
云原生的架构,最核心的部分是微服务的架构。微服务的首要特征是高内聚、功能单一,最好的状态是一个微服务只做一件事情,并且各微服务之间通过进程隔离、独立代码库等,使得每个微服务都可以单独测试、部署和升级。这样,单个微服务规模较小,可以做到灵活使用且易于管理。实现微服务化后,整个云原生的交付和小团队沟通都能快速进行,因为微服务之间使用 API(应用程序编程接口)通信,没有了开发语言的限制,小团队沟通会更简单、顺畅。任何一个功能点或微服务出现问题,其故障影响范围只存在于本服务器内部,这样可以提升微服务整体的高可用性,且每个微服务都能单独演化。
2. 传统软件架构与微服务架构对比
既然微服务如此重要,我们就来进一步对比微服务架构和传统架构。传统单体架构的软件是按模块划分的,一个复杂的系统可能会划分几十个甚至更多的模块,每个模块完成一定的功能,模块之间可能是内部代码级的接口调用或本地 API 调用。可以看出,在架构简单或系统功能单一的情况下,单体软件在初始阶段效率可能更高,因为整个系统使用一套代码,在部署和静态检查时更容易管理,且内存是共享的,可以调用,时延更低,这是它的好处。如果云原生下的所有功能点全部通过微服务化的 API 调用,调用之间就会造成时延。
那么微服务架构有什么好处呢?进程隔离,代码之间彻底解耦,即各微服务可以单独演化和发展。对比传统的单体架构,其在设计上肯定想要解耦使模块功能独立,但在架构演进的过程中,开发人员难免把控不力,导致耦合越来越不清晰,同时每个模块的变动都会涉及到其他模块的升级变更,甚至影响到技术栈发展。一个模块的重构会对另一个模块产生影响,导致整个系统的演进变得异常困难。但是,在服务化架构下,以上问题都能迎刃而解。每个服务之间通过 API 协作完成,更加灵活高效。随着系统规模的扩大,效率也不会降低,可用性和开发效率等方面也能得到保证。
3. 充分利用云基础设施及平台服务
在充分使用云基础设施及平台服务方面,我们的架构师和设计人员的思路也发生了较大变化。云原生软件构建在整个云的基础上,云包括计算资源、网络资源、存储资源、消息队列等,优先使用云服务上已有的资源,而这些资源通过编排的方式调用,便于实现整个系统的可用性。也就是说,每个服务、每个应用,仅需关注自己需要实现的部分,而不是实现每一个功能。在单体架构下,较常规的情况是:需要某一特性,就找到一个开源的代码、软件或模块拿来使用,这种方式是不可取的。在云原生下,通过调用其他服务来实现会更聚焦和高效。
4. 弹性伸缩
弹性伸缩也是云原生的精髓,主要需要解决两个问题:一是“伸”,二是“缩”。对于视频业务而言,其规模往往是不可控制的。若主播在直播时产生一个爆点,大量用户涌入,导致业务量陡增。这时,我们的服务需要能够自动拓展资源,如果等到业务人员接收到高负荷提醒后,再主动升级变更扩展资源,可能会来不及。以上是弹性伸缩中“伸”的部分,而“缩”的必要性主要基于成本。我们知道,视频每天都会有一个高峰期,比如,教育类的视频服务会在早上上课的时间达到高峰期,而游戏类的直播视频在晚上8点到10点是高峰期。高峰期相对于低峰期,其业务规模相差十倍甚至百倍以上,若资源不会自动开放,在空闲期间就会造成资源浪费。“缩”就可把资源释放出来,提供给其他服务使用。
5. 分布式
分布式是云原生的一个核心理念,主要用于提高可用性。分布式分为三部分:其一,应用分布式,分布在多 AZ(可用区)和多 Region(区域)上。如果出现一个故障,不至于影响到其他方面。例如,一个城市的电力系统故障,或者某条光纤被挖断了,也不至于影响到整体服务的可用性。其二,数据分布式。各城市之间,重要的数据需要做到跨 Region 和跨 AZ 的同步部署和存储。其三,跨可用区的部署以及整体的调度。用我们今天的分享举例,整个媒体处理分布在各个不同的 Region上,假设某个城市的光纤出了问题,也不会影响整个直播的过程和质量。这就是分布式带来的好处。
6. 高可用
在云原生下,可用性和传统模式有着本质的区别,在设计思路上就全然不同,云原生是基于不可靠、可抛弃的资源设计反脆弱性的系统。举例说明:在沙漠上建一座牢固的大楼,应该怎么建?我们不能因为沙地不稳固,在其上建造出的楼也不稳定。云原生的系统设计,并没有假设系统下的资源是稳定的,实际上所有资源都可能出故障。那么,系统的反脆弱性具体应该怎么设计?这才是我们云原生设计的精髓之一。
7. 认可失败的设计
在传统方式上,我们总是在安全、可用等方面下大功夫,希望把系统中的 bug 和故障全部清除掉,不留任何隐患,这种思路是没有错的。但是,随着云上系统规模越来越大,云服务越来越多,想要清除所有的 bug 几乎是不可能完成的任务。在设计上,我们应该承认失效是时常发生的。同时,需要考虑的是,如何在系统或者某个功能失效的前提下,业务还能正常运行。如,在某一微服务出现故障之后,如何快速发现并自我隔离,从而消除其对整个系统的影响;甚至,在整个可用区和核心服务出现故障时,怎样对服务进行降级,而不是任由整个服务瘫痪。比如,系统中有10个业务,现在出现一个故障,导致3个业务不可用,那么另外7个业务是否能继续服务?这是在云原生下设计系统的一个核心理念。
8. 自动化运维——基于数据分析的全方位故障监控
目前,云原生下的微服务数量较多,大部分情况下,如果系统规模中等,微服务数量是几十上百甚至更多,若采用人工运维的方式几乎是不可能的。因为每个微服务的运行状态都是非常复杂的,且各服务之间也会产生各种复杂的关系。若仅从最上层的客户黄金指标来判断系统的运行状况,那最终出现问题时,事态可能已经很严重了。所以从开发、部署、升级、问题定位等各方面来看,自动化运维都是云原生下非常重要的一环。
9. 灰度发布
灰度发布也是整个云原生核心的一部分。我们的系统一直处于开发当中,如果没有灰度发布,如何变更一直在开发中的系统?打个比方,一架飞机在高空飞行,不能等飞机落地之后再更换发动机。同理,如果我是一名客户,想让系统停下再去变更,也是不可能执行的。那么,如何在变更的同时保证所有的业务可用,并且保证系统能够稳步向前发展,这其中有着非常大的挑战。灰度发布是目前应用较广泛的方式,其他还有滚动发布、蓝绿发布等方式,其中蓝绿发布会造成资源浪费。灰度发布是目前常用的一种方式,通过灰度升级,逐渐扩大灰度范围,从而保证整个服务的可用性,中途若出现问题则快速回滚。
三、华为云视频 Cloud Native 实践
下面和大家分享我们的视频云业务在实践云原生过程中的一些经验和教训。
1. Cloud Native 架构能力
华为云不但统一了云原生的定义和语言,同时还对多个云原生项目进行了总结,包括内部的架构设计指南,即云原生的架构具体应该如何设计,其中还包括一些优秀案例。对于不同的场景和模式,我们构建了架构模式库,在设计过程中,可以直接参考模式库,方便高效、高质地完成架构设计。对整个云原生,我们也进行了全面、规范的体系建设,各服务间的 Console、风格,包括如何鉴权、AKI 网关如何对接、接口风格等,都有统一的规范。最后一点很关键,针对各业务的云原生研发成熟度,在工具中设立云原生架构评价标准,提供数值打分。这样,包括云视频在内的每一个业务,都可以衡量其当前状态与理想状态之间的差距,并且知晓待改进的方面在哪里。
云原生是一系列云上经验的总结,在实施过程中,没有把所有经验全都实践一遍的必要,只需引用业务所需的实践即可。重要的是经验的价值。
2. 架构-微服务架构
我们对微服务架构也做了总结,从服务发现、服务注册、到服务划分和部署等,各模式都有统一的要求。包括可用性、自动化运维等等,在这里就不详细展开了。
业务刚刚构建之初的微服务架构,当时对云原生的了解并未深入,业务逻辑相对比较简单。大概一年之后,我们发现以前的业务架构出现了问题:第一,开发效率越来越低,由于一个服务的开发经常会涉及到其他服务,并且需要频繁变更,导致一个需求需要很长时间的开发才能上线,客户响应时间明显变低;第二,测试越来越困难,架构出现腐化,代码出现坏味道。基于多种方式判断,我们认为需要重构架构:将之前的 VodManager 微服务拆分为4、5个服务,每一个服务的功能逻辑都是相对独立的,一个需求的开发只会落到一、两个服务里,测试变得简单,开发也更加高效。我认为,微服务划分是动态的,没有一个理想的架构和划分方法,只有一些指导的原则,这些原则就是我们之前所讲到的,这里就不赘述了。需要根据任务场景、以及系统业务复杂度、用户数量和具体要求等方面统一看待,有问题就进行重构,没有问题就尽可能简单化。这是我们在微服务架构重构方面的一些实践。
再强调一点,这里的微服务架构并不能一次性变更到位,而是一个逐渐演进的过程。可能本周拆分出一个微服务,下周又拆分出一个微服务;并不能提前限定时间进行拆分,然后一次性上线。我认为原因主要是基于质量上的考虑,如果突然重构全部架构,可能会涉及几十甚至更多代码同时上线,质量是很难保证的。每次变更一个微服务,就会有一个灰度过程,从而保护客户服务的可用性。目前,整个视频云版块,我们的服务个数大概有2百个,人均一个或一个多一点的规模,都有对外 API 接口,接口数量约2千个。并不是说越多越好,以上内容仅给大家做一个参考。
3. RTC 用户接入微服务容器化实践
我们认为在云服务上必须要做容器化,因为各微服务之间是相互独立的,而且应该设计为无状态,随时可以被销毁。我们实时性视频的一个微服务,目前已经商用了,其中一个案例可以和大家分享一下。所有微服务全部容器化,因为任何一个实例都可以被销毁,如果出现变更或是业务量上升,随意拉起一个微服务,其他微服务仍能正常工作。在这里重述一点,进行对外服务的微服务,我们建议首先通过域名调度,不要通过 IP,因为可能会有多 Region 的情况。大家都明白,如果一个 Region 出了问题,域名还能解析到另一个 Region 上去。对于对外呈现解析的 IP,首先它应该是一个 EIP,且需要有主备,不能是单一的 IP。因为 EIP 可以对应后面多个 IP 地址,可以保证任何一个 IP 或者主机出了问题,都不会都整体服务产生影响。这是对对外服务微服务的一个考虑。
另外,所有微服务之间都不能直接调用,都应该通过服务网格的方式调用。目前华为云上比较成熟的是 CSE,该方式经过了大规模的考验。比较新的方式有 Istio,这两年逐渐开始使用,服务线数量增加较快。我们的整个视频云板块 Docker(容器)的数量最高峰的时候达到了好几千个。
4. 使用容器化的收益
这里通过我们自己遇到的一些情况,特别讲解一下容器化的好处。最开始我们并没有采用容器化的方式,后来发现通过容器化,资源利用率明显下降,因为弹性伸缩做的比较容易;另一点是快速启停,我们现在用容器基本可以达到秒级重启,如果需要就可以秒级弹出、秒级部署,而且各个服务之间的迁移、依赖关系、解耦、服务打包等各方面操作都很迅速。我们现在代码的升级、变更、流水线等等都是和容器化绑定的。以上是我们关于容器化的实践。
5. 实时转码服务的弹性伸缩实践
刚刚也提到,弹性伸缩在云原生里是很重要的一部分,因为它切实影响到可用性和成本。视频中的弹性伸缩主要考虑什么问题呢?首先,"弹",我认为是没有问题的,使用起来很简单,根据事件驱动,如内存、网络、业务量等,当达到某一特定值时,相应地弹出多少个实例,弹出速度非常快,基本可达到秒级弹出。所以,“弹”的方面是没有问题的。但是,对于视频业务而言,“缩”也非常重要。那么,“缩”具体会遇到什么问题呢?视频包括直播、会议、RTC 等业务,对实时性的要求非常高。比如,在某一个实例上,有1000个用户同时在观看,其中有800个已经下线,只有200个占用了一个实例,此时应该怎么办呢?我们的做法有两种,一种方式是,在新业务的调度上,基于部分指定的容器优先预调这些业务,尤其在业务规模的下降期,根据业务的情况,可能要留出半小时到一小时不等的时间进行收缩。对于实在很小的业务,怎样把直播迁移到另一个容器当中去,而且对用户的观看体验没有任何影响。这才是弹性伸缩实践中,云视频业务做到“缩”的时候很重要的一点。
24小时内高峰期和低峰期的资源利用率的峰值有10倍甚至百倍之差,但CPU资源的利用率还算平稳,并未出现大起大落。这就是弹性伸缩所需要做到的一个能力。
6. 视频云统一OPS 平台
云服务上没有 OPS,相当于人没有眼睛。操作每一块业务,可视化每一项服务,出了问题之后快速定位,OPS 都是核心能力。业务监控、配置、调用链、日志规模分析等都能在 OPS 里很好地体现。这一部分与业务相关性较强,包括故障的定位定界、运营、管理、配置等都是必须的。
7. 视频云监控运维系统架构
OPS 平台依赖大量的数据,尤其是日志的数据,因为问题的定位、定界、故障,告警等,全部分析都依赖于这些数据。在云服务下,整个运维的架构非常重要。对于视频云板块,我向大家展示一下我们的过程,供各位借鉴。
针对数据采集上报,需要考虑本地冗余,不能直接上报,在失败之后就丢掉。而且考虑成本,并不会预留很大的数据通道供使用,所以本地需要有缓存能力,以及上报失败后重复上报的能力。对于数据接入,我们采用 Kafka 对数据进行二次汇聚,因为原始数据过大,对其分析、存储、查询等规模上都无法满足。目前,每天的日志量可达数百 T,而且不能长久存储。我认为,运维架构可以不断演进。我们的运维架构起初设计出来时,比现在的要简单很多,大家在构建日志系统或运维系统时,需要着重考虑以下两点:1、日志上报实时性。日志如同神经表现,快速获得日志,就能快速了解系统中存在的问题并解决。实时性是一个挑战,当然这也和成本挂钩。2、日志实时数据。包括数据的汇聚、分析、展示。
8. 工程能力-服务自治
前面提到在微服务架构下,会存在很多个拥有单独代码库的微服务,其相对单体软件而言更加独立,但随之而来的问题是管理。每一个微服务都需要人工部署,而且频度很高,几乎不可能实现。所以工程能力的工具化、自动化,且能够实现服务自治是云原生中非常重要的一部分,需要在最初时就开始构建。从开发人员写完代码到上线,需要经历哪些步骤:包括开发代码、静态检查、合规扫描、Alpha 测试、Gamma 测试、自动部署、灰度发布、在线测试等。虽然,开发一个功能可能只需要30-50行代码,但一套流程全靠人工几乎是不可能完成的。但是,在工具化之后,只需在本地开放代码并测试后一键提交,整个过程只在部署环节需要人工确认,其他步骤可以全部通过工具化自动完成,从而实现一人运维多个微服务。目前,我们的团队每月大约有500多次变更,一年达数千次变更。按照业务发展,并且视频领域更加活跃,包括 RTC 等业务场景,明年的变更次数一定会更多,所以服务自治非常重要。
9. 功能能力-灰度发布
灰度发布也是云服务核心的一部分,服务上限、开发过程质量的基本保障,目前主要使用灰度发布。灰度方式可基于流量、内容、域名、特性等,与开发特性相关,在脚本里便捷地更改后就实现快速发布。每种发布都有验证,验证可以是自动的拨测用例、人工拨测,还能与客户共同测试。
10. 架构-分布式&高可用
前面所讲内容,除了提升效率和降低成本之外,最核心的一点是云服务的可用性。云服务可用性是对客户的服务承诺,出了问题,不仅是赔款,更严重的是影响品牌信誉。那么如何做到可用性?总结如下:基于认可失败的理念设计,能够对失败的业务进行降级;同时对于底层资源做到多 AZ,这样一个城市的基防出问题时,不会影响整体服务,多 Region 相互容灾,最后实现整体的可用性。但是可用性只能做到尽可能高,不能做到百分之百,整个过程还需要大家共同探索。举例来说一个比较严重的410事件:某个 Region 区底层的所有资源几乎都不可用了,我们的业务,几乎没有受到任何影响。在保证业务不受影响的前提下提高服务可用性,应该是我们共同的愿望。
本次的分享就到这里,谢谢大家!
- 点赞
- 收藏
- 关注作者
评论(0)