QQ浏览器信息流云原生应用之路

宋廷豪,高级工程师,就职于PCG-腾讯看点。主要负责QQ浏览器信息流推荐架构的相关工作。

背景

QQ 浏览器信息流(QB)推荐架构支撑了 QQ 浏览器、快报主 feeds 场景、浮层等信息流卡片实时推荐的能力,架构上不仅仅要支持多业务、多产品,如 QB 、快报、外部合作等,而且需要能够快速支持各种类型场景的能力,如主 TL 、浮层,且能够快速扩展支持垂直频道和 APP 。那么信息流推荐架构需要做到灵活模块化,水平易扩展。

为了做到海量级实时精准推荐,信息流推荐架构划分为了四层:展控层、排序层(精排/粗排)、召回层、索引层,并提供实时级用户画像模型打分模块和特征系统,进行实时的用户/物品特征累积,实时反馈给推荐链路进行千万级索引文章/视频的筛选和精准推荐。具体的架构模块图如下所示:

可以看到,推荐架构容纳的模块之多,支持的业务形式之多,而且需要支撑亿级用户规模和百亿特征规模,那么需要更好的技术架构体系对于如此庞大的架构服务和存储去进行开发、扩展、管理、维护等。

挑战

挑战一:实时性

(1)特征实时更新

(2)模型在线实时学习

挑战二:超大规模

(1)用户量级:亿级用户

(2)特征规模大:百亿特征、千亿参数(无量)

(3)样本庞大:精排样本每日样本近百TB

挑战三:高性能

(1)全链路耗时达到业界领先水平。

解决方案

虽然推荐系统模块功能众多,是一个较为庞大系统,但我们以微服务的方式对推荐系统进行拆分。把一个庞大的系统划分为成千上万个微服务模块,每个微服务只负责相对独立的功能,并以远程 RPC 的接口方式提供服务,模块之间可以相互调用,从而形成了一个复杂的调用关系网,整体上就组成了一个庞大的推荐系统。微服务化以后,再结合云原生的相关技术架构体系保证云原生应用的稳定性,并提升资源的利用率和研发效率。

容器化

在云计算 1.0 的时代里,业界通过虚拟化的方式从硬件级分离应用程序,而容器的出现,标志着云计算 2.0 时代的到来,这个阶段应用是通过容器化的手段从操作系统级别分离应用程序。

在容器化的时代中, Docker 的出现使得隔离的开发测试环境和持续集成环境成为广泛实践,而 K8s 则让容器应用进入了大规模工业生产的时期。集群也能够最大程度地发挥发挥容器的良好隔离、资源分配与编排管理的能力。容器化后给企业带来的最大价值是人力和机器成本的节约。下图则从稳定性、可扩展性、资源利用率三大维度上对比了虚拟化和容器化的区别。

云原生时代

云原生(Cloud Native)这个概念最早是由 Pivotal 公司的 Matt Stine 提出的。并随着时间的推移,云原生的概念也不断在更新迭代,云原生架构已经成为互联网行业的技术热门,国内外各大厂都开始推进公司业务朝着云原生的方向进行演变,并在很大程度上推动了 IT 成本的降低和企业的发展。

云原生架构体系简介

云原生是一种技术架构体系和方法论,它包容了容器化、持续交付、 DevOps 和微服务等概念。容器化是微服务的最佳载体,持续交付可频繁快速交付下降低质量风险, DevOps 将发布部署自动化化,微服务则是核心地可被独立部署、更新、 scale 和重启。

CNCF 云原生计算基金会,在 CNCF 全景图中列举了和云原生相关的产品及服务的完整名单,这1381个项目共同构成了恢弘庞大的云原生世界。整个全景图按照功能分为29个模块,分别归属于9种大的类别

  • 应用定义与开发(App Definition and Development)
  • 编排与管理(Orchestration and Management)
  • 运行时(Runtime)
  • 配置(Provsioning)
  • 平台(Platform)
  • 可观察性与分析(Observability and Analysis)
  • 无服务(Serverless)

