IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

腾讯分析系统架构解析

标点符 2013-05-29 22:20:56 累计浏览 7,767 次
本机暂存

   TA(Tencent Analytics,腾讯分析)是一款面向第三方站长的免费网站分析系统,在数据稳定性、及时性方面广受站长好评,其秒级的实时数据更新频率也获得业界的认可。本文将从实时数据处理、数据存储等多个方面带你深入探寻TA的系统架构及实现原理。

   网站分析(Web Analytics)主要指的是基于网站的用户浏览行为,对网站的点击流数据和运营数据进行分析,以监控网站的运营状况,为网站的优化提供决策依据。网站分析系统已成为站长日常运营必不可少的工具,业界比较流行的网站分析系统主要有Google Analytics、CNZZ和百度统计等产品。

   TA作为网站分析产品的后起之秀在社区分析、用户画像、网站工具等多方面形成了自己的特色,其秒级的实时数据更新频率更是业界翘楚。在数据稳定性、准确性和及时性方面,TA在站长圈也是享有良好的口碑。随着接入业务量的不断发展,TA日均需要处理和计算的数据量达到TB级。如此庞大的数据量想要达到秒级实时且保证系统的高可用并非件易事。

   TA的实时计算框架借鉴了一些业界流行的流式计算系统的思路。虽然在构建系统中遇到了一些问题,但由于海量数据的实时处理、实时存储具备一定的典型性与通用性,所以将TA的解决方案分享出来,希望能给大家一些启示。

   基本原理及系统架构

   TA的基本原理是通过嵌入站长网站的JavaScript脚本收集用户访问行为数据,并发送TA采集集群,采集集群收到数据后将其过滤、编码、格式化后继续向后分发。数据处理集群负责按照业务逻辑计算数据,并将计算结果“写入”到数据存储集群,最后将结果数据展现给广大站长使用。TA的基本原理如图所示。

   ta-theory

   TA后台是一套完整的数据流处理系统:由JavaScript采集的用户行为数据像川流不息的河水一样流入TA后台,经过清洗、计算后源源不断地流出到TA存储集群,供用户浏览和查询。TA的具体架构及核心部件如图所示。

   ta-architecture

   TA的后台分为离线和实时两部分:实时部分负责系统的主要功能计算,数据更新频率为秒级;离线部分负责系统复杂的关联分析及跨天计算,数据更新频率为天级。

  • Http Access:主要负责HTTP协议的解析,数据的清洗及格式化。

  • ESC:Event Streaming Coder,主要负责将系统不可枚举的数据类型编码成为整型,并将对应关系持久化。

  • ESP:Event Streaming Processor,主要负责将数据按照站点、UID重新组织并计算PV、UV、停留时长和蹦失率等网站分析指标。

  • ESA:Event Streaming Aggregator,主要负责汇总ESP计算后的数据按照站点,并写入到Redis。

  • Center:系统的中心节点,负责系统配置、数据路由管理,并承担容灾切换功能。

  • Logserver:负责将Access收集到的数据以字符串形式写入文件,并上传到TDCP上。

  • TDCP:腾讯分布式计算平台,负责离线数据的计算,并由脚本将结果数据写入MySQL中。

  •    实时解决方案

       在介绍TA实时解决方案前,我们先来了解下TA支撑的业务量。当前TA日均需要处理几十万网站的上TB级数据,处理过后的URL个数仍有上亿条,系统存储的key个数超过十亿。如何高效、低延迟地处理如此大量的业务数据是TA实时系统面临的主要挑战。TA解决方案的主要思路可以概括为数据全二进制化、计算全内存化、存储NoSQL化。下面就实时计算和实时存储这两大子系统进行深入的讨论。

       实时计算

       对于计算子系统,我们参考了Hadoop、S4和Storm等开源项目,力图设计为一个较为通用,扩展性较强的全内存实时Event处理系统(或者套用流行的术语称为流式实时Event处理系统)。对于这样的一个系统,我们设计支持的典型输入输出流程大致如图所示。

       esp

       实时计算系统的设计要点在数据组织、协议和增量计算模型上。

       数据组织。万物皆int,考虑到内存以及计算过程的性能需求,我们将所有非int的数据类型转化为int。可以枚举的数据类型,将其配置化映射为唯一int;不可枚举的数据类型,则利用MD5算法近似得到唯一的int。例如,页面URL属于不可枚举的类型,则预处理通过MD5算法近似得到唯一的int;UserAgent里的浏览器类型字符串则属于可枚举的数据,则预先配置化映射为int。这个方法节省了较多内存,提高了整个系统的计算性能。

       协议。协议层面上,我们首先设计实现了一种可扩展的Event结构,这种Event结构支持半自动化的序列化/反序列化机制(参考自msgpack的设计)和紧凑的二进制编码(基于Zigzag编码,参考Protobuf的实现)。这种Event结构在流式高性能I/O(网络传输和持久化)方面表现得相当良好。实时计算子系统被设计为可以扩展支持任意的Event实现。

       增量计算模型。增量计算模型,指的是基本计算过程,被定义为以下三部分(如图所示)

       esp-2

  • Processor:负责具体业务逻辑的计算处理。

  • Data Holder:负责保存增量结果数据,以及计算依赖的中间状态数据。

  • Emitter:负责定期输出清空增量计算结果。

  •    具体到流程方面,分为以下三步(如图所示)。

       esp-3

  • 接收Event,计算处理—Processor。

  • 保存计算结果以及计算依赖中间数据—DataHolder。

  • 定时触发输出时间片内计算结果,清空计算结果—Emitter。

  •    增量计算模型弱化了分布式系统中单台机器的事务状态,相应地简化了分布式计算系统的实现,同时也提高了整个系统的性能。

       实时存储

       在TA系统中,实时存储的数据都是需要通过Web展示层读取的统计数据。这类数据存在两个典型特点。

  • 频繁更新写。更新频度视系统实时性而定,每条统计结果更新频度最快可以达到1秒。

  • 少量读取。“少量”是相对上述更新而言的。同时根据业务逻辑,可将统计数据划分为两类。

  • 固定不变数据:主要是URL、搜索关键词等数据。这一部分数据理论上是在不停地增加,不会修改旧有数据。

  • 动态数据:主要是频繁更新的结果统计数据。这一部分数据则需要不停地更新。例如,www.qq.com域名下的PV和UV统计结果。

  •    考虑到上述的TA实时统计数据的特点,我们选择NoSQL实现我们的存储系统;同时,针对两类不同的数据类型,分别选用LevelDB和Redis来存储。

       Redis

       TA实时存储的主要构件。考虑到TA系统本身就是一个比较完善的分布式集群系统,因此我们需要的存储构件是“not clustering, but sharding”。也就是说像HBase和MongoDB这样的“重武器”并不适合TA,而NoSQL数据库中的“瑞士军刀”Redis凭借其出色的性能走入我们的视野。同

       时TA的结果数据类型也比较丰富,有像站点PV、UV、VV和IP等Hash类型的数据,也有像用户访问轨迹这样set类型的“动态数据”,而Redis丰富的数据结构很好地完成了这项任务。

       选择Redis的另一个原因是它足够简单且易于扩展。在实际应用的过程中,我们发现的问题都可以通过扩展Redis命令来解决。

       例如,TA中有这样的一种应用场景:为了消除ESA模块的状态,存储在Redis中的数据往往并不是最终的结果数据,而是还需要进一步运算的中间数据。像bounce rate这个指标(bouncerate=bounce session数/total session数),需要前台查询两次再做一次运算后最终展示给用户。在高并发的情况下,无疑会影响系统的响应速度。

       本着“移动计算,而不是移动数据”的原则,我们对Redis的sort、hmget命令进行了扩展使其支持四则运算,成功地将原来的两次查询优化为一次。扩展四则运算的另外一个目的是可以“通过计算换取存储”,例如需要将两种类型加总成总和的类型数据,可以只存储两份,加总数据“通过计算换取”。

       除了数据读取,数据的写入也可以进行类似合并数据的优化。例如,TA在写入URL的PV、UV、VV、IP、停留时长和bounce rate这6个指标时,需要调用6次Redis命令。而实际上这6个指标是存储在同一个Hash内的,通过扩展hmincrby命令,支持将Hash的所有field一次更改,便能将调用次数优化至一次。上线之后也取得了良好的效果,峰值时的CPU利用率几乎下降了一半,同时也大幅提升了上层模块ESA的吞吐量。

       LevelDB

       它是Redis的有效补充。考虑到Redis为内存数据库,而使用内存的成本要高于硬盘,因此选择引入了基于磁盘存储的LevelDB作为补充。由于LevelDB的写性能足够好,而读性能也远远超过目前“在线少量读取”的需求,所以我们选择LevelDB存储“固定不变数据”。

       在数据存储的架构设计上,由于实时数据服务与在线系统,可靠性要求较高,因此我们主要采取双写复制+Sharding的设计方法。

       双写复制。所有的数据存储都会至少同步写两份,以提高在线系统服务的可用性。

       数据分片(Sharding)。

       基于域名:所有的数据以域名为单位组织分片;任何域名可以调整到任意分片中;单个域名数据原则上存储在一个分片中。

       动态调整(如图所示):只调整分片策略,不移动数据;基于数据量计算分片负载。

       sharding

       此外,针对分片集群数据的查询,我们主要做了三项工作(如图所示)。

       sharding-2

  • Redis Protocol Stack是一个较为完整的Redis协议栈,是上层应用的基础。直接用Redis协议作为对外提供查询的通用协议,这样外部用户可直接通过目前各种Redis Client实现来查询访问数据。Query Rule Engine是一个灵活的查询引擎。能够根据规则智能地在多个Redis、LevelDB数据源中查询,执行类join的操作;也简单扩展支持其他的异构数据源,如MySQL、HBase等。

  • Query Compute Engine是一个实时查询计算引擎,能根据基础查询结果实时计算。引入此部分的主要目的在于减少Redis数据空间占用。

  •    未来展望

       目前TA虽然在后台上已经做到数据秒级更新,但展示方式仍为传统的静态方式。后续TA会在数据的动态刷新上进行更多尝试,让站长可以第一时间了解网站营销效果,时刻感受网站心跳。

       作者介绍

  • 楚大鹏 腾讯数据平台部高级工程师,腾讯分析技术负责人,在网站分析、流式数据处理、海量数据挖掘等领域方面经验丰富。

  • 王琦英 腾讯数据平台部高级工程师,负责腾讯分析的架构设计及开发,有丰富的高并发、高性能后台系统设计、架构经验。

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. WordPress插件开发 -- 在插件使用数据库存储数据 (累计阅读 29,162)
  2. 技术人员的未来:做技术还是做管理? (累计阅读 8,871)
  3. 系统架构的一些思考 (累计阅读 6,791)
  4. 大数据下的工行 (累计阅读 6,639)
  5. 什么是二维码?有什么用? (累计阅读 5,888)
  6. 在perl中连接和使用sqlite做数据存储 (累计阅读 5,807)
  7. ORACLE最大可以存储多少数据量 (累计阅读 5,726)
  8. 数据库的堆表与索引组织表的数据存储格式讨论 (累计阅读 5,596)
  9. Memcache源代码分析之数据存储 (累计阅读 4,981)
  10. 杨建:网站加速--服务器编写篇 (下) (累计阅读 4,207)