(原图链接:https://docimg7.docs.qq.com/image/0jAMPR0cyusui7RRN5nDog?w=6880&h=4400)

QB 云原生架构体系

下图为 QB 信息流推荐架构的整体云原生架构体系。DevOps 承载了代码/发布/构建管理、流水线、自动部署、监控、CI/CD、集成测试等能力,测试平台负责压力测试/接口测试/集成测试/故障分析演练等职责,微服务框架通过服务发现/路由、负载均衡、动态配置等功能提供便捷有效而稳定的服务链路能力,云平台管理的 redis 、 mysql 、 mq 、 flink 等数据存储维护了业务的数据统一安全的管理和备份,容器服务基于集群/容器/镜像/存储管理提供无状态可自动调节和平行扩展的能力,使得机器资源的利用率达到极优,而日常的链路排查和部署维护则通过配置/日志管理和监控告警等串联和及时响应。

在技术选型上, QB 信息流推荐架构在编排和管理上选择了北极星和 trpc 框架,基础配置管理上选择了 rainbow 平台,服务部署管理平台选择了123平台,染色监控方面选择了天机阁和007。

DevOps

QB 信息流推荐架构服务迁移至 trpc 框架和123平台。123平台是通用的研发和运营的开放式 DevOps 平台,支持插件式扩展定制业务特性需求。通过123平台可进行自动化服务部署和运维,合理分配服务容器资源配比充分提升资源池利用率,也通过不同服务部署环境(正式/测试等)的隔离,能够稳定安全地进行新版本部署和发布。

在 CI/CD 上,选型了蓝盾流水线严格规范了 git 提交的代码风格/规范/质量/提交日志规范等,并通过编译构建和单测用例通过率/覆盖率严格保障 MR 分支和默认主线分支代码的可用性和稳定性,同时也通过构建流水线统一规范构建和镜像发布,从而保障在频繁持续交付过程中有较高的服务和代码质量。

可观测性和分析

庞大的业务技术架构下,由于容纳的业务服务模块多且繁杂,链路之长,更不乏业务间合作的场景,故而一旦需要去把控服务链路的稳定性或者是追查问题时,缺乏可观测性的手段的情况下将会变得复杂且费时费力。在可观测性的组件上,我们选择的是天机阁。天机阁旨在解决上述的问题和难点:故障定位难、链路梳理难、性能分析难。它通过 Log 、 Trace 、 Metric 三个维度相辅相成地去给予多方位的监控和串联。通过天机阁,我们可快速地染色和排查定位链路问题,也可以进行服务的流量分析和性能分析。

配置管理

服务配置管理平台需要能够做到的是配置同步、版本管理、权限管理等几个要素。基于上述理由,且trpc框架也支持了七彩石插件,故而我们选型的是七彩石 rainbow 作为服务配置的管理平台。

云原生应用

传统应用 VS 云原生应用概述

传统应用和云原生应用有什么区别?主要体现在几个方面:研发模式、架构设计、部署方式、运维方式。在部署、运维方式上,云原生应用都是自动化的。

传统应用

传统应用一般拥有较长的生命周期,并经常被构建成紧密耦合的单体式应用。它们符合定义时制定的的相关规范,但是这些规范制定的时间通常远早于应用的交付时间。业务运营所需的很多基础性应用在设计时都未曾考虑提供数字化体验。

传统应用的开发方案大部分都属于瀑布式和渐进式,不仅时间跨度长,而且直到近期才实现了半敏捷性。应用历经开发、测试、安全合规监管、部署和管理阶段,这些阶段被分隔成了不同的功能领域,每个领域都由不同的团队负责、发挥着不同的作用、肩负着不同的职责,且各方间均通过线性流程来沟通。

对于大多数传统应用来说,基础架构会针对应用所需的峰值容量预先进行置备;还会通过纵向扩展来提高服务器的硬件的相关性能。

云原生应用

由于云原生应用非常注重研发与交付的效率,信息流业务对此也有着迫切的需求。因此,在开发时需要实施更加敏捷且基于服务和 API 的方案和持续交付策略。开发时从针对服务器的眼光转为以容器为中心的模式。开发方案从单一紧密的应用,转变成松散耦合的服务形式,更加强调应用间接口的通信。服务交付周期通常变的更短,需要持续地迭代交付。而这些方案能否成功实施又取决于以下几点:开发和交付团队间的 DevOps 协作;模块化程度更高的架构;能够按需横向扩展、支持多种环境并实现应用可移植性的灵活基础架构。

云原生应用开发范式

既然云原生应用有诸多的好处,那我们在开发云原生应用需要关注那些点呢?以下会从微服务、名字服务、数据管理、配置管理和日志管理五方面进行介绍。

微服务

微服务架构是以一组小型服务的方式来开发一个独立的应用系统,每个服务都以一个独立进程的方式运行,每个服务与其他服务使用轻量级通信机制。这些服务是围绕业务功能构建的,可以通过全自动部署机制独立部署,同时服务会使用最小规模的集中管理能力,也可以采用不同的编程语言和数据库,实现去中心化的服务管理。微服务的关键词:加速交付准备,高度可扩展,出色的弹性,易于部署,易于访问,更加开放。

为什么要切换成微服务的架构设计?信息流传统的推荐架构,是以服务器为核心而搭建的。传统架构中,精排、粗排、展控等模块部署在同一物理机,这样就会面临着可能物理机器挂了,导致相关的系统整个不可用。运维过程针对单机性能不足的情况,只能运维同学手动对单机容量进行调整。微服务强调的是低耦合+高内聚特性。通过将信息流业务的切分成一个个完整、独立的微服务,每个服务可以作为独立组件升级、灰度或复用等,对整个大应用的影响也较小,每个服务可以由专门的组织来单独完成,依赖方只要定好输入和输出口即可完全开发,甚至整个团队的组织架构也会更精简,因此沟通成本低、效率高。

业务实际在迁微服务过程中,遇到的问题和思维的转变:

  • 版本管理以及一份基准代码,多份部署

信息流业务历史存量代码与资源存放于集中式版本控制 svn 上单一路径管理,中央服务器没有做备份的情况下,可能出现数据丢失的情形。为了应对之后迁移微服务和多人协作开发的大势。引入了 git 版本控制工具,提高了并行开发的生产效率。每一个服务共享一份基准代码,但是可以存在多份部署。通常会将服务的不同版本分别部署在123平台提供的不同发布环境,以期测试验证和灰度验证的效果。

  • 编译、发布系统

采用分布式编译系统加速对源码的编译。123服务运营平台支持各个团队自定义各自的编译、运行镜像,满足各种丰富的自定义化需求。同时可以记录编译及发布的相关历史,达到随时可以追溯各个历史版本的效果。

  • 显式声明依赖关系以及依赖管理

将业务中的单体应用切分成了各个微服务。维护服务间编译的依赖关系,保证服务依赖关系清晰就成了重中之重。业务首先将应用,按照功能与模块划分成粒度更为细致的微服务,并且划分到不同 git 仓库管理。在服务松耦合的基础上,引入了模块依赖管理工具,如 bazel 、 maven 、 go modules 等。通过先进的生产力工具,构造更为清晰的依赖关系,也解决了历史应用各种协议版本不一致引发的各种问题。

  • 进程与并发性

开发、运维同学将思维转化为进程模型来设计应用架构。分配任务给不同的进程类型,如服务中的 Web 、 Worker 进程 。考虑将进程设计成无状态,无共享的模式。应用就可以通过复制其进程来扩容。构造无状态应用还让进程可在不同的计算基础架构之间移植。设计思维逐渐向分布式靠拢,这样在整个系统急需水平扩展时,可以添加更多进程解决燃眉之急。

名字服务

服务发现的概念是随着计算机体系结构的发展而演变的概念。网络时代初期,不同的计算机需要相互定位,这是通过一个全球文本文件 HOSTS.TXT 完成的。因为不经常添加新主机,所以手动维护文件的地址列表。随着互联网的发展,主机的增加速度越来越快,需要一个自动化,可扩展性的更强系统,从而导致了 DNS 的发明和广泛采用。

服务发现一般是由三个模块组成,主控、客户端、服务端,其中服务端会把当前的结点信息注册到主控,当客户端需要调用服务端时,则从主控获取到服务端的结点信息或者从已经缓存的数据中拿到服务端的信息,然后进行调用,其关系如下图所示:

现在,微服务架构正在推动服务发现的不断发展。随着容器化平台或云平台的不断普及,基于平台的微服务架构部署,服务的生命周期以秒和分钟来衡量。同时,因为微服务的自动扩展、故障和发布升级,导致微服务具有动态变化的地址列表,微服务的灵活性再次推动了服务发现技术的发展。现在基于容器化平台或云平台的微服务应用程序,需要解决服务地址动态变化的问题。腾讯内部也提供了众多优秀的平台和组件以供选择,如 cl5 / l5 /北极星( Polaris )等。以下是传统应用和云原生引用在名字服务上的异同:

业务实际在切换名字服务过程中,遇到的问题和思维的转变:

  • 端口绑定

在非云环境中,通常将 Web 应用编写为在应用容器中运行。相比之下,云原生应用不依赖于外部应用容器。相反,它们会将 Web 服务器库打包为应用本身的一部分。互联网应用可以通过端口绑定来提供服务并随时监听所有发送至该端口的请求。123平台上接入的服务,会自动对接北极星名字服务。123平台中的每一个服务,都会被北极星通过该服务名可以解析出具体的实例(代表一个 ip port 以及相关配置信息)。在服务下线或者变更时,采用名字服务的方式,往往能减少很多人力成本。

数据管理

互联网业务也包括信息流业务,因为数据的量级以及对存取速度要求的不同,免不了使用各式各样的存储系统。随着云原生的推广,传统的数据管理方式也在逐步向云存储转变。以常见的 NoSql 组件 redis ,以及关系型数据库 mysql 为例,也经历了单机本地存储,集群存储以及上云的变迁。

相对于传统数据管理方式,云原生数据管理有以下几个特点:

  • 分布式

用户的存储分布在多台机器上,彻底摆脱单机容量和资源限制。

  • 高可用性

每个实例均提供主从热备,宕机自动监测,自动容灾。

  • 高可靠性

数据持久化存储,可提供冷备和自助回档。

  • 弹性扩容

集群版存储往往支持单实例无上限扩容。在扩容过程中不中断服务,真正做到用户无感知。

  • 完善的监控

能提供完整的运营系统,主要包括实时流量、特性的监控以及告警。实时监控各项组件指标,针对阈值配置告警。

以下是分布式存储的监控图

配置管理

信息流业务的推荐系统被划分为成千上万个微服务模块,其中每个服务在123运营平台上又被部署到多个环境中。传统文件配置管理的方式,存在着比较大的局限性,云原生的配置管理系统应运而生。

业务实际在切换配置管理系统过程中,遇到的问题和思维的转变:

  • 在环境中存储配置

信息流业务使用七彩石 rainbow 系统作为配置管理核心系统。在123平台中,七彩石以插件化的形式存在。业务的配置在不同环境下(如预发布、正式环境)还是有差距的,七彩石以及123平台可以针对环境做不同隔离,可以满足业务的需求。

  • 环境等价

不同环境的配置会存在差异,而应用要想做到持续部署,保证系统稳定,就得做到配置文件间差异尽可能少。从信息流业务自身出发,通过引入 DevOps ,缩短部署上线的时间,做到尽可能由开发的同学来修改配置文件,这样的举措是值得的。

日志管理

传统的日志管理形式,日志以存储在 Web Server 本地文件形式而存在,单机存储日志文件存在单机容量的局限。业务开发及运维同学,需要分析数据时,往往只能登录到特定机器才能看到特定的日志。不能总览事件触发的链路,及其他相关模块的日志。

在云原生的日志管理流程下,服务的日志应该是事件流的汇总。日志采集系统将所有运行中进程和后端服务的输出流按照时间顺序收集起来。日志是以流水的形式追加到所属的日志文件后,开发及运维可以实时在终端跟踪标准输出流的情况。再辅以日志采集跟踪组件,即可完整地追踪事件发生流程相关模块产生的染色日志。信息流业务目前是通过鹰眼日志系统,来分析业务生命周期中的各种可能遇到的问题。

业务实际在切换日志系统过程中,遇到的问题和思维的转变:

  • 集中式远程日志中心
  • 集中收集,统一管理
  • 方便快捷的日志分析能力

资源利用率优化

业务使用了 Docker 、 K8s 等技术后,从理论上来说可以有效地提升资源利用率,但在复杂的业务架构下,微服务数量膨胀,大部分业务应用还是存在资源利用率低的问题,究其原因主要是工具平台不够完善、业务的独有资源使用方式不同,那如何提升资源的利用率是云原生架构体系的一个重要命题。

资源浪费场景

考虑到资源浪费,首先我们来分析下业务中常见的资源使用方式,从这些场景中可以找到一些优化的方向。

索取大于使用

业务应用在实际的使用过程中,存在资源预留大量浪费的问题,比如服务实际运行需要1核 CPU ,服务负责人对应用使用的内存没有估算到位,为了让应用能稳定地运行,服务负责人会申请过多资源,比如4核 CPU ,避免后面服务在运行的过程中出现问题。这势必会造成较大的资源浪费。如下图所示,CPU 使用率只有1%-1.5%左右。

波峰波谷现象

大多数业务存在波峰波谷现象,比如我们的业务中,中午饭后、晚上睡前的时间段存在一个波峰,这段时间用户有跟多的空闲时间来消费信息流。而凌晨时间用户在休息,则出现了波谷。如下图所示,晚上10-11点左右出现了一个波峰。

应用资源使用差异

不同的业务应用在不同的时段使用的资源存在较大的差异,在信息流业务中较为明显,在线业务白天负载较高,对时延也要求较高,而离线计算业务在凌晨负载较高,对时延要求相对较低。

优化方案

针对以上提到的资源浪费场景,我们可以采用手动、自动的方式进行资源利用率调优,比如针对索取大于使用的场景可以采用手动的方式进行调优,把多申请的资源重新按照真实的使用情况进行缩容,但这种操作方式很大程度上依赖开发的能力和意愿,在实际的操作过程中难以落地,所以需要采用自动的方式进行优化,尽可能少地依赖开发者。自动的方式有以下几种:

  • 根据 HPA 、 CA 等参数弹性伸缩
  • 调度, K8s 提供资源分配机制,自动找到合适的节点
  • 在线、离线业务混合部署

这些自动的能力在TKE上都支持,详细操作可以查阅TKE的相关文档。

监控

虽然自动的扩容、缩容能力能有效地调度资源,使得资源的利用率有所提升,但对于整个业务的资源使用情况还需要有相应的监控,以下是我们业务部分的监控模块,通过这些监控数据可以快速找出优化的方向。

  • 整体资源概况
  • 业务应用扩缩容阈值
  • 模块资源利用率排行榜

后记

云原生架构体系是一个庞大的技术体系,在各个技术方向上都有相关研究或成熟组件,公司也有 Oteam 在相关领域进行共建,作为业务更多的是需要借助平台、 Oteam 的能力进行整合,站在巨人的肩膀上才能飞得更高。最后感谢公司在云原生各个技术领域上做出贡献的团队和个人。

参考文档

云原生应用之路:https://www.sohu.com/a/211846555_617676

12-factors:https://12factor.net/zh_cn/

  往期精选推荐  

  • Addon SuperEdge 让原生 K8s 集群可管理边缘应用和节点
  • SuperEdge 云边隧道新特性:从云端SSH运维边缘节点
  • 如何削减 50% 机器预算?“人机对抗”探索云端之路
  • 白话边缘计算解决方案 SuperEdge
  • 原创干货合集 | 大数据云原生技术实战及最佳实践系列