数据存储单位

# 数据存储单位

1. 计算机的最小存储单位是 bit

  • 位 bit(比特)(Binary Digits):存放一位二进制数,即 0 或 1,是最小的存储单位。

2. 计算机存储容量的基本单位是字节

  • 字节 byte:8 个二进制位(bit)为一个字节(B),是最常用的单位。(我们常常会说一个字节占 8 位)

  • 一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。

  • 英文标点占一个字节,中文标点占两个字节。比如:英文句号 “.” 占 1 个字节的大小,中文句号 “。” 占 2 个字节大小。

3. 存储单位的换算关系

  • 1 B(Byte 字节) = 8 bit

  • 1 KB (Kilobyte 千字节) = 1024 B

  • 1 MB (Megabyte 兆字节,简称 “兆”) = 1024 KB

  • 1 GB (Gigabyte 吉字节,又称 “千兆”) = 1024 MB

  • 1 TB (Trillionbyte 太字节,万亿字节) = 1024 GB

  • 1 PB (Petabyte 拍字节,千万亿字节) = 1024 TB

  • 1 EB (Exabyte 艾字节,百亿亿字节) = 1024 PB

  • 1 ZB (Zettabyte 泽字节,十万亿亿字节) = 1024 EB

  • 1 YB (Yottabyte 尧字节,一亿亿亿字节) = 1024 ZB

  • 1 BB (Brontobyte 珀字节,一千亿亿亿字节) = 1024 YB

  • 1 NB (NonaByte 诺字节) = 1024 BB

  • 1 DB (DoggaByte 刀字节) = 1024 NB

# 阿里巴巴大数据系统体系

数据体系主要分为数据采集数据计算数据服务数据应用四大层次。

# 数据采集层

  • 数据采集分日志采集和数据同步两部分。

  • 阿里巴巴的日志采集体系方案包括两大体系:

    • Aplus.JS 是 Web 端日志采集技术方案;

    • UserTrack 是 APP 端日志采集技术方案。

  • 在传输方面,采用 TimeTunnel(TT),它既包括数据库的增量数据传输,也包括日志数据的传输;TT 作为数据传输服务的基础架构,既支持实时流式计算,也支持各种时间窗口的批量计算。

  • 通过数据同步工具(DataX 和同步中心,其中同步中心是基于 DataX 易用性封装的)直连异构数据库(备库)来抽取各种时间窗口的数据。

# 数据计算层

  • 数据只有被整合和计算,才能被用于洞察商业规律,挖掘潜在信息,从而实现大数据价值,达到赋能于商业和创造价值的目的。从采集系统中收集到的大量原始数据,将进入数据计算层中被进一步整合与计算。

  • 阿里巴巴的数据计算层包括两大体系:

    • 数据存储及计算云平台离线计算平台 MaxCompute实时计算平台 StreamCompute

      • MaxCompute 是阿里巴巴自主研发的离线大数据平台,其丰富的功能和强大的存储及计算能力使得阿里巴巴的大数据有了强大的存储和计算引擎。

      • StreamCompute 是阿里巴巴自主研发的流式大数据平台,在内部较好地支持了阿里巴巴流式计算需求。

    • 数据整合及管理体系(内部称之为 “OneData”)

      • OneData 是数据整合及管理的方法体系和工具。
  • 阿里巴巴的大数据工程师在这一体系下,构建统一、规范、可共享的全域数据体系,避免数据的冗余和重复建设,规避数据烟囱和不一致性,充分发挥阿里巴巴在大数据海量、多样性方面的独特优势。借助这一统一化数据整合及管理的方法体系,我们构建了阿里巴巴的数据公共层,并可以帮助相似大数据项目快速落地实现。

  • 数据计算频率角度来看,阿里数据仓库可以分为离线数据仓库实时数据仓库。离线数据仓库主要是指传统的数据仓库概念,数据计算频率主要以天(包含小时、周和月)为单位;如 T - 1 ,则每天凌晨处理上一天的数据。而 “双 11” 实时数据直播大屏,就是实时数据仓库的一种典型应用。

  • 阿里数据仓库的数据加工链路也是遵循业界的分层理念,包括操作数据层(Operational Data Store, ODS)、明细数据层(Data Warehouse Detail, DWD)、汇总数据层(Data Warehouse Summary, DWS)和应用数据层(Application Data Store, ADS)。通过数据仓库不同层次之间的加工过程实现从数据资产向信息资产的转化,并且对整个过程进行有效的元数据管理及数据质量处理

  • 在阿里大数据系统中,元数据模型整合及应用是一个重要的组成部分,主要包含数据源元数据、数据仓库元数据、数据链路元数据、工具类元数据、数据质量类元数据等。元数据应用主要面向数据发现、数据管理等,如用于存储、计算和成本管理等。

# 数据服务层

  • 当数据已被整合和计算好之后,需要提供给产品和应用进行数据消费

  • 为了有更好的性能和体验,阿里巴巴构建了自己的数据服务层,通过接口服务化方式对外提供数据服务

  • 针对不同的需求,数据服务层的数据源架构在多种数据库之上,如 MySQL 和 HBase 等。后续将逐渐迁移至阿里云云数据库 ApsaraDB for RDS(简称 “RDS”)和表格存储(Table Store)等。

  • 数据服务层对外提供数据服务主要是通过统一的数据服务平台(简称为 “OneService”)。One Service 以数据仓库整合计算好的数据作为数据源,对外通过接口的方式提供数据服务,主要提供简单数据查询服务复杂数据查询服务(承接集团用户识别、用户画像等复杂数据查询服务)和实时数据推送服务三大特色数据服务。

# 数据应用层

  • 数据已经准备好,需要通过合适的应用提供给用户,让数据最大化地发挥价值。商家,阿里内部的搜索、推荐、广告、金融等平台,阿里内部的运营和管理人员等,都是数据应用方;ISV、研究机构和社会组织等也可以利用阿里开放的数据能力和技术。

  • 阿里巴巴基于数据的应用产品有很多,比如服务于阿里内部员工的阿里数据平台和服务于商家的对外数据产品 —— 生意参谋

  • 对内,阿里数据平台产品主要有实时数据监控、自助式的数据网站或产品构建的数据小站、宏观决策分析支撑平台、对象分析工具、行业数据分析门户、流量分析平台等。

  • 数据已经成为一项新能源。

# 日志采集

# 浏览器的页面日志采集

浏览器的页面型产品/服务的日志采集可分为如下两大类。

  • 页面浏览(展现)日志采集。顾名思义,页面浏览日志是指当一个页面被浏览器加载呈现时采集的日志。此类日志是最基础的互联网日志,也是目前所有互联网产品的两大基本指标:页面浏览量(PageView, PV)访客数(Unique Visitors, UV)的统计基础。页面浏览日志是目前成熟度和完备度最高,同时也是最具挑战性的日志来集任务。

  • 页面交互日志采集。当页面加载和渲染完成之后,用户可以在页面上执行各类操作。随着互联网前端技术的不断发展,用户可在浏览器内与网页进行的互动已经丰富到只有想不到没有做不到的程度,互动设计都要求采集用户的互动行为数据,以便通过量化获知用户的兴趣点或者体验优化点。交互日志采集就是为此类业务场景而生的。

此外,还有一些专门针对某些特定统计场合的日志采集需求,如专门采集特定媒体在页面被曝光状态的曝光日志、用户在线状态的实时监测等,但在基本原理上都脱胎于上述两大类。

# 页面浏览日志采集流程

目前典型的网页访问过程是以浏览器请求、服务器响应并返回所请求的内容(大多以 HTML 文档的形式)这种模式进行的,浏览器和服务器之间的通信普遍遵守 HTTP 协议。浏览器发起的请求被称为 HTTP 请求(HTTP Request),服务器的返回则被称为 HTTP 响应(HTTP Response)。

在这个访问过程中,采集日志的动作只能在浏览器开始解析文档时才能进行。

在这一模式下最直接的日志采集思路如下:

在 HTML 文档内的适当位置增加一个日志采集节点,当浏览器解析到这个节点时,将自动触发一个特定的 HTTP 请求到日志采集服务器。如此一来,当日志采集服务器接收到这个请求时,就可以确定浏览器已经成功地接收和打开了页面。

这就是目前几乎所有互联网网站页面浏览日志采集的基本原理,而业界的各类网页日志采集的解决方案只是在实施的细节、自动采集内容的广度以及部署的便利性上有所不同。

# 阿里巴巴的页面浏览日志采集方案

阿里巴巴采用的页面浏览日志采集方案的流程框架如下:

📌 1. 客户端日志采集

日志采集工作一般由一小段被植人页面 HTML 文档内的 JavaScript 脚本来执行。采集脚本被浏览器加载解析后执行,在执行时采集当前页面参数、浏览行为的上下文信息(如读取用户访问当前页面时的上一步页面)以及一些运行环境信息(如当前的浏览器和分辨率等)

在 HTML 文档内植入日志采集脚本的动作可以由业务服务器在响应业务请求时动态执行,也可以在开发页面时由开发人员手动植人。在阿里巴巴,这两种方式均有采用,其中前一种方式的占比较高,这一点与业界的普遍状况有所不同。上图中的第三、四步描述了阿里业务服务器端植入日志采集脚本的过程。

📌 2. 客户端日志发送

采集脚本执行时,会向日志服务器发起一个日志请求,以将采集到的数据发送到日志服务器。在大多数情况下,采集完成之后会立即执行发送;但在个别场景下,日志采集之后可能会经过一段时间的延迟才被发出。

日志采集和发送模块一般会集成在同一个 JavaScript 脚本文件内,且通过互联网浏览器必然支持的 HTTP 协议与日志服务器通信,采集到的日志信息一般以 URL 参数形式放在 HTTP 日志请求的请求行内

📌 3. 服务端日志收集

日志服务器接收到客户端发来的日志请求后,一般会立即向浏览器发回一个请求成功的响应,以免对页面的正常加载造成影响;同时,日志服务器的日志收集模块会将日志请求内容写入一个日志缓冲区内,完成此条浏览日志的收集

📌 4. 服务器端日志解析存档

服务器接收到的浏览日志进入缓冲区后,会被一段专门的日志处理程序顺序读出并按照约定的日志处理逻辑解析。由日志采集脚本记录在日志请求行内的参数,将在这个环节被解析(有时候伴随着转义和解码)出来,转存人标准的日志文件中并注入实时消息通道内供其他后端程序读取和进一步加工处理。

经过采集 一> 发送 一>收集一>解析存档四个步骤,我们将一次页面浏览日志成功地记录下来。可见,除了采集代码在某些场合下需要手动植入之外,整个过程基本都是依照 HTML 规范和 HTTP 协议自动进行的,这种依赖协议和规范自动运行的采集机制最大限度地减少了人工干预的扰动,进而保证了日志的准确性。

阿里巴巴的页面浏览日志采集框架,不仅指定了上述的采集技术方案,同时也规定了 PV 日志的采集标准规范,其中规定了 PV 日志应采集和可采集的数据项,并对数据格式做了规定。这些格式化日志,为后续的日志加工和计算得以顺利开展打下了基础。

# 页面交互日志采集

  • PV 日志的采集解决了页面流量和流量来源统计的问题

  • 因为终端类型、页面内容、交互方式和用户实际行为的千变万化不可预估,交互日志的采集和 PV 日志的采集不同,无法规定统一的采集内容,呈现出高度自定义的业务特征。

  • 在阿里巴巴,通过一套名为 “黄金令箭” 的采集方案来解决交互日志的采集问题,“黄金令箭” 是一个开放的基于 HTTP 协议的日志服务。采集流程如下:

    • (1)业务方在 “黄金令箭” 的元数据管理界面依次注册需要采集交互日志的业务、具体的业务场景以及场景下的具体交互采集点,在注册完成之后,系统将生成与之对应的交互日志来集代码模板。

    • (2)业务方将交互日志采集代码植入目标页面,并将采集代码与需要监测的交互行为做绑定。

    • (3)当用户在页面上产生指定行为时,采集代码和正常的业务互动响应代码一起被触发和执行。

    • (4)采集代码在采集动作完成后将对应的日志通过 HTTP 协议发送到日志服务器,日志服务器接收到日志后,对于保存在 HTTP 请求参数部分的自定义数据,即用户上传的数据,原则上不做解析处理,只做简单的转储。

经过上述步骤采集到日志服务器的业务随后可被业务方按需自行解析处理,并可与正常的 PV 日志做关联运算。

# 页面日志的服务器端清洗和预处理

在大部分场合下,经过上述解析处理之后的日志并不直接提供给下游使用。基于如下几个原因,在对时效要求较宽松的应用场合下,一般还需要进行相应的离线预处理。

  • 识别流量攻击、网络爬虫和流量作弊(虚假流量)。页面日志是互联网分析和大数据应用的基础源数据,在实际应用中,往往存在占一定比例的虚假或者恶意流量日志,导致日志相关指标的统计发生偏差或明显谬误。为此,需要对所采集的日志进行合法性校验,依托算法识 别非正常的流量并归纳出对应的过滤规则集加以滤除。这是一个长期而艰苦的对抗过程。

  • 数据缺项补正。为了便利后续的日志应用和保证基本的数据统计口径一致,在大多数情况下,需要对日志中的一些公用且重要的数据项做取值归一、标准化处理或反向补正。反向补正,即根据新日志对稍早收集的日志中的个别数据项做回补或修订(例如,在用户登录后,对登录前页面日志做身份信息的回补)。

  • 无效数据剔除。在某些情况下,因业务变更或配置不当,在采集到的日志中会存在一些无意义、已经失效或者冗余的数据项。这些数据项不仅消耗存储空间和运算能力,而且在偶然的情况下还可能干扰正常计算的进行。为了避免此类异常的发生,需要定时检查配置并依照配 置将此类数据项剔除。

  • 日志隔离分发。基于数据安全或者业务特性的考虑,某些日志在进入公共数据环境之前需要做隔离。

原始日志经过上述的清洗、修正,并结构化变形处理之后, Web 页面日志的采集流程就算完成了。此时的日志已经具备了结构化或者半结构化的特征,可以方便地被关系型数据库装载和使用。

# 无线客户端的日志采集

  1. 移动端的数据采集有以下两个目的:
  • 一是为了服务于开发者,协助开发者分析各类设备信息

  • 二是为了帮助各 APP 更好地了解自己的用户,了解用户在 APP 上的各类行为,帮助各应用不断进行优化,提升用户体验

  1. 无线客户端的日志采集采用采集 SDK 来完成,在阿里巴巴内部,多使用名为 UserTrack 的 SDK 来进行无线客户端的日志采集。

  2. 无线客户端的日志采集和浏览器的日志采集方式的区别:

  • 移动端的日志采集根据不同的用户行为分成不同的事件,“事件” 为无线客户端日志行为的最小单位。
  1. 基于常规的分析, UserTrack(UT)把事件分成了几类,常用的包括页面事件(同前述的页面浏览)和控件点击事件(同前述的 页面交互)等。

  2. 对事件进行分类的原因,除了不同事件的日志触发时机、日志内容和实现方式有差异之外,另一方面是为了更好地完成数据分析。在常见的业务分析中,往往较多地涉及某类事件,而非全部事件;故为了降低后续处理的复杂性,对事件进行分类尤为重要。

# 页面事件

  1. 每条页面事件日志记录三类信息:
  • 设备及用户的基本信息;

  • 被访问页面的信息,这里主要是一些业务参数(如商品详情页的商品 ID、所属的店铺等);

  • 访问基本路径(如页面来源、来源的来源等),用于还原用户完整的访问行为。

  1. UT 提供了页面事件的无痕埋点,即无须开发者进行任何编码即可实现。对于手动模式的埋点,UT 提供了两个接口,分别在页面展现和页面退出时调用。
  • 以进入手机淘宝的某店铺详情页来举例,当进入该店铺详情页时,调用页面展现的接口,该接口会记录页面进人时的一些状态信息,但此时不发送日志;当从该店铺详情页离开时(可能是在店铺详情页上点击某个商品到了对应的商品详情页,也可能是退出了手机淘宝,抑或是点击返回,返回到了之前的一个页面),调用页面退出的接口,该接口会发送日志。除了基础的两个接口外,还提供了添加页面扩展信息的接口;在页面离开前,使用该接口提供的方法给页面添加相关参数,比如给店铺详情页添加店铺 ID、店铺类别(天猫店铺或淘宝店铺)等。
  1. 为什么不在页面进人时就发送日志,而是在页面离开时才发送日志呢?
  • 基于浏览器的日志采集,在每次页面进人时就实现采集日志的发送,每个页面停留时长的计算一直困扰着分析师;而无线客户端的日志采集,在页面离开时发送日志,此时页面停留时长就是天然自带的准确值了
  1. 为了平衡采集、计算和分析的成本,在部分场景下我们选择采集更多的信息来减少计算及分析的成本。因此,UT 还提供了透传参数功能所谓透传参数,即把当前页面的某些信息,传递到下一个页面甚至下下一个页面的日志中。在阿里系内,使用 SPM(Super Position Model ,超级位置模型)进行来源去向的追踪,在无线客户端也同样使用 SPM, SPM 信息就可以通过透传机制带人到下一步甚至下下一步的浏览页面,这样整个用户行为路径还原就轻松实现了。

# 控件点击及其他事件

  1. 在阿里巴巴的无线客户端日志采集实践中,将交互日志采集从页面事件采集中剥离出来,这就是控件点击事件和其他事件

  2. 控件点击事件比页面事件要简单得多,首先,它和页面事件一样,记录了基本的设备信息、用户信息;其次,它记录了控件所在页面名称、控件名称、控件的业务参数等。由于控件点击事件的逻辑简单得多,就是操作页面上的某个控件,因此只需把相关基础信息告诉采集 SDK 即可。

  3. 所谓其他事件,就是用户可以根据业务场景需求,使用自定义事件来采集相关信息。UT 提供了一个自定义埋点类,其包括:事件名称、事件时长、事件所携带的属性、事件对应的页面。当然,具体实现什么功能,需要带哪些内容,各个采集 SDK 可以自行决定。

  4. 除了上述这些需要应用开发者触发的日志采集接口方法外,UT 还提供了一些默认的日志采集方法,比如可以自动捕获应用崩溃,并且产生一条日志记录崩溃相关信息。类似的日志采集方法还有很多,比如应用的退出、页面的前后台切换等。诸如一些和业务信息不是非常相关,但又对分析起很大作用的日志采集,就完全没有必要让应用开发者去触发埋点了。

# 无线客户端日志采集的特殊场景

  1. 普通的业务场景是一个行为产生一条日志,如一次浏览、一次点击等,上述的技术方案支持是足够的。

  2. 但对于阿里巴巴巨大的业务体量来说,为了平衡日志大小,减小流量消耗、采集服务器压力、网络传输压力等,采集 SDK 提供了聚合功能,对某些场景如曝光或一些性能技术类日志,我们提倡在客户端对这类日志进行适当聚合,以减少对日志采集服务器端的请求,适当减小日志大小。总体思路就是每个曝光的元素一般都属于一个页面,利用页面的生命周期来实现适当的聚合及确定发送时机。

  3. 对于一些只需要计数,而不需要知道具体内容的场景,如需要分析某些接口的调用次数,客户端聚合功能就更加凸显出其作用了。

  4. 区别于浏览器的页面访问,在无线客户端用户的访问行为路径存在明显的回退行为(如点击回退按钮、各种滑屏等),在进行业务分析时,回退同样作为特殊场景而存在。针对这种场景,可以利用页面的生命周期,识别页面的复用,配合栈的深度来识别是否是回退行为。

# H5 & Native 日志统一

  1. APP 分为两种:一种是纯 Native APP;一种是既有 Native,又有 H5 页面嵌入的 APP,即 Hybrid APP。当前,纯 Native APP 已经非常少了,一般都是 Hybrid APP 。

  2. Native 页面采用采集 SDK 进行日志采集,H5 页面一般采用基于浏览器的页面日志采集方式进行采集。

  3. 在当前的实践中,由于采集方式的不同,采集到的内容及采集服务器均分离开。若需要进行完整的数据分析,就需要将两类日志在数据处理时进行关联,而就算不考虑处理成本,在很多情况下,Native 和 H5 互跳,即使关联也无法还原用户路径,数据丢失严重。对于产品经理以及运营、管理、数据分析人员而言,在不同的终端采用不同的方案采集日志,以不同的算法来做日志统计,忍受多端之间的数据隔离,并对由此导致的多样数据口径进行整理分析和解释,已经是越来越不能容忍的切身之痛。考虑到后续日志数据处理的便捷性、计算成本、数据的合理性及准确性,我们需要对 Native 和 H5 日志进行统一处理

  4. 要想实现 Native 和 H5 日志的统一处理,就需要对 Hybrid 日志有统一的方案。简单的思路就是首先将两类日志进行归一。那么是把 Native 日志向 H5 日志归,还是把 H5 日志归到 Native 日志呢?其实两条路均可以实现,没有绝对的答案。

  5. 在阿里巴巴,采用的是将 H5 日志归到 Native 日志的方式,原因有二:

  • 一是采用来集 SDK 可以采集到更多的设备相关数据,这在移动端的数据分析中尤为重要;

  • 二是采集 SDK 处理日志,会先在本地缓存,而后借机上传,在网络状况不佳时延迟上报,保证数据不丢失。

  1. 将 H5 日志归到 Native 日志的流程如下:

(1)H5 页面浏览和页面交互的数据,在执行时通过加载日志采集的 JavaScript 脚本,采集当前页面参数,包括浏览行为的上下文信息以及一些运行环境信息。在 APP 中打开 H5 页面和在浏览器中的处理完全一样,在前端页面的开发中无须做任何特殊的处理,只需在页面开发时手动植入日志采集的 JavaScript 脚本即可

(2)在浏览器日志采集的 JavaScript 脚本中实现将所采集的数据打包到一个对象中,然后调用 WebView 框架的 JSBridge 接口,调用移动客户端对应的接口方法,将埋点数据对象当作参数传入

(3)移动客户端日志采集 SDK,封装提供接口,实现将传入的内容转换成移动客户端日志格式。采集 SDK 会根据日志类别来识别是页面浏览事件,还是控件点击事件,然后调用内部相应的接口进行处理,将埋点数据转换成移动客户端日志的统一格式。而后就同移动客户端的日志处理一样,先记录到本地日志缓存中,择机上传。通过日志类别的识别来做不同的日志格式转换,这样,未来如果要实现新的事件类别,比如自定义事件,就不需要改动 WebView 层的接口,只需改动 JavaScript 的部分内容及移动客户端日志采集 SDK 中对应的实现即可。

这种方案的局限性就在于:必须要浏览器采集 JavaScript、WebView、客户端采集 SDK 的配合。而往往很多时候业务并不希望做任何调整,更多的是希望减少依赖。

# 设备标识

  1. 所有互联网产品的两大基本指标是页面浏览量(Page View, PV)访客数(Unique Visitors, UV)。关于 UV,对于登录用户,可以使用用户 ID 来进行唯一标识,但是很多日志行为并不要求用户登录,这就导致在很多情况下采集上来的日志都没有用户 ID。

  2. PC 端一般使用 Cookie 信息来作为设备的唯一信息,对于 APP 来说,我们就要想办法获取到能够唯一标识设备的信息。

  3. 对于只有单 APP 的公司来说,设备唯一标识不是需要攻克的难题,但对于像阿里巴巴这样拥有众多 APP 的公司来说,设备唯一标识就显得尤为重要。阿里巴巴集团无线设备唯一标识使用 UTDID,每台设备一个 ID 作为唯一标识。UTDID 随着 iOS 和 Android 系统对权限控制的不断升级,对方案做了多次调整,包括存储方式、存储位置、共享方式等,以及和服务器端的配合,其生成方式也使用一套较完备的算法。但就目前的进展来说,UTDID 还未完全实现其使命。

# 日志传输

  1. 无线客户端日志的上传,不是产生一条日志上传一条,而是无线客户端产生日志后,先存储在客户端本地,然后再伺机上传。所谓伺机,就需要有数据分析的支持,如在启动后、使用过程中、切换到后台时这些场景下分别多久触发一次上传动作。当然单纯地靠间隔时间来决定上传动作是不够的,还需要考虑日志的大小及合理性(如单条日志超大,很可能就是错误日志)。另外,还需要考虑上传时网络的耗时,来决定是否要调整上传机制。

  2. 客户端数据上传时是向服务器发送 POST 请求,服务器端处理上传请求,对请求进行相关校验,将数据追加到本地文件中进行存储,存储方式使用 Nginx 的 access_log,access_log 的切分维度为天,即当天接收的日志存储到当天的日志文件中。

  3. 此外,考虑到后续的数据处理,以及特殊时期不同日志的保障级别,还对日志进行了分流。比如阿里巴巴集团的 Adash(无线日志服务器端处理程序),根据应用及事件类型对每日高达数千亿的日志进行了分流。

  4. 分流的好处显而易见,如 “双11” 时,日常数千亿的日志可能冲高到万亿,此时服务器及后续的数据计算压力就非常大了;而对于重要的数据计算来说,很可能只需要页面事件及控件点击事件即可,此时就可以适当地释放其他类型日志的资源来处理更重要的页面事件及控件点击事件。

# 日志采集的挑战

  1. 对于目前的互联网行业而言,互联网日志早已跨越初级的饥饿阶段(大型互联网企业的日均日志收集量均以亿为单位计量),反而面临海量日志的淹没风险。各类采集方案提供者所面临的主要挑战已不是日志采集技术本身,而是如何实现日志数据的结构化和规范化组织,实现更为高效的下游统计计算,提供符合业务特性的数据展现,以及为算法提供更便捷、灵活的支持等方面。

  2. 以下是两个典型的场景及阿里巴巴采用的解决方案。

  • 日志分流与定制处理

    • 大型互联网网站的日志类型和日志规模都呈现出高速增长的态势,而且往往会出现短时间的流量热点爆发。这一特点,使得在日志服务器端采用集中统一的解析处理方案变得不可能,其要求在日志解析和处理过程中必须考虑业务分流(相互之间不应存在明显的影响,爆发热点不应干扰定常业务日志的处理)、日志优先级控制,以及根据业务特点实现定制处理。例如,对于电商网站而言,数据分析人员对位于点击流前端的促销页面和位于后端的商品页面的关注点是不一样的,而这两类页面的流量又往往同等重要且庞大,如果采用统一的解析处理方案,则往往需要在资源浪费(尽可能多地进行预处理)和需求覆盖不全(仅对最重要的内容进行预处理)两个选择之间进行取舍。这种取舍的结果一般不是最优的。

    • 考虑到阿里日志体量的规模和复杂度,分治策略从一开始便是阿里互联网日志采集体系的基本原则。以 PV 日志采集领域一个最浅显的例子来说明,与业界通用的第三方日志采集方案的日志请求路径几乎归一不同,阿里 PV 日志的请求位置(URL)是随着页面所在业务类型的不同而变化的。通过尽可能靠前地布置路由差异,就可以尽可能早地进行分流,降低日志处理过程中的分支判断消耗,并作为后续的计算资源调配的前提,提高资源利用效率。

    • 与业界方案的普遍情况相比,阿里的客户端日志采集代码的一个突出特点是实现了非常高的更新频次(业界大多以季度乃至年为单位更新代码,阿里则是以周/月为单位),并实现了更新的配置化。我们不仅考虑诸如日志分流处理之类的日志服务器端分布计算方案,而且将分类任务前置到客户端(从某种程度上讲,这才是真正的“分布式” !)以实现整个系统的效能最大化。最后可以在计算后端几乎无感知的情况下,承载更大的业务量并保证处理质量和效率。

  • 采集与计算一体化设计

    • 以 PV 日志为例,页面 PV 日志采集之后一个基础性操作是日志的归类与汇总在早期的互联网日志分析实践中,是以 URL 路径,继而以 URL(正则)规则集为依托来进行日志分类的。在网站规模较小时,这一策略还可以基本顺利地运转下去,但随着网站的大型化和开发人员的增加,URL 规则集的维护和使用成本会很快增长到不现实的程度,同时失控的大规模正则适配甚至会将日志计算硬件集群彻底榨干。

    • 这一状况要求日志采集方案必须将采集与计算作为一个系统来考量,进行一体化设计。阿里日志采集针对这一问题给出的答案是两套日志规范和与之对应的元数据中心。其中,对应于 PV 日志的解决方案是目前用户可直观感知的 SPM 规范(例如,在页面的 URL 内可以看见 SPM 参数)SPM 元数据中心

    • 通过 SPM 的注册和简单部署(仅需要在页面文件内声明一个或多个标签),用户即可将任意的页面流量进行聚类,不需要进行任何多余的配置就可以在相应的内部数据产品内查询聚合统计得到的流量、转化漏斗、引导交易等数据,以及页面各元素点击数据的可视化视图。

    • 对应于自定义日志的解决方案则是黄金令箭(Goldlog)/APP 端的点击或其他日志规范及其配置中心通过注册一个与所在页面完全独立的令箭实体/控件实体,用户可以一键获得对应的埋点代码,并自动获得实时统计数据和与之对应的可视化视图。通过简单的扩展配置,用户还可以自动获得自定义统计维度下的分量数据。

    • 在当前的互联网环境下,互联网日志的规模化采集方案必须具备一个与终端设备的技术特点无关,具有高度扩展弹性和适应性,同时深入契合应用需求的业务逻辑模型,并基于此制定对应的采集规范交由产品开发人员执行。若非如此,则不足以保障采集一解析一处理一应用整个流程的通畅。

    • 目前阿里已成功实现规范制定一元数据注册一日志采集一自动化计算一可视化展现全流程的贯通。通过一体化设计,用户甚至可以在不理解规范的前提下,通过操作向导式界面,实现日志来集规范的自动落地和统计应用。

    • 日志本身不是日志采集的目的,服务于基于日志的后续应用,才是日志采集正确的着眼点。

# 大促保障

阿里的日志处理全链路如下:

首先,端上实现了服务器端推送配置到客户端,且做到高到达率;其次,对日志做了分流,结合日志的重要程度及各类日志的大小,实现了日志服务器端的拆分;最后,在实时处理方面,也做了不少的优化以提高应用的吞吐量。

在这几项的基础上,结合实时处理能力,评估峰值数据量,在高峰期通过服务器端推送配置的方式对非重要日志进行适当限流,错峰后逐步恢复。

这里说的服务器端推送配置包含较多的内容,首先是作用范围,可以针对应用、平台、事件、事件中的某个场景;其次是具体实施,包括延迟上报、部分采样等。所谓延迟上报,即配置生效后,满足条件的日志将被暂时存在客户端,待配置恢复后再上传到服务器;所谓采样,即配置生效后,满足条件的日志将被实施采样(对于一些技术类日志,如页面加载情况、消耗内存等,可以实施采样),只上报部分日志到服务器。

整个日志处理流程还是比较长的,对于对实时性要求极高的业务场景,如上链路显然不能满足需求。所以一方面,我们从业务上进行改造,采用端上记录;另一方面,我们也在链路各环节做优化,如从采集服务器直接完成解码并调用业务 API 完成业务的计算(省去中间的传输和过多的处理)。在这方面我们也面临着巨大的挑战,在保证稳定的同时扩展功能,在稳定及业务深度之间做到很好的平衡。

# 数据同步

  1. 数据同步技术更通用的含义是不同系统间的数据流转,有多种不同的应用场景。
  • 主数据库与备份数据库之间的数据备份,以及主系统与子系统之间的数据更新,属于同类型不同集群数据库之间的数据同步。

  • 此外,还有不同地域、不同数据库类型之间的数据传输交换,比如分布式业务系统与数据仓库系统之间的数据同步。

  1. 对于大数据系统来说,包含数据从业务系统同步进入数据仓库数据从数据仓库同步进入数据服务或数据应用两个方面。

# 数据同步基础

  1. 源业务系统的数据类型多种多样,有如下这些:
  • 来源于关系型数据库的结构化数据,如 MySQL 、Oracle 、DB2, SQL Server 等;

  • 来源于非关系型数据库的非结构化数据,如 OceanBase 、HBase 、MongoDB 等,这类数据通常存储在数据库表中

  • 来源于文件系统的结构化或非结构化数据,如阿里云对象存储 OSS、文件存储 NAS 等,这类数据通常以文件形式进行存储

  1. 数据同步需要针对不同的数据类型及业务场景选择不同的同步方式。总的来说,同步方式可以分为三种:直连同步、数据文件同步数据库日志解析同步

# 直连同步

直连同步是指通过定义好的规范接口 API 和基于动态链接库的方式直接连接业务库,如 ODBC/JDBC 等规定了统一规范的标准接口,不同的数据库基于这套标准接口提供规范的驱动,支持完全相同的函数调用和 SQL 实现。

📌 优点

  • 配置简单,实现容易,比较适合操作型业务系统的数据同步。

📌 缺点

  • 对源系统的性能影响较大,当执行大批量数据同步时会降低甚至拖垮业务系统的性能。如果业务库采取主备策略,则可以从备库抽取数据,避免对业务系统产生性能影响。但是当数据量较大时,采取此种抽取方式性能较差,不太适合从业务系统到数据仓库系统的同步。

# 数据文件同步

数据文件同步通过约定好的文件编码、大小、格式等,直接从源系统生成数据的文本文件,由专门的文件服务器,如 FTP 服务器传输到目标系统后,加载到目标数据库系统中。

📌 优点

  • 当数据源包含多个异构的数据库系统(如 MySQL、Oracle、SQL Server、DB2 等)时,用这种方式比较简单、实用。

  • 互联网的日志类数据,通常是以文本文件形式存在的,也适合使用数据文件同步方式。

📌 优化点

  • 由于通过文件服务器上传、下载可能会造成丢包或错误,为了确保数据文件同步的完整性,通常除了上传数据文件本身以外,还会上传一个校验文件该校验文件记录了数据文件的数据量以及文件大小等校验信息,以供下游目标系统验证数据同步的准确性

  • 在从源系统生成数据文件的过程中,可以增加压缩和加密功能,传输到目标系统以后,再对数据进行解压缩和解密,这样可以大大提高文件的传输效率和安全性。

# 数据库日志解析同步

目前,大多数主流数据库都已经实现了使用日志文件进行系统恢复,因为日志文件信息足够丰富,而且数据格式也很稳定,完全可以通过解析日志文件获取发生变更的数据,从而满足增量数据同步的需求

以 Oracle 为例,可以通过源系统的进程,读取归档日志文件用以收集变化的数据信息,并判断日志中的变更是否属于被收集对象,将其解析到目标数据文件中。这种读操作是在操作系统层面完成的,不需要通过数据库,因此不会给源系统带来性能影响。

然后可通过网络协议,实现源系统和目标系统之间的数据文件传输。相关进程可以确保数据文件的正确接收和网络数据包的正确顺序并提供网络传输冗余,以确保数据文件的完整性。

数据文件被传输到目标系统后,可通过数据加载模块完成数据的导入,从而实现数据从源系统到目标系统的同步。

📌 优点

  • 数据库日志解析同步方式实现了实时与准实时同步的能力,延迟可以控制在毫秒级别,并且对业务系统的性能影响也比较小,目前广泛应用于从业务系统到数据仓库系统的增量数据同步应用之中。

📌 缺点

  • 数据延迟。例如,业务系统做批量补录可能会使数据更新量超出系统处理峰值,导致数据延迟。

  • 投入较大。采用数据库日志抽取的方式投入较大,需要在源数据库与目标数据库之间部署一个系统实时抽取数据。

  • 数据漂移和遗漏。数据漂移,一般是对增量表而言的,通常是指该表的同一个业务日期数据中包含前一天或后一天凌晨附近的数据或者丢失当天的变更数据

📌 删除数据变更

由于数据库日志抽取一般是获取所有的数据记录的变更(增、删、改),落地到目标表时我们需要根据主键去重按照日志时间倒排序获取最后状态的变化情况。对于删除数据这种变更情况,针对不同的业务场景可以采用一些不同的落地手法。主要有 3 种方式:

  • 不过滤删除流水。不管是否是删除操作,都获取同一主键最后变更的那条流水。

  • 过滤最后一条删除流水。如果同一主键最后变更的那条流水是删除操作,就获取倒数第二条流水。

  • 过滤删除流水和之前的流水。如果在同一主键变更的过程中有删除操作,则根据操作时间将该删除操作对应的流水和之前的流水都过滤掉。

对于采用哪种方式处理删除数据,要看前端是如何删除无效数据的。前端业务系统删除数据的方式一般有两种:正常业务数据删除手工批量删除。手工批量删除通常针对类似的场景,业务系统只做逻辑删除,不做物理删除,DBA 定期将部分历史数据直接删除或者备份到备份库。

一般情况下,可以采用不过滤的方式来处理,下游通过是否删除记录的标识来判断记录是否有效。如果明确业务数据不存在业务上的删除,但是存在批量手工删除或备份数据删除,例如淘宝商品、会员等,则可以采用只过滤最后一条删除流水的方式,通过状态字段来标识删除记录是否有效。

# 阿里数据仓库的同步方式

  1. 数据仓库的特性之一是集成将不同的数据来源、不同形式的数据整合在一起,所以从不同业务系统将各类数据源同步到数据仓库是一切的开始。

  2. 阿里数据仓库的数据同步的特点

  • 数据来源多种多样。

  • 数据量巨大。

因此,需要针对不同的数据源类型和数据应用的时效性要求而采取不同的策略。

# 批量数据同步

对于离线类型的数据仓库应用,需要将不同的数据源批量同步到数据仓库,以及将经过数据仓库处理的结果数据定时同步到业务系统。

当前市场上的数据库系统种类很多,有行存储的和列存储的,有开源的和非开源的,每一种数据库的数据类型都略有不同,而数据仓库系统则是集成各类数据源的地方,所以数据类型是统一的。

要实现各类数据库系统与数据仓库系统之间的批量双向数据同步,就需要先将数据转换为中间状态,统一数据格式

由于这类数据都是结构化的,且均支持标准的 SQL 语言查询,所以所有的数据类型都可以转换为字符串类型。因此,我们可以通过将各类源数据库系统的数据类型统一转换为字符串类型的方式,实现数据格式的统一。

阿里巴巴的 DataX 就是这样一个能满足多方向高自由度的异构数据交换服务产品

对于不同的数据源, DataX 通过插件的形式提供支持,将数据从数据源读出并转换为中间状态,同时维护好数据的传输、缓存等工作。数据在 DataX 中以中间状态存在,并在目标数据系统中将中间状态的数据转换为对应的数据格式后写入。

DataX 可接入的数据源如下:

DataX 采用 Framework + Plugin 的开放式框架实现,Framework 处理缓冲、流程控制、并发、上下文加载等高速数据交换的大部分技术问题,并提供简单的接口与插件接入。

插件仅需实现对数据处理系统的访问,编写方便,开发者可以在极短的时间内开发一个插件以快速支持新的数据库或文件系统。

数据传输在单进程(单机模式)/多进程(分布式模式)下完成,传输过程全内存操作,不读写磁盘,也没有进程间通信,实现了在异构数据库或文件系统之间的高速数据交换。

DataX 的架构设计图如下:

  • Job:数据同步作业。

  • Splitter:作业切分模块,将一个大任务分解成多个可以并发行的小任务。

  • Sub-Job:数据同步作业切分后的小任务,或称之为 Task。

  • Reader:数据读入模块,负责运行切分后的小任务,将数据从源系统装载到 DataX。

  • Channel:Reader 和 Writer 通过 Channel 交换数据。

  • Writer:数据写出模块,负责将数据从 DataX 导人目标数据系统。

# 实时数据同步

阿里巴巴的 TimeTunnel(TT) 系统就是一个实时数据传输平台,具有高性能、实时性、顺序性、高可靠性、高可用性、可扩展性等特点。它有效保障了阿里各种场景的实时数据应用。

具体来说,TT 是一种基于生产者、消费者和 Topic 消息标识的消息中间件,将消息数据持久化到 HBase 的高可用、分布式数据交互系统。TT 的实时数据传输示意图如下:

  • 生产者:消息数据的产生端,向 Time Tunnel 集群发送消息数据,就是图中的生产 Client。

  • 消费者:消息数据的接收端,从 TimeTunnel 集群中获取数据进行业务处理。

  • Topic:消息类型的标识,如淘宝 acookie 日志的 Topic 为 taobao_acookie,生产 Client 和消费 Client 均需要知道对应的 Topic 名字。

  • Broker 模块:负责处理客户端收发消息数据的请求,然后往 HBase 取发数据。

Time Tunnel 支持主动、被动等多种数据订阅机制,订阅端自动负载均衡,消费者自己把握消费策略。对于读写比例很高的 Topic ,能够做到读写分离,使消费不影响发送。同时支持订阅历史数据,可以随意设置订阅位置,方便用户回补数据。另外,针对订阅有强大的属性过滤功能,用户只需关心自己需要的数据即可。

# 数据同步遇到的问题与解决方案

# 1. 分库分表的处理

随着业务的不断增长,业务系统处理的数据量也在飞速增加,需要系统具备灵活的扩展能力高并发大数据量的处理能力,目前一些主流数据库系统都提供了分布式分库分表方案来解决这个问题。但是对于数据同步来说,这种分库分表的设计无疑加大了同步处理的复杂度。分库分表处理方案如下:

阿里巴巴的 TDDL(Taobao Distributed Data Layer)就是这样一个分布式数据库的访问引擎,通过建立中间状态的逻辑表来整合统一分库分表的访问。TDDL 引擎如下:

TDDL 是在持久层框架之下、JDBC 驱动之上的中间件,它与 JDBC 规范保持一致,有效解决了分库分表的规则引擎问题,实现了 SQL 解析、规则计算、表名替换、选择执行单元并合并结果集的功能,同时解决了数据库表的读写分离、高性能主备切换的问题,实现了数据库配置信息的统一管理。

# 2. 高效同步和批量同步

数据同步的方法通常是先创建目标表,再通过同步工具填写数据库连接、表、字段等各种配置信息后测试完成数据同步。这也是 DataX 任务的配置过程,同步中心对 DataX 进行进一步封装,通过源系统元数据降低了数据库连接、表和字段等信息的配置复杂度,但在实际生产过程中仍然会遇到一些问题。

  • 需要同步大批量的数据时,会导致工作量特别大,同时相似且重复的操作会降低开发人员的工作热情。

  • 数据仓库的数据源种类特别丰富,遇到不同类型的数据源同步就要求开发人员去了解其特殊配置。

  • 部分真正的数据需求方,如 Java 开发和业务运营,由于存在相关数据同步的专业技能门槛,往往需要将需求提交给数据开发方来完成,额外增加了沟通和流程成本。

为了解决上述问题,阿里巴巴数据仓库研发了 OneClick 产品

  • 对不同数据源的数据同步配置透明化,可以通过库名和表名唯一定位,通过 IDB 接口获取元数据信息自动生成配置信息。

  • 简化了数据同步的操作步骤,实现了与数据同步相关的建表、配置任务、发布、测试操作一键化处理,并且封装成 Web 接口进一步达到批量化的效果。

  • 降低了数据同步的技能门槛,让数据需求方更加方便地获取和使用数据。

通过 OneClick 产品,真正实现了数据的一键化和批量化同步,一键完成 DDL 和 DML 的生成、数据的冒烟测试以及在生产环境中测试等。

IDB

IDB 是阿里巴巴集团用于统一管理 MySQL、Ocean Base、PostgreSQL、Oracle、SQL Server 等关系型数据库的平台,它是一种集数据管理、结构管理、诊断优化、实时监控和系统管理于一休的数据管理服务;在对集团数据库表的统一管理服务过程中,IDB 产出了数据库、表、字段各个级别元数据信息,并且提供了元数据接口服务。

# 3. 增量与全量同步的合并

在批量数据同步中,有些表的数据量随着业务的发展越来越大,如果按周期全量同步的方式会影响处理效率。在这种情况下,可以选择每次只同步新变更的增量数据,然后与上一个同步周期获得的全量数据进行合井,从而获得最新版本的全量数据

在传统的数据整合方案中,合并技术大多采用 merge 方式(update + insert)。

不过,当前流行的大数据平台基本都不支持 update 操作,现在比较推荐的方式是全外连接(full outer join)+ 数据全量覆盖重新加载(insert overwrite),即如日调度,即将当天的增量数据和前一天的全量数据做全外连接,重新加载最新的全量数据。在大数据量规模下,全量更新的性能比 update 要高得多。

此外,如果担心数据更新错误问题,可以采用分区方式,每天保持一个最新的全量版本,保留较短的时间周期(如 3~7 天)

另外,当业务系统的表有物理删除数据的操作,而数据仓库需要保留所有历史数据时,也可以选择这种方式,在数据仓库中永久保留最新的全量数据快照。

# 4. 同步性能的处理

数据同步任务是针对不同数据库系统之间的数据同步问题而创建的一系列周期调度的任务。

在大型的数据调度工作台上,每天会运行大量的数据同步任务。针对数据同步任务,一般首先需要设定首轮同步的线程数,然后运行同步任务

这样的数据同步模式存在以下几个问题:

  • 有些数据同步任务的总线程数达不到用户设置的首轮同步的线程数时,如果同步控制器将这些同步线程分发到 CPU 比较繁忙的机器上,将导致这些同步任务的平均同步速度非常低,数据同步速度非常慢。

  • 用户不清楚该如何设置首轮同步的线程数,基本都会设置成一个固定的值,导致同步任务因得不到合理的 CPU 资源而影响同步效率。

  • 不同的数据同步任务的重要程度是不一样的,但是同步控制器平等对待接收到的同步线程,导致重要的同步线程因得不到 CPU 资源而无法同步。

这几个问题会导致数据同步任务运行不稳定

对此,阿里巴巴数据团队实践出了一套基于负载均衡思想的新型数据同步方案。该方案的核心思想是通过目标数据库的元数据估算同步任务的总线程数,以及通过系统预先定义的期望同步速度估算首轮同步的线程数,同时通过数据同步任务的业务优先 级决定同步线程的优先级,最终提升同步任务的执行效率和稳定性。

# 5. 数据漂移的处理

通常我们把从源系统同步进人数据仓库的第一层数据称为 ODS 或者 staging 层数据,阿里巴巴统称为 ODS。

数据漂移是 ODS 数据的一个顽疾,通常是指 ODS 表的同一个业务日期数据中包含前一天或后一天凌晨附近的数据或者丢失当天的变更数据

由于 ODS 需要承接面向历史的细节数据查询需求,这就需要物理落地到数据仓库的 ODS 表按时间段来切分进行分区存储,通常的做法是按某些时间戳字段来切分,而实际上往往由于时间戳字段的准确性问题导致发生数据漂移

通常,时间戳字段分为四类:

  • 数据库表中用来标识数据记录更新时间的时间戳字段(假设这类字段叫 modified_ time)。

  • 数据库日志中用来标识数据记录更新时间的时间戳字段(假设这类宇段叫 log_time)。

  • 数据库表中用来记录具体业务过程发生时间的时间戳字段(假设这类字段叫 proc_time)。

  • 标识数据记录被抽取到时间的时间戳字段(假设这类字段叫 extract_time)。

在实际生产中,这几个时间往往会出现差异,可能的原因有以下几点:

  • 由于数据抽取是需要时间的,extract_time 往往会晚于前三个时间。

  • 前台业务系统手工订正数据时未更新 modified_time。

  • 由于网络或者系统压力问题,log_time 或者 modified_time 会晚于 proc_time。

通常的做法是根据其中的某一个字段来切分 ODS 表,这就导致产生数据漂移。

以下是数据漂移的几种场景:

  • 根据 extract_time 来获取数据。这种情况数据漂移的问题最明显。

  • 根据 modified_time 限制。在实际生产中这种情况最常见,但是往往会发生不更新 modified_time 而导致的数据遗漏,或者凌晨时间产生的数据记录漂移到后一天。

  • 根据 log_time 限制。由于网络或者系统压力问题,log_time 会晚于 proc_time ,从而导致凌晨时间产生的数据记录漂移到后一天。

  • 根据 proc_time 限制。仅仅根据 proc_time 限制,我们所获取的 ODS 表只是包含一个业务过程所产生的记录,会遗漏很多其他过程的变化记录,这违背了 ODS 和业务系统保持一致的设计原则。

处理方法主要有以下两种:

  • 多获取后一天的数据

    可以在 ODS 每个时间分区中向前、向后多冗余一些数据,保障数据只会多不会少,而具体的数据切分让下游根据自身不同的业务场景用不同的业务时间 proc_time 来限制。但是这种方式会有一些数据误差,例如一个订单是当天支付的,但是第二天凌晨申请退款关闭了该订单,那么这条记录的订单状态会被更新,下游在统计支付订单状态时会出现错误。

  • 通过多个时间戳字段限制时间来获取相对准确的数据

    • 首先根据 log_time 分别冗余前一天最后 15 分钟的数据和后一天凌晨开始 15 分钟的数据,并用 modified_time 过滤非当天数据,确保数据不会因为系统问题而遗漏。

    • 然后根据 log_time 获取后一天 15 分钟的数据;针对此数据,按照主键根据 log_time 做升序排列去重。因为我们需要获取的是最接近当天记录变化的数据(数据库日志将保留所有变化的数据,但是落地到 ODS 表的是根据主键去重获取最后状态变化的数据)。

    • 最后将前两步的结果数据做全外连接,通过限制业务时间 proc_time 来获取我们所需要的数据。

# 离线数据开发

从采集系统中收集了大量的原始数据后,数据只有被整合和计算,才能被用于洞察商业规律,挖掘潜在信息,从而实现大数据价值,达到赋能于商业创造价值的目的。

# 数据开发平台

  1. 阿里数据研发岗位的工作大致可以概括为:了解需求 → 模型设计 → ETL 开发 → 测试 → 发布上线 → 日常运维 → 任务下线

  2. 与传统的数据仓库开发(ETL)相比,阿里数据研发有如下几个特点:

  • 业务变更频繁——业务发展非常快,业务需求多且变更频繁。

  • 需要快速交付——业务驱动,需要快速给出结果。

  • 频繁发布上线——迭代周期以天为单位,每天需要发布数次。

  • 运维任务多——在集团公共层平均每个开发人员负责 500 多个任务。

  • 系统环境复杂——阿里平台系统多为自研,且为了保证业务的发展,平台系统的迭代速度较快,平台的稳定性压力较大。

  1. 阿里通过统一的计算平台(Max Compute)统一的开发平台(D2 等相关平台和工具)统一的数据模型规范统一的数据研发规范,可以在一定程度上解决数据研发的痛点。

# 统一计算平台

阿里离线数据仓库的存储和计算都是在阿里云大数据计算服务 Max Compute 上完成的。

Max Compute 采用抽象的作业处理框架,将不同场景的各种计算任务统一在同一个平台之上,共享安全、存储、数据管理和资源调度,为 来自不同用户需求的各种数据处理任务提供统一的编程接口和界面。它提供数据上传/下载通道、SQL、MapReduce、机器学习算法、图编程模型和流式计算模型多种计算分析服务,并且提供完善的安全解决方案。

MaxCompute 的体系架构如下图:

MaxCompute 由四部分组成,分别是客户端(MaxCompute Client)接入层(MaxCompute Front End)逻辑层(MaxCompte Server)存储与计算层(Apsara Core)

  • MaxCompute 客户端有以下几种形式。

    • Web:以 RESTful API 的方式提供离线数据处理服务。

    • SDK:对 RESTful API 的封装,目前有 Java 等版本的实现。

    • CLT(Command Line Tool): 运行在 Windows/Linux 下的客户端工具,通过 CLT 可以提交命令完成 Project 管理、DDL、DML等操作。

    • IDE:上层可视化 ETL/BI 工具,即阿里内部名称是在云端(D2),用户可以基于在云端完成数据同步、任务调度、报表生成等常见操作。

  • 接入层提供 HTTP 服务、Cache、负载均衡,实现用户认证和服务层面的访问控制

  • 逻辑层又称作控制层,是 MaxCompute 的核心部分,实现用户空间和对象的管理、命令的解析与执行逻辑、数据对象的访问控制与授权等功能。在逻辑层有 Worker、SchedulerExecutor 三个角色:

    • Worker 处理所有的 RESTful 请求,包括用户空间(Project)管理操作、资源(Resource)管理操作、作业管理等,对于 SQL DML、MR 等需要启动 MapReduce 的作业,会生成 MaxCompute Instance(类似于 Hive 中的 Job ),提交给 Scheduler 进一步处理。

    • Scheduler 负责 MaxCompute Instance 的调度和拆解,并向计算层的计算集群询问资源占用情况以进行流控。

    • Executor 负责 MaxCompute Instance 的执行,向计算层的计算集群提交真正的计算任务。

  • 计算层就是飞天内核(Apsara Core),运行在和控制层相互独立的计算集群上,它包括 Pangu(分布式文件系统)、Fuxi(资源调度系统)、Nuwa/ZK(Namespace 服务)、Shennong(监控模块)等。

MaxCompute 中的元数据存储在阿里云计算的另一个开放服务 OTS(Open Table Service,开放结构化数据服务)中,元数据内容主要包括用户空间元数据、Table/Partition Schema、ACL、Job 元数据、安全体系等。

MaxCompute 的特点:

  • 计算性能高且更加普惠。

  • 集群规模大且稳定性高。

  • 功能组件非常强大。

    • MaxCompute SQL:标准 SQL 的语法,提供各类操作和函数来处理数据。

    • MaxCompute MapReduce:提供 Java MapReduce 编程模型,通过接口编写 MR 程序处理 MaxCompute 中的数据。还提供基于MapReduce 的扩展模型 MR2,在该模型下,一个 Map 函数后可以接入连续多个 Reduce 函数,执行效率比普通的 MapReduce 模型高。

    • MaxCompute Graph:面向迭代的图计算处理框架,典型应用有 PageRank、单源最短距离算法、K-均值聚类算法。

    • Spark:使用 Spark 接口编程处理存储在 MaxCompute 中的数据。

    • RMaxCompute:使用 R 处理 MaxCompute 中的数据。

    • Volume:MaxCompute 以 Volume 的形式支持文件,管理非二维表数据。

  • 安全性高。

    MaxCompute 采用多租户数据安全体系,实现用户认证、项目空间的用户与授权管理、跨项目空间的资源分享,以及项目空间的数据保护。如支付宝数据,符合银行监管的安全性要求,支持各种授权鉴权审查和 “最小访问权限” 原则,确保数据安全。

# 统一开发平台

阿里的数据研发人员在完成需求了解和模型设计之后,进入开发环节,开发工作流如下图。

对应于该开发工作流的产品和工具如下图。

1. SQLSCAN

SQLSCAN 与 D2 进行结合,嵌入到开发流程中,用户在提交代码时会触发 SQLSCAN 检查。SQLSCAN 工作流程如下图:

SQLSCAN 主要有如下三类规则校验:

  • 代码规范类规则,如表命名规范、生命周期设置、表注释等。

  • 代码质量类规则,如调度参数使用检查、分母为 0 提醒、NULL 值参与计算影响结果提醒、插入字段顺序错误等。

  • 代码性能类规则,如分区裁剪失效、扫描大表提醒、重复计算检测等。

SQLSCAN 规则有强规则和弱规则两类。触发强规则后,任务的提交会被阻断,必须修复代码后才能再次提交;而触发弱规则,则只会显示违反规则的提示,用户可以继续提交任务。

2. DQC

DQC(Data Quality Center,数据质量中心)主要关注数据质量,通过配置数据质量校验规则,自动在数据处理任务过程中进行数据质量 方面的监控。

DQC 主要有数据监控数据清洗两大功能。

DQC 数据监控规则有强规则和弱规则之分,强规则会阻断任务的执行(将任务置为失败状态,其下游任务将不会被执行);而弱规则只告警而不会阻断任务的执行。常见的 DQC 监控规则有:主键监控、表数据量及波动监控、重要字段的非空监控、重要枚举字段的离散值监控、指标值波动监控、业务规则监控等。

阿里数据仓库的数据清洗采用非侵人式的清洗策略,在数据同步过程中不进行数据清洗,避免影响数据同步的效率,其过程在数据进入 ODS 层之后执行。对于需要清洗的表,首先在 DQC 配置清洗规则;对于离线任务,每隔固定的时间间隔,数据入仓之后,启动清洗任务,调用 DQC 配置的清洗规则,将符合清洗规则的数据清洗掉,并保存至 DIRTY 表归档。如果清洗掉的数据量大于预设的阐值,则阻断任务的执行;否则不会阻断。

DQC 工作流程如下图:

3. 在彼岸

数据测试的典型测试方法是功能测试,主要验证目标数据是否符合预期。主要有以下场景:

  • 新增的业务需求

  • 数据迁移、重构和修改

在彼岸是阿里的大数据系统的自动化测试平台,将通用的、重复性的操作沉淀在测试平台中,提高测试效率。

在彼岸主要包含如下组件,除满足数据测试的数据对比组件之外,还有数据分布数据脱敏组件。

  • 数据对比:支持不同集群、异构数据库的表做数据对比。表级对比规则主要包括数据量和全文对比;字段级对比规则主要包括字段的统计值(如 SUM、AVG、MAX、MIN 等)、枚举值、空值、去重数、长度值等。

  • 数据分布:提取表和字段的一些特征值,并将这些特征值与预期值进行比对。表级数据特征提取主要包括数据量、主键等;字段级数据特征提取主要包括字段枚举值分布、空值分布、统计值(如 SUM、AVG、MAX、MIN 等)、去重数、长度值等。

  • 数据脱敏:将敏感数据模糊化。

使用在彼岸进行回归测试的流程如下图:

# 任务调度系统

在云计算大数据时代,调度系统无疑是整个大数据体系的指挥中枢。

如下图所示,调度系统中的各类任务互相依赖,形成一个典型的有向无环图。

在传统的数据仓库系统中,很多是依靠 Crontab 定时任务功能进行任务调度处理的。这种方式有很多弊端:

  • 各任务之间的依赖基于执行时间实现,容易造成前面的任务未结束或失败而后面的任务已经运行;

  • 任务难以并发执行,增加了整体的处理时间;

  • 无法设置任务优先级;

  • 任务的管理维护很不方便,无法进行执行效果分析等。

而在大数据环境下,每天需要处理海量的任务,多的可以达到几十上百万。另外,任务的类型也很繁杂,有 MapReduce、Hive、SQL、Spark、Java、Shell、Python、Perl、虚拟节点等,任务之间互相依赖且需要不同的运行环境。为了解决以上问题,阿里巴巴的大数据调度系统应运而生。

📌 调度系统的核心设计模型

整个调度系统共有两个核心模块:调度引擎(Phoenix Engine)执行引擎(Alisa)

  • 调度引擎的作用是根据任务节点属性以及依赖关系进行实例化,生成各类参数的实值,并生成调度树;

  • 执行引擎的作用是根据调度引擎生成的具体任务实例和配置信息,分配 CPU、内存、运行节点等资源,在任务对应的执行环境中运行节点代码。

在认识调度引擎之前,需要先了解两个模型:任务状态机模型工作流状态机模型

📌 任务状态机模型

任务状态机模型是针对数据任务节点在整个运行生命周期的状态定义,总共有 6 种状态,状态之间的转换逻辑如下图。

📌 工作流状态机模型

工作流状态机模型是针对数据任务节点在调度树中生成的工作流运行的不同状态定义,共有 5 种状态,其关系如下图。

📌 调度引擎工作原理

调度引擎(Phoenix Engine)基于以上两个状态机模型原理,以事件驱动的方式运行,为数据任务节点生成实例,并在调度树中生成具体执行的工作流。

任务节点实例在工作流状态机、任务状态机和事件处理器之间转换,其中调度引擎只涉及任务状态机的未运行和等待运行两种状态,其他 5 种状态存在于执行引擎中

调度引擎工作原理示意图如下图所示:

  • Async Dispatcher:异步处理任务调度。

  • Sync Dispatcher:同步处理任务调度。

  • Task 事件处理器:任务事件处理器,与任务状态机交互。

  • DAG 事件处理器:工作流事件处理器,与工作流状态机交互。

一个 DAG 事件处理器包含若干个 Task 事件处理器。

📌 执行引擎工作原理

执行引擎(Alisa)的逻辑架构如下图所示:

# 实时技术

在大数据系统中,离线批处理技术可以满足非常多的数据使用场景需求,但在 DT 时代,每天面对的信息是瞬息万变的,越来越多的应用场景对数据的时效性提出了更高的要求。

数据价值是具有时效性的,在一条数据产生的时候,如果不能及时处理并在业务系统中使用,就不能让数据保持最高的 “新鲜度” 和价值最大化。

# 数据时效性

按照数据的延迟情况,数据时效性一般分为三种(离线、准实时、实时):

  • 离线:在今天(T)处理 N 天前(T - N,N 1 )的数据,延迟时间粒度为

  • 准实时:在当前小时(H)处理 N 小时前(H - N,N > 0,如 0.5 小时、1 小时等)的数据,延迟时间粒度为小时

  • 实时:在当前时刻处理当前的数据,延迟时间粒度为

离线和准实时都可以在批处理系统中实现(比如 Hadoop、MaxCompute、Spark 等系统),只是调度周期不一样而己,而实时数据则需要在流式处理系统中完成

# 流式数据处理

流式数据处理技术是指业务系统每产生一条数据,就会立刻被采集并实时发送到流式任务中进行处理,不需要定时调度任务来处理数据。

流式数据处理一般具有以下特征:

  • 时效性高

  • 常驻任务

    区别于离线任务的周期调度,流式任务属于常驻进程任务,一旦启动后就会一直运行,直到人为地终止,因此计算成本会相对比较高。这一特点也预示着流式任务的数据源是无界的,而离线任务的数据源是有界的。这也是实时处理和离线处理最主要的差别,这个特性会导致实时任务在数据处理上有一定的局限性。

  • 性能要求高

    实时计算对数据处理的性能要求非常严格,如果处理吞吐量跟不上采集吞吐量,计算出来的数据就失去了实时的特性。比如实时任务 1 分钟只能处理 30 秒采集的数据,那么产出的数据的延时会越来越长,不能代表当前时刻的业务状态,有可能导致业务方做出错误的运营决策。在互联网行业中,需要处理的数据是海量的,如何在数据量快速膨胀的情况下也能保持高吞吐量低延时,是当前面临的重要挑战。因此,实时处理的性能优化占了任务开发的很大一部分工作。

  • 应用局限性

    实时数据处理不能替代离线处理,除了计算成本较大这个因素外,对于业务逻辑复杂的场景(比如双流关联或者需要数据回滚的情况),其局限性导致支持不足。另外,由于数据源是流式的,在数据具有上下文关系的情况下,数据到达时间的不确定性导致实时处理眼离线处理得出来的结果会有一定的差异。

# 流式技术架构

在流式计算技术中,需要各个子系统之间相互依赖形成一条数据处理链路,才能产出结果最终对外提供实时数据服务。流式技术架构中的系统跟离线处理是有交叉的,两套技术方案并不是完全独立的,并且在业界中有合并的趋势。

各个子系统按功能划分的话,主要分为以下几部分。

  • 数据采集

  • 数据处理

  • 数据存储

  • 数据服务

流式技术架构图如下:

在数据采集和数据服务部分实时和离线是公用的,因为在这两层中都不需要关心数据的时效性。这样才能做到数据源的统一,避免流式处理和离线处理的不一致。

📌 1. 数据采集

所采集的数据都来自于业务服务器,从所采集的数据种类来看,主要可以划分为两种:

  • 数据库变更日志,比如 MySQL 的 binlog 日志、HBase 的 hlog 日志、Ocean Base 的变更日志、Oracle 的变更日志等。

  • 引擎访问日志,比如用户访问网站产生的 Apache 引擎日志、搜索引擎的接口查询日志等。

一般情况下,出于吞吐量以及系统压力上的考虑,并不是新增一条记录就采集一次,而是基于下面的原则,按批次对数据进行采集。

  • 数据大小限制:当达到限制条件时,把目前采集到的新数据作为一批(例如 512KB 写一批)。

  • 时间阈值限制:当时间达到一定条件时,也会把目前采集到的新数据作为一批,避免在数据量少的情况下一直不采集(例如 30 秒写一批)。

只要上面的其中一个条件达到了,就会被作为一批新数据采集到数据中间件中。这两个条件的参数需要根据业务的需求来设定,当批次采集频繁时,可以降低延时,但必然会导致吞吐量下降。

对于采集到的数据需要一个数据交换平台分发给下游,这个平台就是数据中间件。数据中间件系统有很多实现方式,比如开源的系统有 Kafka ,而阿里巴巴集团内部用得比较多的是 TimeTunnel(原理和 Kafka 类似),还有 MetaQ 、Notify 等消息系统。

消息系统与数据中间件、数据库之间的关系如下图:

从图中可以看出,消息系统是数据库变更节点的上游,所以它的延时比数据中间件低很多,但是其支持的吞吐量有限。因此,消息系统一般会用作业务数据库变更的消息中转,比如订单下单、支付等消息。对于其他较大的业务数据(每天几十 TB 的容量),一般会通过数据中间件系统来中转,虽然它的延时在秒级,但是其支持的吞吐量高。

消息系统和数据中间件的性能对比如下:

时效性 吞吐量
消息系统 毫秒
数据中间件

在一些情况下,有些业务并没有通过消息系统来对数据库进行更新(比如有些子业务的订单数据是通过同步方式导入 MySQL 的)。也就是说,从消息系统中获取的数据并不是最全的,而通过数据库变更日志拿到的业务变更过程数据肯定是全的。因此,为了和离线数据源保持一致,一般都是通过数据中间件来采集数据库变更数据这种形式来获取实时数据的。

时效性和吞吐量是数据处理中的两个矛盾体,很多时候需要从业务的角度来权衡使用什么样的系统来做数据中转。

📌 2. 数据处理

在各大互联网公司中,有各种开源的和非开源的流计算引擎系统在使用。在业界使用比较广泛的是 Twitter 开源的 Storm (opens new window) 系统、雅虎开源的 S4 系统、Apache 的 Spark Streaming,以及最近几年兴起的 Flink

在阿里巴巴集团内使用比较多的是阿里云提供的 StreamCompute 系统,作为业界首创的全链路流计算开发平台,涵盖了从数据采集到数据生产各个环节,力保流计算开发严谨、可靠。

Storm (opens new window) 为例,简单说一下流数据处理的原理。实时应用的整个拓扑结构是一个有向无环图,如下:

  • spout:拓扑的输入,从数据中间件中读取数据,并且根据自定义的分发规则发送给下游的 bolt,可以有多个输入源。

  • bolt:业务处理单元,可以根据处理逻辑分为多个步骤,其相互之间的数据分发规则也是自定义的。

实时数据处理应用出于性能考虑,计算任务往往是多线程的。一般会根据业务主键进行分桶处理,并且大部分计算过程需要的数据都会放在内存中,这样会大大提高应用的吞吐量。当然,为了避免内存溢出,内存中过期的数据需要定时清理,可以按照 LRU(最近最少使用)算法或者业务时间集合归类清理(比如业务时间属于 T - 1 的,会在今天凌晨进行清理)。

# 实时任务的几个典型问题

# 1. 去重指标

在 BI(商业智能)统计类实时任务中,对于资源的消耗有一类指标是非常高的,那就是去重指标由于实时任务为了追求处理性能,计算逻辑一般都是在内存中完成的,中间结果数据也会缓存在内存中,这就带来了内存消耗过多的问题。

在计算去重时,势必要把去重的明细数据保存下来,当去重的明细数据达到上亿甚至几十亿时,内存中放不下了,怎么办?这时需要分两种情况去看:

  • 精确去重。在这种情况下,明细数据是必须要保存下来的,当遇到内存问题时,可以通过数据倾斜来进行处理,把一个节点的内存压力分到多个节点上

  • 模糊去重。在去重的明细数据量非常大,而业务的精度要求不高的情况下,可以使用相关的去重算法,把内存的使用量降到千分之一甚至万分之一,以提高内存的利用率

相关的去重算法有:

  • 布隆过滤器

该算法是位数组算法的应用,不保存真实的明细数据,只保存明细数据对应哈希值的标记位。当然,会出现哈希值碰撞的情况,但是误差率可以控制,计算出来的去重值比真实值小。采用这个算法存储 1 亿条数据只需要 100 多 MB 的空间。

适用场景:统计精度要求不高,统计维度值非常多的情况。比如统计全网各个商家的 UV 数据,结果记录数达到上千万条。因为在各个维度之间,布隆过滤器是可以共用的。

  • 基数估计

该算法也是利用哈希的原理,按照数据的分散程度来估算现有数集的边界,从而得出大概的去重值总和。这里估算的去重值可能比真实值大,也可能比真实值小。采用这个算法存储 1 亿条数据只需要几 KB 的内存。

适用场景:统计精度要求不高,统计维度非常粗的情况。比如整个大盘的UV 数据,每天的结果只有一条记录。基数估计在各个维度值之间不能共用,比如统计全天小时的 UV 数据,就需要有 24 个基数估计对象,因此不适合细粒度统计的场景。

# 2. 数据倾斜

数据倾斜是 ETL 中经常遇到的问题,比如计算一天中全网访客数或者成交额时,最终的结果只有一个,通常应该是在一个节点上完成相关的计算任务。

在数据量非常大的时候,单个节点的处理能力是有限的,必然会遇到性能瓶颈。这时就需要对数据进行分桶处理,分桶处理和离线处理的思路是一样的。

  • 去重指标分桶

通过对去重值进行分桶 Hash,相同的值一定会被放在同一个桶中去重,最后再把每个桶里面的值进行加和就得到总值,这里利用了每个桶的 CPU 和内存资源。

  • 非去重指标分桶

数据随机分发到每个桶中,最后再把每个桶的值汇总,主要利用的是各个桶的 CPU 能力。

# 3. 事务处理

由于实时计算是分布式处理的,系统的不稳定性必然会导致数据的处理有可能出现失败的情况。比如网络的抖动导致数据发送不成功、机器重启导致数据丢失等。在这些情况下,怎么做到数据的精确处理呢?上面提到的几个流计算系统几乎都提供了数据自动 ACK失败重发以及事务信息等机制。

  • 超时时间:由于数据处理是按照批次来进行的,当一批数据处理超时时,会从拓扑的 spout 端重发数据。另外,批次处理的数据量不宜过大,应该增加一个限流的功能(限定一批数据的记录数或者容量等),避免数据处理超时。

  • 事务信息:每批数据都会附带一个事务 ID 的信息,在重发的情况下,让开发者自己根据事务信息去判断数据第一次到达和重发时不同的处理逻辑。

  • 备份机制:开发人员需要保证内存数据可以通过外部存储恢复,因此在计算中用到的中间结果数据需要备份到外部存储中。

上面的这些机制都是为了保证数据的幂等性

# 数据存储

实时任务在运行过程中,会计算很多维度和指标,这些数据需要放在一个存储系统中作为恢复或者关联使用。其中会涉及三种类型的数据:

  • 中间计算结果——在实时应用处理过程中,会有一些状态的保存(比如去重指标的明细数据),用于在发生故障时,使用数据库中的数据恢复内存现场。

  • 最终结果数据——指的是通过 ETL 处理后的实时结果数据,这些数据是实时更新的,写的频率非常高,可以被下游直接使用。

  • 维表数据——在离线计算系统中,通过同步工具导入到在线存储系统中,供实时任务来关联实时流数据。

数据库分为很多种类型,比如关系型数据库、列式数据库、文档数据库等,那么在选择实时任务所使用的数据库时应该注意哪些特征呢?

因为实时任务是多线程处理的,这就意味着数据存储系统必须能够比较好地支持多并发读写,并且延时需要在毫秒级才能满足实时的性能要求。在实践中,一般使用 HBase、Tair、MongoDB 等列式存储系统

由于这些系统在写数据时是先写内存再落磁盘,因此写延时在毫秒级;读请求也有缓存机制,重要的是多并发读时也可以达到毫秒级延时。

但是这些系统的缺点也是比较明显的,以 HBase 为例, 一张表必须要有 rowkey,而 rowkey 是按照 ASCII 码来排序的,这就像关系型数据库的索引一样,rowkey 的规则限制了读取数据的方式。如果业务方需要使用另一种读取数据的方式,就必须重新输出 rowkey 。从这个角度来看,HBase 没有关系型数据库方便。但是 HBase 的一张表能够存储几 TB 甚至几十 TB 的数据,而关系型数据库必须要分库分表才能实现这个量级的数据存储。因此,对于海量数据的实时计算,一般会采用非关系型数据库,以应对大量的多并发读写

下面是在数据统计中表名设计和 rowkey 设计的一些实践经验。

  • 表名设计

设计规则:汇总层标识+数据域+主维度+时间维度

例如:dws_trd_s lr_dtr ,表示汇总层交易数据,根据卖家(sir)主维度 + O 点截至当日(dtr)进行统计汇总。

这样做的好处是,所有主维度相同的数据都放在一张物理表中,避免表数量过多,难以维护。另外,可以从表名上直观地看到存储的是什 么数据内容,方便排查问题。

  • rowkey 设计

设计规则:MD5+主维度+维度标识+子维度1+时间维度+子维度2

例如:卖家 D 的 MD5 前四位 + 卖家 ID + app + 一级类目 ID + ddd + 二级类目 ID。

以 MD5 的前四位作为 rowkey 的第一部分,可以把数据散列,让服务器整体负载是均衡的,避免热点问题。在上面的例子中,卖家 ID 属于主维度,在查数据时是必传的。每个统计维度都会生成一个维度标识,以便在 rowkey 上做区分。

# 数据服务

实时数据落地到存储系统中后,使用方就可以通过统一的数据服务获取到实时数据。比如 OneService ,其好处是:

  • 不需要直连数据库,数据源等信息在数据服务层维护,这样当存储系统迁移时,对下游是透明的。

  • 调用方只需要使用服务层暴露的接口,不需要关心底层取数逻辑的实现。

  • 屏蔽存储系统间的差异,统一的调用日志输出,便于分析和监控下游使用情况。

# 流式数据模型

实时建模跟离线建模非常类似,数据模型整体上分为五层ODS、DWD、DWS、ADS、DIM)。

由于实时计算的局限性,每一层中并没有像离线做得那么宽,维度和指标也没有那么多,特别是涉及回溯状态的指标,在实时数据模型中几乎没有

整体来看,实时数据模型是离线数据模型的一个子集,在实时数据处理过程中,很多模型设计就是参考离线数据模型实现的。

下面从数据分层、多流关联、维表使用这三个方面来说明。

# 1. 数据分层

📌 ODS 层

ODS 层属于操作数据层,是直接从业务系统采集过来的最原始数据,包含了所有业务的变更过程,数据粒度也是最细的

在这一层,实时和离线在源头上是统一的,这样的好处是用同一份数据加工出来的指标,口径基本是统一的,可以更方便进行实时和离线间数据比对。例如:原始的订单变更记录数据、服务器引擎的访问日志。

📌 DWD 层

DWD 层是在 ODS 层基础上,根据业务过程建模出来的实时事实明细层,对于访问日志这种数据(没有上下文关系,并且不需要等待过程的记录),会回流到离线系统供下游使用,最大程度地保证实时和离线数据在 ODS 层和 DWD 层是一致的。例如:订单的支付明细表、退款明细表、用户的访问日志明细表。

📌 DWS 层

订阅明细层的数据后,会在实时任务中计算各个维度的汇总指标。如果维度是各个垂直业务线通用的,则会放在实时通用汇总层,作为通用的数据模型使用。比如电商网站的卖家粒度,只要涉及交易过程,就会跟这个维度相关,所以卖家维度是各个垂直业务的通用维度,其中的汇总指标也是各个业务线共用的。例如:电商数据的几大维度的汇总表(卖家、商品、买家)。

📌 ADS 层

个性化维度汇总层,对于不是特别通用的统计维度数据会放在这一层中,这里计算只有自身业务才会关注的维度和指标,跟其他业务线一般没有交集,常用于一些垂直创新业务中。例如:手机淘宝下面的某个爱逛街、微淘等垂直业务。

📌 DIM 层

实时维表层的数据基本上都是从离线维表层导出来的,抽取到在线系统中供实时应用调用。这一层对实时应用来说是静态的,所有的 ETL 处理工作会在离线系统中完成。维表在实时应用的使用中跟离线稍有区别。例如:商品维表、卖家维表、买家维表、类目维表。

整体的数据流向如下图所示。

其中,ODS 层到 DIM 层的 ETL 处理是在离线系统中进行的,处理完成后会同步到实时计算所使用的存储系统。ODS 层和 DWD 层会放在数据中间件中,供下游订阅使用。而 DWS 层和 ADS 层会落地到在线存储系统中,下游通过接口调用的形式使用。

在每一层中,按照重要性划分为 P0、P1、P2、P3 等级,P0 属于最高优先级保障。根据不同的优先级给实时任务分配不同的计算和存储资源,力求重要的任务可以得到最好的保障。

另外,字段命名、表命名、指标命名是按照 OneData 规范来定义的,以便更好地维护和管理。

# 2. 多流关联

在流式计算中常常需要把两个实时流进行主键关联,以得到对应的实时明细表

在离线系统中两个表关联是非常简单的,因为离线计算在任务启动时已经可以获得两张表的全量数据,只要根据关联键进行分桶关联就可以了

但流式计算不一样,数据的到达是一个增量的过程,并且数据到达的时间是不确定的和无序的,因此在数据处理过程中会涉及中间状态的保存恢复机制等细节问题。

比如 A 表和 B 表使用 ID 进行实时关联,由于无法知道两个表的到达顺序,因此在两个数据流的每条新数据到来时,都需要到另外一张表中进行查找。如 A 表的某条数据到达,到 B 表的全量数据中查找,如果能查找到,说明可以关联上,拼接成一条记录直接输出到下游;但是如果关联不上,则需要放在内存或外部存储中等待,直到 B 表的记录也到达。

多流关联的一个关键点就是需要相互等待,只有双方都到达了,才能关联成功

下面通过订单信息表和支付信息表关联这个例子来说明:

在这个例子中,实时采集两张表的数据,每到来一条新数据时都在内存中的对方表截至当前的全量数据中查找,如果能查找到,则说明关联成功,直接输出;如果没查找到,则把数据放在内存中的自己表数据集合中等待。

此外,不管是否关联成功,内存中的数据都需要备份到外部存储系统中,在任务重启时,可以从外部存储系统中恢复内存数据,这样才能保证数据不丢失。因为在重启时,任务是续跑的,不会重新跑之前的数据

还有,订单记录的变更有可能发生多次(比如订单的多个字段多次更新),在这种情况下,需要根据订单 ID 去重,避免 A 表和 B 表多次关联成功;否则输出到下游就会有多条记录,这样得到的数据是有重复的。

以上是整体的双流关联流程,在实际处理时,考虑到查找数据的性能,实时关联这个步骤一般会把数据按照关联主键进行分桶处理,并且在故障恢复时也根据分桶来进行,以降低查找数据量和提高吞吐量。

# 3. 维表使用

在离线系统中,一般是根据业务分区来关联事实表和维表的,因为在关联之前维表的数据就已经就绪了。

而在实时计算中,关联维表一般会使用当前的实时数据(T)去关联 T-2 的维表数据,相当于在 T 的数据到达之前需要把维表数据准备好,并且一般是一份静态的数据。

实时计算中这么做主要是基于以下几点考虑。

  • 数据无法及时准备好

当到达零点时,实时流数据必须去关联维表(因为不能等待,如果等就失去了实时的特性),而这个时候 T-1 的维表数据一般不能在零点马上准备就绪(因为 T-1 的数据需要在 T 这一天加工生成),因此去关联 T-2 维表,相当于在 T-1 的一天时间里加工好 T-2 的维表数据。

  • 无法准确获取全量的最新数据

维表一般是全量的数据,如果需要实时获取到当天的最新维表数据,则需要 T-1 的数据+当天变更才能获取到完整的维表数据。也就是说,维表也作为一个实时流输入,这就需要使用多流实时关联来实现。但是由于实时数据是无序的并且到达时间不确定,因此在维表关联上有歧义。

  • 数据的无序性

在实时计算中维表关联一般都统一使用 T-2 的数据,这样对于业务来说,起码关联到的维表数据是确定的(虽然维表数据有一定的延时,但是许多业务的维表在两天之间变化是很少的)。

在有些业务场景下,可以关联 T-1 的数据,但 T-1 的数据是不全的。比如在 T-1 的晚上 22:00 点开始对维表进行加工处理,在零点到达之前,有两个小时可以把数据准备好,这样就可以在 T 的时候关联 T-1 的数据了,但是会缺失两个小时的维表变更过程。

此外,由于实时任务是常驻进程的,因此维表的使用分为两种形式。

  • 全量加载

在维表数据较少的情况下,可以一次性加载到内存中,在内存中直接和实时流数据进行关联,效率非常高

缺点是内存一直占用着,并且需要定时更新

例如:类目维表,每天只有几万条记录,在每天零点时全量加载到内存中。

  • 增量加载

维表数据很多,没办法全部加载到内存中,可以使用增量查找和 LRU 过期的形式,让最热门的数据留在内存中。

优点是可以控制内存的使用量;缺点是需要查找外部存储系统,运行效率会降低

例如:会员维表,有上亿条记录,每次实时数据到达时,去外部数据库中查询,并且把查询结果放在内存中,然后每隔一段时间清理一次最近最少使用的数据,以避免内存溢出。

# 大促挑战&保障

# 1. 大促特征

  • 毫秒级延时

  • 洪峰明显

  • 高保障性

  • 公关特性

大促是一场对数据计算的高吞吐量、低延时、高保障性、高准确性的挑战。

# 2. 大促保障

📌 1. 如何进行实时任务优化

以下几点是实时任务优化中经常需要考虑的要素。

  • 独占资源和共享资源的策略

在一台机器中,共享资源池可以被多个实时任务抢占,如果一个任务在运行时 80% 以上的时间都需要去抢资源,这时候就需要考虑给它分配更多的独占资源,避免抢不到 CPU 资源导致吞吐量急剧下降。

  • 合理选择缓存机制,尽量降低读写库次数

内存读写性能是最好的,根据业务的特性选择不同的缓存机制,让最热和最可能使用的数据留在内存中,读写库次数降低后,吞吐量自然就上升了。

  • 计算单元合并,降低拓扑层级

拓扑结构层级越深,性能越差,因为数据在每个节点间传输时,大部分是需要经过序列化和反序列化的,而这个过程非常消耗 CPU 和时间。

  • 内存对象共享,避免字符拷贝

在海量数据处理中,大部分对象都是以字符串形式存在的,在不同线程间合理共享对象,可以大幅降低字符拷贝带来的性能消耗,不过要注意不合理使用带来的内存溢出问题。

  • 在高吞吐量和低延时间取平衡

高吞吐量和低延时这两个特性是一对矛盾体,当把多个读写库操作或者 ACK 操作合并成一个时,可以大幅降低因为网络请求带来的消耗,不过也会导致延时高一些,在业务上衡量进行取舍。

📌 2. 如何进行数据链路保障

实时数据的处理链路非常长(数据同步 → 数据计算 → 数据存储 → 数据服务),每一个环节出现问题,都会导致实时数据停止更新。

为了保障实时数据的可用性,需要对整条计算链路都进行多链路搭建,做到多机房容灾,甚至异地容灾。多机房客灾示意图如下:

由于造成链路问题的情况比较多,并且一般不能在秒级定位到原因,因此会通过工具比对多条链路计算的结果数据,当某条链路出现问题时,它一定会比其他链路计算的值小,并且差异会越来越大。

此时会一键切换到备链路,并且通过推送配置的形式让其秒级生效,所有的接口调用会立刻切换到备链路,对直播大屏完全透明,并且用户也感知不到故障的发生。

📌 3. 如何进行压测

在大促备战中,会对实时链路进行多次压测,主要是模拟 “双 11” 的峰值情况,验证系统是否能够正常运行。压测都是在线上环境中进行的,分为数据压测产品压测

数据压测主要是蓄洪压测,就是把几个小时甚至几天的数据积累下来,并在某个时刻全部放开,模拟 “双11”洪峰流量的情况,这里面的数据是真实的。比如通过把实时作业的订阅数据点位调到几个小时或者几天前,这时候每一批读到的数据都是最多的,对实时计算的压力也最大。

产品压测还细分为产品本身压测前端页面稳定性测试

  • 产品本身压测

收集大屏服务端的所有读操作的 URL ,通过压测平台进行压测流量回放,按照 QPS:500 次/秒的目标进行压测。在压测过程中不断地迭代优化服务端的性能,提升大屏应用处理数据的性能。

  • 前端页面稳定性测试

将大屏页面在浏览器中打开,并进行 8~24 小时的前端页面稳定性测试。监控大屏前端 JS 对客户端浏览器的内存、CPU 等的消耗,检测出前端 JS 内存泄漏等问题并修复,提升前端页面的稳定性。

# 数据服务

# 阿里的数据服务架构演进

基于性能、扩展性和稳定性等方面的要求,阿里不断升级数据服务的架构,依次经历了内部代号为 DWSOA、OpenAPI、SmartDQOneService 的四个阶段,演进过程如下图所示。

# 1. DWSOA

DWSOA 是数据服务的第一个阶段,也就是将业务方对数据的需求通过 SOA 服务的方式暴露出去。由需求驱动,一个需求开发一个或者几个接口,编写接口文档,开放给业务方调用。架构示意图如下:

  • 优点

    • 实现比较简单。
  • 缺点

    • 接口粒度比较粗,灵活性不高,扩展性差,复用率低。随着业务方对数据服务的需求增加,接口的数量也会很快从一位数增加到两位数,从两位数增加到三位数,其维护成本可想而知。

    • 开发效率不高,无法快速响应业务。一个接口从需求开发、测试到最终的上线,整个流程走完至少需要 1 天的时间,即使有时候仅仅是增加一、两个返回字段,也要走一整套流程,所以开发效率比较低,投入的人力成本较高。

# 2. OpenAPI

DWSOA 阶段存在的明显问题,就是烟囱式开发,导致接口众多不好维护,因此需要想办法降低接口的数量。当时我们对这些需求做了调研分析,发现实现逻辑基本上就是从 DB 取数,然后封装结果暴露服务,并且很多接口其实是可以合并的。

OpenAPI 就是数据服务的第二个阶段。具体的做法就是将数据按照其统计粒度进行聚合,同样维度的数据,形成一张逻辑表,采用同样的接口描述。以会员维度为例:把所有以会员为中心的数据做成一张逻辑宽表,只要是查询会员粒度的数据,仅需要调用会员接口即可。通过一段时间的实施,结果表明这种方式有效地收敛了接口数量。

# 3. SmartDQ

然而,数据的维度并没有想象的那么可控,随着时间的推移,大家对数据的深度使用,分析数据的维度也越来越多,当时 OpenAPI 生产已有近 100 个接口;同时也带来大量对象关系映射的维护工作量。

于是,在 OpenAPI 的基础上,再抽象一层,用 DSL(Domain Specific Language ,领域专用语言)来描述取数需求。新做一套 DSL 必然有一定的学习成本,因此采用标准的 SQL 语法,在此基础上做了一些限制和特殊增强,以降低学习成本。

同时也封装了标准 DataSource,可以使用 ORM(Object Relation Mapping,对象关系映射)框架(目前比较主流的框架有 Hibernate、MyBatis 等)来解决对象关系映射问题。

至此,所有的简单查询服务减少到只有一个接口,这大大降低了数据服务的维护成本。

传统的方式查问题需要翻源码,确认逻辑;而 SmartDQ 只需要检查 SQL 的工作量,并且可以开放给业务方通过写 SQL 的方式对外提供服务,由服务提供者自己来维护 SQL,也算是服务走向 DevOps 的一个里程碑吧。

逻辑表虽然在 OpenAPI 阶段就已经存在,但是在 SmartDQ 阶段讲更合适,因为 SmartDQ 把逻辑表的作用真正发挥出来了。SQL 提供者只需关心逻辑表的结构,不需要关心底层由多少物理表组成,甚至不需要关心这些物理表是 HBase 还是 MySQL 的,是单表还是分库分表,因为 SmartDQ 已经封装了跨异构数据源和分布式查询功能。

此外,数据部门字段的变更相对比较频繁,这种底层变更对应用层来说应该算是最糟糕的变更之一了。而逻辑表层的设计很好地规避了这个痛点,只变更逻辑表中物理字段的映射关系,并且即刻生效,对调用方来说完全无感知。

小结

接口易上难下,即使一个接口也会绑定-批人(业务方、接口开发维护人员、调用方)。所以对外提供的数据服务接口一定要尽可能抽象,接口的数量要尽可能收敛,最后在保障服务质量的情况下,尽可能减少维护工作量。

# 4. OneService

第四个阶段是统一的数据服务层(即 OneService)。SmartDQ 其实只满足了简单的查询服务需求。其他的场景还有这么几类:个性化的垂直业务场景、实时数据推送服务、定时任务服务

所以 OneService 主要是提供多种服务类型来满足用户需求,分别是 OneService-SmartDQ、OneService-Lego、OneService-iPush、OneService-uTiming。

  • OneService-Lego

SmartDQ 不能满足个性化的取数业务场景,可以使用 Lego。Lego 采用插件化方式开发服务,一类需求开发一个插件,目前一共生产 5 个插件。为了避免插件之间相互影响,我们将插件做成微服务,使用 Docker 做隔离。

  • OneService-iPush

实时数据服务 iPush 主要提供 WebSocket 和 long polling 两种方式,其应用场景主要是商家端实时直播。

  • OneService-uTiming

uTiming 主要提供即时任务和定时任务两种模式,其主要应用场景是满足用户运行大数据量任务的需求。

# 数据服务最佳实践

# 1. 性能

# (1)资源分配

系统的资源是有限的,如果能合理分配资源,使资源利用最大化,那么系统的整体性能就会上一个台阶。

  • 剥离计算资源

剥离复杂的计算统计逻辑,将其全部交由底层的数据公共层进行处理,只保留核心的业务处理逻辑。

  • 查询资源分配

查询接口分为两种:Get 接口,只返回一条数据;List 接口,会返回多条数据。

一般来说,Get 查询基本都转换为 KV 查询,响应时间比较短,或者说查询代价比较小。而 List 查询的响应时间相对较长,且返回记录数比较多,这就增加了序列化以及网络传输的成本,查询代价肯定会更高一些

假如将 Get、List 请求都放在同一个线程池中进行查询,虽然 Get 请求的真正查询耗时很短,但是会在队列等待上消耗大量的时间,这样整体的 QPS 会很不理想。

为此,我们设计了两个独立的线程池:Get 线程池List 线程池,分别处理 Get 请求和 List 请求,这样就不会因为某些 List 慢查询,而影响到 Get 快查询。系统的 QPS 比之前提升许多。

List 查询的响应时间相对较长,所以 List 线程池设置的最大运行任务数就稍微多一些。另外,由于超时的限制,List 线程池的等待队列不宜过长。具体的参数设置,可以根据压力测试的结果评估出来。后期,也可以根据线上调用日志的统计,比如 List 请求与 Get 请求的比例来进行优化调整。

  • 执行计划优化

(1)查询拆分

接口暴露给调用者的指标都是逻辑字段,调用者不用关注这些逻辑字段对应的是哪张物理表的哪个物理字段。比如调用者调用了 A、B、C 三个指标,这些指标分别在三张物理表中,引擎层会将调用者的请求拆分成三个独立的查询,分别去三张物理表中查询,且这些查询是并发执行的。查询结束后,引擎层会将三个查询的结果汇总至一起返回给调用者,这样最大程度地降低了调用者的调用成本,并能保证查询性能。

(2)查询优化

查询优化,就是分析用户请求中的 SQL 语句,将符合条件的 List 查询转换为 Get 查询,从而提高性能。具体的步骤是:

  • 解析 SQL 语句中的 WHERE 子句,提取出筛选字段以及筛选条件。

  • 假如筛选字段中包含了该逻辑表的所有主键,且筛选条件都为 equal ,则说明主键都已经确定为固定值,返回记录数肯定为 1 条。在这种场景中,List 查询就转换为 Get 查询。

# (2)缓存优化

  • 元数据缓存

在接口查询的过程中,查询引擎需要频繁地调用元数据信息。

这些元数据的总量不大,因此在服务启动时就已经将全量数据加载到本地缓存中,以最大程度地减少元数据调用的性能损耗。

后台对数据生产者的发布信息进行监听,一旦有新的发布,就重新加载一次元数据。不过,这时候的加载与初始化时不同,是一次增量更新,只会加载刚刚修改的元数据

  • 模型缓存

接口查询的输入其实是 DSL,而最终提交给 DB 执行的是物理 SQL在从 DSL 到物理 SQL 的转换过程中,经过了多步解析处理。SmartDQ 的主处理模块的处理步骤如下。

模型缓存,就是将解析后的模型(包括逻辑模型、物理模型)缓存在本地。下次再遇到相似的 SQL 时,直接从缓存中得到解析结果,直接省略了图中虚线框中的步骤,因而节省了 DSL -> SQL 的解析时间。具体做法如下:

  • 对 DSL 进行语法、词法分析,并替换 WHERE 中的常量。比如将 where user_id = 123 替换为 where user_id = ?。

  • 以替换后的语句做 key,去本地缓存中进行查找。如果命中,则提取出缓存中的模型,直接将 SQL 提交给 DB 查询。

  • 如果上一步没有命中,则进行正常的解析处理,并缓存解析后的结果。

需要注意的是,由于模型缓存在本地,为了避免占用太多的内存,需要定期将过期的模型淘汰掉。假如元数据有变更,则缓存中的模型有可能已经失效或者是错误的,因此需要全部清理掉。

  • 结果缓存

在某些场景下,会对查询结果进行缓存,以提高查询性能。比如:

  • 某些查询可能比较复杂,直接查询 DB 响应时间较长。这时可以将结果进行缓存,下次执行相同的查询时,即可直接从缓存中获取结果,省去了 DB 查询这一步耗时操作。

  • 还有一种场景,比如获取某个卖家所属类目的统计指标,一个类目下可能会有十几万个卖家,这些卖家请求的结果肯定是完全一致的。因此,这时将结果放在缓存中,大部分请求都会直接从缓存中得到结果,缓存命中率会非常高。另外,类目的记录数不会太多,这样不会增加太多的额外开销。

当然,并不是所有场景都适合走缓存。

假设有这样的场景:获取某个卖家对应的指标。由于每个卖家只能请求自己的指标,因此就会导致绝大部分请求都需要从 DB 查询,再写入缓存中。这样不仅使得单次请求的成本会提升,而且缓存的记录数会非常大,利用率也非常低。所以,这种场景其实是不太适合走缓存的,直接走 DB 查询是比较合适的。

# (3)查询能力

  • 合并查询

数据产品的有些场景,虽然表面上看只是展现几个数字而己,但是后台的处理逻辑其实并不简单。

比如,展现某一日卖家的支付金额,有个日期选择框可以任意选择日期。日期为今天时,展现的是实时数据(从零点截至当前的成交金额);日期为昨天时,展现的就是离线数据(最近 1 天的成交金额)。

其背后的复杂性在于:

  • 在数据公共层中,实时数据是在流计算平台 Galaxy 上进行计算的,结果保存在 HBase 中;而离线数据的计算和存储都是在 MaxCompute 中进行的。这就造成了实时数据与离线数据存储在两个数据源中,调用者的查询方式完全不同

  • 离线数据的产出时间,取决于上游任务的执行时间,以及当前平台的资源情况。所以其产出时间是无法估算的,有可能 3:00 产出,也有可能延迟到 6:00 。在昨天的离线任务产出之前,其前台展现的数字只能来源于实时数据。

  • 出于对性能和成本的考虑,实时作业做了一些折中,去重时,视情况可能使用一些不精准的去重算法,这就导致实时数据的计算结果与离线数据存在一些差异

综上所述,离线数据最准确,需要优先使用离线数据。如果离线数据还未产出,则改用实时数据

  • 推送服务

有些数据产品需要展现实时指标,为了追求数据的实时性,都是轮询请求最新数据。

轮询的间隔时间设置很重要,如果设置间隔时间较长,用户体验会不太好;如果设置很短,对服务器的请求压力会非常大,从而影响整体性能。另外,这种轮询请求的方式,其实很大部分时间是在浪费资源,因为有可能后台的数据根本没有更新,而前端却一直在请求。

那能不能换种方式呢?

监听数据提供者,新数据产生时能够及时知道,并且告知用户,为此 “推送” 应运而生。推送服务很好地解决了数据更新的实时性问题,同时也减少了对服务器的请求压力。

# 2. 稳定性

# (1)发布系统

  • 元数据隔离

一般的应用都会有三个环境:日常环境、预发环境和线上环境。日常环境用于线下开发测试。预发环境隔离了外部用户的访问,用于在正 式发布前校验即将上线的代码。

为了保障系统的稳定性,根据应用环境设计了三套元数据:日常元数据预发元数据线上元数据

三套元数据分别对应着三个应用环境,每个环境的应用只会访问对应的元数据。此外,会有一个定时任务,定期将预发元数据同步到日常环境。

通过元数据的隔离,使得用户的变更可以在预发环境中进行充分的验证,验证通过后再发布到线上环境中,避免了因用户误操作而导致线上故障,保障了系统的稳定性。

  • 隔离发布

隔离发布,即不同用户的发布不会相互影响。要实现这一点,需要做到:

(1)资源划分

为了做到隔离发布,首先需要确定隔离的最小单元。由于调用者的查询请求最终都会转换成对某张逻辑表的查询,因此我们决定将隔离的粒度控制在逻辑表层面上。

(2)资源独占

当用户开始修改的时候,系统会锁定其正在修改的逻辑表及其下挂的物理表等资源,禁止其他用户修改。当用户正式发布变更后,就会释放锁定的资源,这时其他用户才可以对相关元数据进行修改。

(3)增量更新

用户每次只会修改某张逻辑表的对应元数据,因此发布时引擎是不需要重新加载全量元数据的,只需要加载所发布的逻辑表元数据即可。同理,预发元数据与线上元数据之间的数据同步,也仅仅需要同步用户修改的部分。

# (2)隔离

  • 隔离有以下作用:

    • 将系统划分为若干个独立模块,当某个模块出现问题时,整体功能仍然能保证可用。

    • 可以对系统资源进行有效的管理,从而提高系统的可用性。

  • 机房隔离

    将服务器部署在两个机房中,每个机房独立部署一个集群,且机器数量尽量保持均衡,以实现双机房容灾。当一个机房发生故障时,另一个机房中的应用仍然可以对外服务。同时,需要保障内部调用优先,服务调用同机房优先,最大程度地减少双机房部署带来的网络开销。

  • 分组隔离

    不同调用者的优先级不尽相同,且查询场景也存在一定的差异。所以,可以根据某些条件将调用者进行分层,然后将服务端的机器划分为若干个分组,每个分组都有明确的服务对象和保障等级。即使某个分组出现性能较差的查询,或者有突发大流量涌入,也不会影响其他分组的正常使用。另外,可以动态地调整分组规则,以重新分配每个分组的机器数量,在总体机器数量不变的情况下,实现资源的最大化利用。

# (3)安全限制

对调用者的调用做诸多安全限制,以防止查询消耗大量的资源,或者返回太多的记录。主要体现在以下几点:

  • 最大返回记录数

    数据库的查询强制带上 LIMIT 限制,具体的数值以用户配置为准。

  • 必传字段

    每张逻辑表都会配置主键,并标识哪些字段是调用者必须传入的。这样最终的 SQL 肯定会带上这些字段的限制条件,防止对表做全表扫描。

  • 超时时间

    设置合适的超时时间,以使得超时的查询能及时终止并释放资源,保障系统不会被偶发的超时拖垮。

# (4)监控

  • 调用日志采集

    如果要对调用做监控,首先要保证调用日志的完整性。对于每次调用都进行了采集,采集的信息包括:

    • 基础信息,包括调用时间、接口名、方法名、返回记录数等。

    • 调用者信息,包括调用者应用名、来源IP 地址等。

    • 调用信息,包括调用指标、查询筛选条件等。

    • 性能指标,包括响应时间、是否走缓存等。

    • 错误信息,包括出错原因、错误类型、数据源、错误堆械等。

  • 调用监控

    有了调用日志,就可以监控系统的健康状况,及时发现问题。监控可以从以下几个方面展开:

    • 性能趋势。总体的 QPS 趋势图、RT 趋势图、响应时长区间分布。分组性能统计、单机QPS 统计,以对当前系统容量做评估。

    • 零调用统计。找出最近 N 天无调用的表,进行下线处理,节约成本。

    • 慢 SQL 查找。找出响应时间较长的 SQL,及时进行优化。

    • 错误排查。当系统的调用错误数突增时,能从错误日志中及时发现出错原因、出错的数据源等。

# (5)限流、降级

系统的总体容量,主要是根据平日的性能监控,以及定期的全链路压测评估得出,但是难免会遇到突发流量涌入的情况。此时,系统需要有合适的方式来应对突增流量,以免系统被压垮。

  • 限流

    限流有很多种方法,我们采用的是应用内的 QPS 保护。针对调用者以及数据源等关键角色做了 QPS 阔值控制。也就是说,如果某个调用者的调用量突增,或者对某个数据源的查询流量突增,超过了预设的 QPS 阈值,则后续的请求立即失败返回,不再继续处理。通过快速失败,将超出系统处理能力的流量直接过滤掉,保障了系统的可用性。

  • 降级

    查询引擎底层是支持多种数据源接入的,但是接入的数据源越多,系统就越复杂,出问题的概率也就越大。假设某个数据源突然出现问题,或者某个数据源中的某张表访问超时,那么该如何处理才能保障整体的可用性呢?

    理想的做法肯定是将这些数据源、表全部隔离成独立的模块,单个模块的故障不会引起整体不可用。但是,实际中隔离带来的成本也是比较大的,且有可能造成资源的浪费。

    假如没有隔离措施,所有数据源共享资源,这时候就需要通过降级将故障影响降到最低。

    降级主要有两种做法:

    • 通过限流措施,将 QPS 置为 0,则对应的所有访问全部立即失败,防止了故障的扩散。

    • 通过修改元数据,将存在问题的资源置为失效状态,则重新加载元数据后,对应的访问就全部失败了,不会再消耗系统资源。

# 数据挖掘

当我们从业务系统中能够轻松采集到海量数据时,往往会发现里面的有效数据信息却越来越稀疏,有效数据和无效数据的增长率是不成比例的。因此,如何从海量数据中挖掘出有效信息形成真正的生产力,是所有大数据公司需要面对的共同课题。

数据挖掘技术数据仓储及计算技术的发展是相辅相成的。

基于大数据的企业级数据挖掘需要包含两个要素:

  • 面向机器学习算法的并行计算框架与算法平台

  • 面向企业级数据挖掘的算法资产管理体系

# 数据挖掘算法平台

目前,阿里巴巴已建成一套稳定、高效的算法平台,该平台架构于阿里云 MaxCompute、GPU 等计算集群之上,汇集了阿里巴巴集团大量优质的分布式算法,包括数据处理、特征工程、机器学习算法、文本算法等,可高效地完成海量、亿级维度数据的复杂计算。

此外,平台还提供了一套极易操作的可视化编辑页面,大大降低了数据挖掘的门槛,提高了建模效率。未来还将面向外部客户开放,配合阿里云的其他基础数据设施,为外部企业提供数据挖掘应用的基础能力。

阿里巴巴算法平台的框架和原理如下:

支持海量样本的高维特征训练是算法平台的必备要素,因此计算框架的选择非常重要。业界主流的并行计算框架主要有 MapReduce、MPI、Spark 等。

在阿里巴巴集团内部,基于 MapReduce 与 Hive 的计算己经能解决公司业务 90% 以上的离线数据分析任务。

对于需要频繁进行网络通信、内存消耗高、计算要求快速迭代的算法任务,MPI 无疑是最佳选择。MPI 是一种基于消息传递的并行计算框架,由于没有 IO 操作,性能优于 MapReduce。

因此,阿里巴巴的算法平台选用 MPI 作为基础计算框架,其核心机器学习算法的开发都是基于阿里云 MaxCompute 的 MPI 实现的

MaxCompute MPI 的处理流程如下图所示,与分布式计算系统的原理类似。其中伏羲为阿里云飞天系统的分布式调度系统,女娲为阿里云飞天系统的分布式一致性协同服务系统,盘古为阿里云飞天系统的分布式文件存储系统。

基于 MaxCompute MPI ,目前阿里巴巴的算法平台已经集成了绝大部分业界主流的机器学习算法,这些算法基本可以满足企业级数据挖掘应用的需要。

分类 具体算法
分类算法 LogisticRegression、kNN、GBDT、DTC5.0、Randomforest、linearSVM、nonlinearSVM、NavieBayes、Bayes、Fisher 判别、马氏距离判别、标签传播分裂等
回归算法 LinearRegression、GBDT、LASSO、RidgeRegression、Factorization Machines、XO Boost 等
聚类算法 K-Means、Canopy、PSC 谱聚类、标签传播聚类、EM 聚类等
推荐算法 etrec 协同过滤、SYD 协同过滤、ALS 协同过滤等
深度学习 Word2Vec、Doc2Vec、CNN、DBN、DeepMatchModel 等
其他 PageRank、LOA、pLSA、关联规则、NMF、CRF、SVD、RankSVM、PCA、kcore、sssp、Modularity 计算等

etrec 是阿里巴巴集团搜索算法团队开发的运行于 MaxCompute 上的基于商品的协同过滤算法。

# 数据挖掘中台体系

通常一次数据挖掘的过程包括商业理解、数据准备、特征工程、模型训练、模型测试、模型部署、线上应用及效果反馈等环节。

就数据挖掘的商业场景而言,可以分为两大类应用:个体挖掘应用关系挖掘应用

  • 个体挖掘应用指对单个实体的行为特征进行预测与分析,如预测某商品的销量、划分某行业的价格区间等;

  • 关系挖掘应用指研究多个实体间的关系特征,如商品的相似关系、竞争关系等。

就数据挖掘技术而言,其包含两大要素:数据算法

  • 数据是数据挖掘的起源与挖掘结果最终的承载形式,可以说任何数据挖掘的过程都是从数据里来,回数据里去,源于数据而高于数据;

  • 算法是数据挖掘的神经中枢,通过算法对原始数据进行加工,得到对业务更有价值的数据。

因此,对于数据挖掘中台体系的设计也包含两大块:数据中台算法中台;结合数据挖掘的商业场景,对这两大块的设计又分别从个体挖掘应用和关系挖掘应用两方面进行考虑。

# 1. 挖掘数据中台

在数据挖掘的过程中包含两类数据:特征数据结果数据。比如要预测某商品的销量,那么算法需要的特征变量其实就是特征数据,算法最终输出的商品销量的预测结果就是结果数据。

对于特征数据,在挖掘项目中 80% 的时间可能都是在处理特征,这些特征的提取、清洗、标准化,以及基于业务场景的再组合和二次加工往往是我们工作内容的主体部分。

通过算法生成的结果数据也需要进行合理的分层存储。有的结果非常通用和基础化,可以在很多的业务场景中复用,有的结果则相对个性和场景化,只适用于某个具体的业务和产品,因此需要对结果数据进行合理的分层,有效隔离通用性强和个性化强的结果,这样可以充分发挥通用性强的算法结果的作用,提升它的复用率,减少不必要的重复建设。

因此,阿里巴巴把挖掘数据中台分为三层:特征层(Featural Data Mining Layer, FDM)、中间层应用层(Application-oriented Data Mining Layer, ADM),其中中间层包括个体中间层(Individual Data Mining Layer, IDM)和关系中间层(Relational Data Mining Layer, RDM),如下图所示:

不同数据层的作用有所区别:

  • FDM 层:用于存储在模型训练前常用的特征指标,并进行统一的清洗和去噪处理,提升机器学习特征工程环节的效率。

  • IDM 层:个体挖掘指标中间层,面向个体挖掘场景,用于存储通用性强的结果数据,主要包含商品、卖家、买家、行业等维度的个体数据挖掘的相关指标。

  • RDM 层:关系挖掘指标中间层,面向关系挖掘场景,用于存储通用性强的结果数据,主要包含商品间的相似关系、竞争关系,店铺间的相似关系、竞争关系等。

  • ADM 层:用来沉淀比较个性偏应用的数据挖掘指标,比如用户偏好的类目、品牌等,这些数据已经过深度的加工处理,满足某一特点业务或产品的使用。

# 2. 挖掘算法中台

算法是数据挖掘的神经中枢,算法使用的方式往往决定应用的成败。理解算法的原理不难,难的是在理解原理的基础上如何能结合业务合理地运用算法。很多开发者对算法了如指掌,但发现结合实际的业务仍然会有很多困难,甚至会踩很多地雷或陷阱。

阿里巴巴数据挖掘算法中台建设的目的在于从各种各样的挖掘场景中抽象出有代表性的几类场景,并形成相应的方法论和实操模板

按照个体挖掘应用和关系挖掘应用的分类方式,可以抽象出常见的几类数据挖掘应用场景:

  • 在个体挖掘应用中,消费者画像业务指标预测是两类非常有代表性的场景;

  • 在关系挖掘应用中,相似关系竞争关系是两类非常通用的关系挖掘应用,在此基础上构建的推荐系统竞争分析系统,则是电商领域持续关注的两大热门话题。

# 用户画像

对用户有深刻的理解是网站推荐、企业经营制胜的重要一环。阿里全域数据提供了足够的数据基础,正是基于用户网购、搜索和娱乐影音等行为的数据洞察,可以利用数据分析辅以算法的视角对用户进行 全方位的特征刻画。

用户画像即是为用户打上各种各样的标签,如年龄、性别、职业、商品品牌偏好、商品类别偏好等。这些标签的数目越丰富,标签越细化,对用户的刻画就越精准。

一般而言,用户画像可以分为基础属性、购物偏好、社交关系、财富属性等几大类。

# 大数据领域建模

# 为什么需要数据建模

数据模型就是数据组织和存储方法,它强调从业务、数据存取和使用角度合理存储数据。

Linux 的创始人 Torvalds 有一段关于 “什么才是优秀程序员” 的话:“烂程序员关心的是代码,好程序员关心的是数据结构和它们之间的关系”,其阐述了数据模型的重要性。

有了适合业务和基础数据存储环境的模型,那么大数据就能获得以下好处。

  • 高性能:良好的数据模型能帮助我们快速查询所需要的数据,减少数据的 I/O 吞吐。

  • 低成本:良好的数据模型能极大地减少不必要的数据冗余,也能实现计算结果复用,极大地降低大数据系统中的存储和计算成本。

  • 高效率:良好的数据模型能极大地改善用户使用数据的体验,提高使用数据的效率。

  • 高质量:良好的数据模型能改善数据统计口径的不一致性,减少数据计算错误的可能性。

因此,大数据系统需要数据模型方法来帮助更好地组织和存储数据,以便在性能、成本、效率和质量之间取得最佳平衡。

# 关系数据库系统和数据仓库

E.F.Codd 是关系数据库的鼻祖,他首次提出了数据库系统的关系模型,开创了数据库关系方法和关系数据理论的研究。

随着一大批大型关系数据库商业软件(如 Oracle、lnformix、DB2 等)的兴起,现代企业信息系统几乎都使用关系数据库来存储、加工和处理数据。

数据仓库系统也不例外,大量的数据仓库系统依托强大的关系数据库能力存储和处理数据,其采用的数据模型方法也是基于关系数据库理论的

虽然近年来大数据的存储和计算基础设施在分布式方面有了飞速的发展,NoSQL 技术也曾流行一时,但是不管是 Hadoop 、Spark 还是阿里巴巴集团的 MaxCompute 系统,仍然在大规模使用 SQL 进行数据的加工和处理,仍然在用 Table 存储数据,仍然在使用关系理论描述数据之间的关系,只是在大数据领域,基于其数据存取的特点在关系数据模型的范式上有了不同的选择而已。

# 从 OLTP 和 OLAP 系统的区别看模型方法论的选择

OLTP 系统通常面向的主要数据操作是随机读写,主要采用满足 3NF 的实体关系模型存储数据,从而在事务处理中解决数据的冗余和一致性问题

OLAP 系统面向的主要数据操作是批量读写,事务处理中的一致性不是 OLAP 所关注的,其主要关注数据的整合,以及在一次性的复杂大数据查询和处理中的性能,因此它需要采用一些不同的数据建模方法。

# 典型的数据仓库建模方法论

# 1. ER 模型

数据仓库之父 Bill Inmon (opens new window) 提出的建模方法是从全企业的高度设计一个 3NF 模型,用实体关系(Entity Relationship, ER)模型描述企业业务,在范式理论上符合 3NF。他所倡导的建模方法的出发点是,减少数据冗余性,保证数据的一致性

数据仓库中的 3NF 与 OLTP 系统中的 3NF 的区别在于,它是站在企业角度面向主题的抽象,而不是针对某个具体业务流程的实体对象关系的抽象。其具有以下几个特点:

  • 需要全面了解企业业务和数据。

  • 实施周期非常长。

  • 对建模人员的能力要求非常高。

采用 ER 模型建设数据仓库模型的出发点是整合数据,将各个系统中的数据以整个企业角度按主题进行相似性组合和合并,并进行一致性处理,为数据分析决策服务,但是并不能直接用于分析决策

其建模步骤分为三个阶段。

  • 高层模型:一个高度抽象的模型,描述主要的主题以及主题间的关系,用于描述企业的业务总体概况。

  • 中层模型:在高层模型的基础上,细化主题的数据项。

  • 物理模型(也叫底层模型):在中层模型的基础上,考虑物理存储,同时基于性能和平台特点进行物理属性的设计,也可能做一些表的合并、分区的设计等。

ER 模型在实践中最典型的代表是 Teradata 公司基于金融业务发布的 FS-LDM(Financial Services Logical Data Model),它通过对金融业务的高度抽象和总结,将金融业务划分为 10 大主题,并以设计面向金融仓库模型的核心为基础,企业基于此模型做适当调整和扩展就能快速落地实施。

比如,下面是一个统计 2020 年各个国家的销售总额的例子。

  • 时间范围:2020

  • 维度值:国家

  • 度量值:销售总额

从图中可以看出,较为松散、零碎,物理表数量多。这种这种模型并不适合直接用于分析统计。3NF 模型导致蜘蛛网的关系,对于 BI 系统带来复杂性和查询性能低下。

# 2. 维度模型

维度模型是数据仓库领域的 Ralph Kimball (opens new window) 大师所倡导的,他的 《The Data Warehouse Toolkit: The Complete Guide to Dimensional Modeling》 是数据仓库工程领域最流行的数据仓库建模的经典。

维度模型通过事实维度表示业务数据。

事实通常对应业务过程,而维度通常对应业务过程发生时所处的环境。

以埋点为例:

  • 行为——事实,从收集的各种行为而来

  • 环境——维度,从收集各个行为所处的环境信息而来

何人何时何地(维度)做了什么事(事实)

维度建模从分析决策的需求出发构建模型,为分析需求服务,因此它重点关注用户如何更快速地完成需求分析,同时具有较好的大规模复杂查询的响应性能。

其典型的代表是星形模型,以及在一些特殊场景下使用的雪花模型

其设计分为以下几个步骤:

  • 选择需要进行分析决策的业务过程。业务过程可以是单个业务事件,比如交易的支付、退款等;也可以是某个事件的状态,比如当前的账户余额等;还可以是一系列相关业务事件组成的业务流程,具体需要看我们分析的是某些事件发生情况,还是当前状态,或是事件流转效率。

  • 选择粒度。在事件分析中,我们要预判所有分析需要细分的程度,从而决定选择的粒度。粒度是维度的一个组合。

  • 识别维表。选择好粒度之后,就需要基于此粒度设计维表,包括维度属性,用于分析时进行分组和筛选。

  • 选择事实。确定分析需要衡量的指标。

跟前面的 ER 模型相比,这个维度模型:

  1. Product 把子类、大类的 id 信息冗余到产品中,且把类名也冗余(退化)

  2. Location 把国家 id 和国家名冗余起来(退化)

  3. Date 也是一样退化

# 3. Data Vault 模型

Data Vault 是 Dan Linstedt 发起创建的一种模型,它是 ER 模型的衍生,其设计的出发点也是为了实现数据的整合,但不能直接用于数据分析决策。

它强调建立一个可审计的基础数据层,也就是强调数据的历史性、可追溯性和原子性,而不要求对数据进行过度的一致性处理和整合;同时它基于主题概念将企业数据进行结构化组织,并引入了更进一步的范式处理来优化模型,以应对源系统变更的扩展性。

Data Vault 模型由以下几部分组成。

  • Hub:是企业的核心业务实体,由实体 key、数据仓库序列代理键、装载时间、数据来源组成。

  • Link:代表 Hub 之间的关系。这里与 ER 模型最大的区别是将关系作为一个独立的单元抽象,可以提升模型的扩展性。它可以直接描述1:1、1:n 和 n:n 的关系,而不需要做任何变更。它由 Hub 的代理键、装载时间、数据来源组成。

  • Satellite:是 Hub 的详细描述内容,一个 Hub 可以有多个 Satellite。它由 Hub 的代理键、装载时间、来源类型、详细的 Hub 描述信息组成。

Data Vault 模型 ER 模型更容易设计和产出,它的 ETL 加工可实现配置化。通过 Dan Linstedt 的比喻更能理解 Data Vault 的核心思想:Hub 可以想象成人的骨架,那么 Link 就是连接骨架的韧带,而 Satellite 就是骨架上面的血肉。

# 4. Anchor 模型

Anchor 对 Data Vault 模型做了进一步规范化处理,其核心思想是所有的扩展只是添加而不是修改,因此将模型规范到 6NF,基本变成了 k-v 结构化模型。

Anchor 模型的组成如下。

  • Anchors:类似于 Data Vault 的 Hub,代表业务实体,且只有主键。

  • Attributes:功能类似于 Data Vault 的 Satellite ,但是它更加规范化,将其全部 k-v 结构化,一个表只有一个 Anchors 的属性描述。

  • Ties:就是 Anchors 之间的关系,单独用表来描述,类似于 Data Vault 的 Link ,可以提升整体模型关系的扩展能力。

  • Knots:代表那些可能会在多个 Anchors 中公用的属性的提炼,比如性别、状态等这种枚举类型且被公用的属性。

在上述四个基本对象的基础上,又可以细划分为历史的和非历史的,其中历史的会以时间戳加多条记录的方式记录数据的变迁历史。

Anchor 模型的创建者以此方式来获取极大的可扩展性,但是也会增加非常多的查询 join 操作。创建者的观点是,数据仓库中的分析查询只是基于一小部分字段进行的,类似于列存储结构,可以大大减少数据扫描,从而对查询性能影响较小。一些有数据表裁剪(Table Elimination)特性的数据库如 MariaDB 的出现,还会大量减少 join 操作。但是实际情况是不是如此,还有待商榷。

# 阿里巴巴的数据模型设计

阿里巴巴的数据团队把表数据模型分为三层:操作数据层(ODS)、公共维度模型层(CDM)应用数据层(ADS),其中公共维度模型层包括明细数据层(DWD)汇总数据层(DWS)

操作数据层(ODS):把操作系统数据几乎无处理地存放在数据仓库系统中

公共维度模型层(CDM):存放明细事实数据、维表数据及公共指标汇总数据,其中明细事实数据、维表数据一般根据 ODS 层数据加工生成;公共指标汇总数据一般根据维表数据和明细事实数据加工生成。

CDM 层又细分为 DWD 层和 DWS 层,分别是明细数据层和汇总数据层,采用维度模型方法作为理论基础,更多地采用一些维度退化手法,将维度退化至事实表中,减少事实表和维表的关联,提高明细数据表的易用性;同时在汇总数据层,加强指标的维度退化,采取更多的宽表化手段构建公共指标数据层,提升公共指标的复用性,减少重复加工。

应用数据层(ADS):存放数据产品个性化的统计指标数据,根据 CDM 层与 ODS 层加工生成。

# 阿里巴巴数据模型实践

阿里巴巴的数据仓库模型建设经历了多个发展阶段。

# 1. 完全应用驱动时代

阿里巴巴的第一代数据仓库系统构建在 Oracle 上,数据完全以满足报表需求为目的,将数据以与源结构相同的方式同步到 Oracle(称作 ODS 层),数据工程师基于 ODS 数据进行统计,基本没有系统化的模型方法体系,完全基于对 Oracle 数据库特性的利用进行数据存储和加工,部分采用一些维度建模的缓慢变化维方式进行历史数据处理。这时候的数据架构只有两层,即 ODS + DSS。

# 2. MPP 架构体系的 Greenplum

随着阿里巴巴业务的快速发展,数据量也在飞速增长,性能成为一个较大的问题,因此引入了当时 MPP 架构体系的 Greenplum,同时阿里巴巴的数据团队也在着手进行一定的数据架构优化,希望通过一些模型技术改变烟囱式的开发模型,消除一些冗余,提升数据的一致性。

来自传统行业的数据仓库工程师开始尝试将工程领域比较流行的 ER 模型+维度模型方式应用到阿里巴巴集团,构建出一个四层的模型架构,即 ODL(操作数据层)+ BDL(基础数据层)+ IDL(接口数据层)+ ADL(应用数据层)。

ODL 和源系统保持一致;BDL 希望引人 ER 模型,加强数据的整合,构建一致的基础数据模型;IDL 基于维度模型方法构建集市层;ADL 完成应用的个性化和基于展现需求的数据组装。

在此阶段也得到了一个经验:在不太成熟、快速变化的业务面前,构建 ER 模型的风险非常大,不太适合去构建 ER 模型。

# 3. 数据公共层

随着以 Hadoop 为代表的分布式存储计算平台的快速发展,阿里巴巴在拥抱分布式计算平台的同时,也开始建设自己的第三代模型架构,选择以 Kimball 的维度建模为核心理念的模型方法论,同时对其进行了一定的升级和扩展,构建了阿里巴巴的公共层模型数据架构体系。

数据公共层建设的目的是着力解决数据存储和计算的共享问题。

阿里巴巴数据公共层建设的指导方法是一套统一化的集团数据整合及管理的方法体系(在内部这一体系称为 “OneData”),其包括一致性的指标定义体系、模型设计方法体系以及配套工具。

# 维度设计

# 维度的基本概念

维度是维度建模的基础和灵魂。在维度建模中,将度量称为 “事实” ,将环境描述为 “维度”,维度是用于分析事实所需要的多样环境。维度模型就是通过事实和维度表示业务数据。例如,在分析交易过程时,可以通过买家、卖家、商品和时间等维度描述交易发生的环境。

维度所包含的表示维度的列,称为维度属性维度属性是查询约束条件、分组和报表标签生成的基本来源,是数据易用性的关键。例如,在查询请求中,获取某类目的商品、正常状态的商品等,是通过约束商品类目属性和商品状态属性来实现的;统计淘宝不同商品类目的每日成交金额,是通过商品维度的类目属性进行分组的;我们在报表中看到的类目、BC 类型(B 指天猫,C 指集市)等,都是维度属性。所以维度的作用一般是查询约束、分类汇总以及排序等。

维度使用主键标识其唯一性,主键也是确保与之相连的任何事实表之间存在引用完整性的基础。

主键有两种:代理键自然键,它们都是用于标识某维度的具体值。但代理键是不具有业务含义的键, 一般用于处理缓慢变化维;自然键是具有业务含义的键

比如商品,在 ETL 过程中,对于商品维表的每一行,可以生成一个唯一的代理键与之对应;商品本身的自然键可能是商品 ID 等。其实对于前台应用系统来说,商品 ID 是代理键;而对于数据仓库系统来说,商品 ID 则属于自然键。

# 维度表设计方法

  1. 选择维度或新建维度。

  2. 确定主维表和相关维表。此处的主维表一般是 ODS 表,直接与业务系统同步。

  3. 确定维度属性。本步骤主要包括两个阶段,其中第一个阶段是从主维表中选择维度属性或生成新的维度属性;第二个阶段是从相关维表中选择维度属性或生成新的维度属性。

维度表主要包含一个主键维度属性

  • 主键:

    • 维度表的粒度通常与主维表相同
  • 维度属性:

    • 尽可能生成丰富的维度属性

    • 尽可能多地给出包括一些富有意义的文字性描述,一般可以编码和文字共存

    • 区分数值型属性和事实

    • 尽量沉淀出通用的维度属性

# 规范化和反规范化

将维度的属性层次实例化为一系列维度,而不是单一的维度的操作成为规范化;将维度的属性层次合并到单个维度中的操作称为反规范化

在设计维度表时,如果对其进行规范化,得到的维度模型称为雪花模型,如果对其进行反规范化,得到的模型称为星型模型

除此之外,还有星座模型

  • 多个星型模型或者雪花模型组合在一起,就是星座模型。实际工作中,大部分是星座模型。

  • 多个事实表,它们公用一些维度表,所以就组成星座模型。

大多数联机事务处理系统(OLTP)的底层数据结构在设计时采用规范化技术,通过规范化处理将重复属性移至其自身所属的表中,删除冗余数据。这种方法用在 OLTP 系统中可以有效避免数据冗余导致的不一致性。

而对于联机分析处理系统(OLAP)来说,数据是稳定的,不存在 OLTP 系统中所存在的问题。分析系统的主要目的是用于数据分析和统计,如何更方便用户进行统计分析决定了分析系统的优劣。采用雪花模式,用户在统计分析的过程中需要大量的关联操作,使用复杂度高,同时查询性能很差;而采用反规范化处理,则方便、易用且性能好。

# 全量表和拉链表

事实表是不会变的,但是维度是会变化的,所以我们要考虑如何在数仓中保留维度的历史信息

通常有两种方法:

  • 全量快照表

    • 目的是为了和历史事实关联
  • 拉链表

    • 相当于对全量快照表的压缩(zip)

    • 适用于数据变化频率不高的维度(缓慢变化维

    • 插入新的记录时【结束日期】=最大值,同时更新旧记录的【结束日期】=今天

如何使用拉链表

# 维度退化

维度直接写在事实表,不需要一张表,这个就是维度退化,比如支付类型、日期等。

与其他存储在维表中的维度一样,退化维度也可以用来进行事实表的过滤查询、实现聚合操作等。

# 多值维度

事实表中一条记录在某个维度表中有多条记录与之对应,称为多值维度

应对多值维度的方法有:

# 多值属性

维表中的某个属性同时有多个值,称之为多值属性,例如商品维度的平台属性和销售属性,每个商品均有多个属性值。

应对多值属性的方法有:

  • 将多值属性放到一个字段,该字段内容为 key1:value1, key2:value2 的形式,json 格式也可以

  • 或者将多值属性放到多个字段,但只适用于个数固定;而且无法通用。比如手机、大米就无法放到同一个维度表,因为它的维度属性不一样

# 维度变化

  • 缓慢变化维

  • 快照维表

  • 极限存储

  • 微型维度

# 特殊维度

  • 递归层次

  • 行为维度

  • 多值维度

  • 多值属性

  • 杂项维度

# 维度整合

先来看数据仓库的定义:

数据仓库是一个面向主题的集成的非易失的随时间变化的数据集合,用来支持管理人员的决策。其中集成是数据仓库的四个特性中最重要的一个。

数据仓库的重要数据来源是大量的、分散的面向应用的操作型环境。不同的应用在设计过程中,可以自由决策,主要满足本应用的需求,很少会考虑和其他系统进行数据集成。

数据由面向应用的操作型环境进入数据仓库后,需要进行数据集成。将面向应用的数据转换为面向主题的数据仓库数据,本身就是一种集成。

维表的整合有两种表现形式。

  • 垂直整合,即不同的来源表包含相同的数据集,只是存储的信息不同。

  • 水平整合,即不同的来源表包含不同的数据集,不同子集之间无交叉,也可以存在部分交叉。

有整合就有拆分,维度的拆分也有两种表现形式。

  • 水平拆分

    维度通常可以按照类别或类型进行细分。不同分类的商品,其维度属性可能相同,也可能不同。

    如何设计维度?针对此问题,主要有两种解决方案:

    • 方案 1 是将维度的不同分类实例化为不同的维度,同时在主维度中保存公共属性

    • 方案 2 是维护单一维度,包含所有可能的属性

    选择哪种方案?在数据模型设计过程中需要考虑的因素有很多,基本不可能满足各个特性指标的最优化。在设计过程中需要重点考虑以下三个原则。

    • 扩展性:当源系统、业务逻辑变化时,能通过较少的成本快速扩展模型,保持核心模型的相对稳定性。软件工程中的高内聚、低耦合的思想是重要的指导方针之一。

    • 效能:在性能和成本方面取得平衡。通过牺牲一定的存储成本,达到性能和逻辑的优化。

    • 易用性:模型可理解性高、访问复杂度低。用户能够方便地从模型中找到对应的数据表,并能够方便地查询和分析。

    根据数据模型设计思想,在对维度进行水平拆分时,主要考虑如下两个依据。

    • 第一个依据是维度的不同分类的属性差异情况。当维度属性随类型变化较大时,将所有可能的属性建立在一个表中是不切合实际的,也没有必要这样做,此时建议采用方案 1。定义一个主维度用于存放公共属性;同时定义多个子维度,其中除了包含公共属性外,还包含各自的特殊属性。

    • 第二个依据是业务的关联程度。两个相关性较低的业务,耦合在一起弊大于利,对模型的稳定性和易用性影响较大。

  • 垂直拆分

    维度属性的丰富程度直接决定了数据仓库的能力。在进行维度设计时,依据维度设计的原则,尽可能丰富维度属性,同时进行反规范化处理。

    对于由于维度分类的不同而存在特殊的维度属性的问题,可以通过水平拆分的方式来解决。

    而对于某些维度属性的来源表产出时间较早,而某些维度属性的来源表产出时间较晚;或者某些维度属性的热度高、使用频繁,而某些维度属性的热度低、较少使用;或者某些维度属性经常变化,而某些维度属性比较稳定的问题,在 “水平拆分” 中提到的模型设计的三个原则同样适合解决此问题。

    出于扩展性产出时间易用性等方面的考虑,设计主从维度。主维表存放稳定、产出时间早、热度高的属性;从维表存放变化较快、产出时间晚、热度低的属性。

# 一致性维度和交叉探查

构建企业级数据仓库不可能一蹦而就,一般采用迭代式的构建过程。而单独构建存在的问题是形成独立型数据集市,导致严重的不一致性。

Kimball 的数据仓库总线架构提供了一种分解企业级数据仓库规划任务的合理方法,通过构建企业范围内一致性维度和事实来构建总线架构。

数据仓库总线架构的重要基石之一就是一致性维度。维度一致性的几种表现形式如下:

  • 共享维表

  • 一致性上卷,其中一个维度的维度属性是另一个维度的维度属性的子集,且两个维度的公共维度属性结构和内容相同。

  • 交叉属性,两个维度具有部分相同的维度属性。

在针对不同数据域进行迭代构建或并行构建时,存在很多需求是对于不同数据域的业务过程或者同一数据域的不同业务过程合并在一起观察。将不同数据域的商品的事实合并在一起进行数据探查,如计算转化率等,称为交叉探查

如果不同数据域的计算过程使用的维度不一致,就会导致交叉探查存在问题。当存在重复的维度,但维度属性或维度属性的值不一致时,会导致交叉探查无法进行或交叉探查结果错误。导致交叉探查的形式有很多种,但基本可以划分为维度格式和内容不一致两种类型。

# 事实表设计

事实表作为数据仓库维度建模的核心,紧紧围绕着业务过程来设计,通过获取描述业务过程的度量来表达业务过程,包含了引用的维度和与业务过程有关的度量。

事实表中一条记录所表达的业务细节程度被称为粒度。应该尽可能选择最细粒度,保证灵活性。通常粒度可以通过两种方式来表述:

  • 一种是维度属性组合所表示的细节程度;

  • 一种是所表示的具体业务含义。

如何确定业务过程有哪些维度不是由需求决定的,而是由业务中的业务逻辑决定的。

应根据业务逻辑尽可能多的确认相关维度。维度的丰富程度就决定了维度模型能够支持的指标丰富程度。

# 事实的类型

事实指的是每个业务过程的度量值,一般为整型或浮点型的十进制数值,比如:次数、个数、件数、金额等。

可加性半可加性不可加性三种类型。

  • 可加性事实是指可以按照与事实表关联的任意维度进行汇总。

  • 半可加性事实只能按照特定维度汇总,不能对所有维度汇总,比如库存可以按照地点和商品进行汇总,而按时间维度把一年中每个月的库存累加起来则毫无意义。

  • 还有一种度量完全不具备可加性,比如比率型事实。对于不可加性事实可分解为可加的组件来实现聚集。

# 事实表的类型

事实表有三种类型:事务事实表周期快照事实表累积快照事实表

  • 事务事实表用来描述业务过程,跟踪空间或时间上某点的度量事件,保存的是最原子的数据,也称为 “原子事实表“。

    • 最细粒度,方便灵活使用

    • 一个业务过程一个事务事实表

  • 周期快照事实表以具有规律性的、可预见的时间间隔记录事实,时间间隔如每天、每月、每年等。

    • 主要用于分析一些存量型(例如商品库存,账户余额)或者状态型(空气温度,行驶速度)指标

    • 周期性的全量采集

    • 对应一个或者多个业务过程,影响到余额有两个业务过程,影响速度的只有一个过程

    • 采样周期通常选择每日,所以粒度包含采样周期

  • 累积快照事实表用来表述过程开始和结束之间的关键步骤事件,覆盖过程的整个生命周期,通常具有多个日期字段来记录关键时间点,当过程随着生命周期不断变化时,记录也会随着过程的变化而被修改。

    • 应对:多事务关联统计

    • 对应一个业务流程,包含多个业务过程

    • 会影响到度量值和业务过程,可以放到一个事实表中

在实际使用过程中,一些业务过程可能只需要一种事实表,而另外一些业务过程可能需要两种或三种事实表。三种事实表相互补充,给出业务的完整描述。

补充

  1. 存量型指标

假设统计指标:统计截至当日的各用户虚拟货币余额。加、减分别是两个业务过程,要计算余额就必须两个事实表统计再互减,效率低。所以需要业务中把库存或余额计算好,定期同步一份全量数据到数据仓库

  1. 多事务关联统计

假设统计指标:最近 30 天,用户下单到支付的时间间隔的平均值。传统要 join 两张大表:下单事务事实表、支付事务事实表。

# 事实表设计原则

  • 原则 1:尽可能包含所有与业务过程相关的事实

    事实表设计的目的是为了度量业务过程,所以分析哪些事实与业务过程有关是设计中非常重要的关注点。在事实表中应该尽量包含所有与业务过程相关的事实,即使存在冗余,但是因为事实通常为数字型,带来的存储开销也不会很大。

  • 原则 2:只选择与业务过程相关的事实

    在选择事实时,应该注意只选择与业务过程有关的事实。比如在订单的下单这个业务过程的事实表设计中,不应该存在支付金额这个表示支付业务过程的事实。

  • 原则 3:分解不可加性事实为可加的组件

    对于不具备可加性条件的事实,需要分解为可加的组件。比如订单的优惠率,应该分解为订单原价金额与订单优惠金额两个事实存储在事实表中。

  • 原则 4:在选择维度和事实之前必须先声明粒度

    粒度的声明是事实表设计中不可忽视的重要一步,粒度用于确定事实表中一行所表示业务的细节层次,决定了维度模型的扩展性,在选择维度和事实之前必须先声明粒度,且每个维度和事实必须与所定义的粒度保持一致。

    在设计事实表的过程中,粒度定义得越细越好,建议从最低级别的原子粒度开始,因为原子粒度提供了最大限度的灵活性,可以支持无法预期的各种细节层次的用户需求。

    在事实表中,通常通过业务描述来表述粒度,但对于聚集性事实表的粒度描述,可采用维度或维度属性组合的方式。

  • 原则 5:在同一个事实表中不能有多种不同粒度的事实

  • 原则 6:事实的单位要保持一致

    对于同一个事实表中事实的单位,应该保持一致。比如原订单金额、订单优惠金额、订单运费金额这三个事实,应该采用一致的计量单位,统一为元或分,以方便使用。

  • 原则 7:对事实的 null 值要处理

    在数据库中 null 值对常用数字型字段的 SQL 过滤条件都不生效,比如大于、小于、等于、大于或等于、小于或等于,建议用零值填充。

  • 原则 8:使用退化维度提高事实表的易用性

# 事实表设计方法

在 Kimball 所著的 《The Data Warehouse Toolkit: The Definitive Guide to Dimensional Modeling》一书中,对于维度模型设计采用四步设计方法:选择业务过程声明粒度确定维度确定事实

阿里巴巴基于这四步维度建模方法,做了进一步的改进。

  • 选择业务过程及确定事实表类型。

  • 声明粒度。

  • 确定维度。

  • 确定事实。

  • 冗余维度。

# 数仓设计

# 数仓分层

  • DWD、DIM 才是使用维度建模理论构建的,面向业务过程。

  • DWS:公共的、中间的计算结果,它存在不是必须,是为了优化汇总,避免重复计算,是被 ADS 驱动的,被需求驱动。

  • ODS:贴源层,原始数据层,操作数据层。

# 数仓构建流程

  • 业务分析 -> 业务总线矩阵 -> 维度模型 DWD、DIM(【维度模型】方法论

  • 需求分析 -> 指标体系 -> 汇总模型 DWS(【指标体系】需求分析方法论

  • 数据调研时是初步的需求分析,明确统计指标时是深入的需求分析,使用方法论是指标体系,得到公共的派生指标放到 DWS,也就是公共汇总层。

具体实践过程如下:

# 1. 数据调研

# (1)业务调研

熟悉业务流程、熟悉业务数据,将数据变化(包括埋点日志和业务数据表)与业务过程对应起来。

# (2)需求分析

明确需求所需的业务过程维度,可以填写一个表格进行梳理。

需求(指标) 业务过程 维度

# 2. 明确数据域

数据仓库模型设计除横向的分层外,通常也需要根据业务情况进行纵向划分数据域。划分数据域的意义是便于数据的管理和应用。数仓中可以按数据域分目录,方便管理,快速找到数据集。

实际就是分到事实表(DWD 层),维度层是不需要分数据域,DWS 层也可以分数据域。

可以根据业务过程或者部门进行划分。以下就是按业务过程分的:

# 3. 构建业务总线矩阵

一个业务过程对应维度模型中一张事务型事实表,一个维度则对应维度模型中的一张维度表。所以构建业务总线矩阵的过程就是设计维度模型的过程

按照事务型事实表的设计流程,选择业务过程 -> 声明粒度 -> 确认维度 -> 确认事实,得到的最终的业务总线矩阵如下。

注意

  1. 有些维度可能退化到事实表,这些维度不需要维度表。

  2. 总线矩阵中通常只包含事务型事实表,另外两种类型的事实表需单独设计。

# 4. 明确统计指标

这一步就是进行指标分析,建立指标体系,也可以说需求分析。

构建指标体系的主要意义就是指标定义标准化,所有指标的定义,都必须遵循同一套标准,这样能有效的避免指标定义存在歧义,指标定义重复等问题。

标准化后就可以平台化,指标体系也是一套需求分析的方法论!

# (1)原子指标

原子指标包含三要素:业务过程度量值聚合逻辑。例如订单总额就是一个典型的原子指标,其中的业务过程为用户下单、度量值为订单金额,聚合逻辑为 sum() 求和。

原子指标只是用来辅助定义指标一个概念,通常不会对应有实际统计需求与之对应,数据集上也没有原子指标。

# (2)派生指标

派生指标基于原子指标而来。

当统计需求足够多时,必然会出现部分统计需求对应的派生指标相同的情况。这些公共的派生指标统一保存在数据仓库的 DWS 层。

# (3)衍生指标

衍生指标是在一个或多个派生指标的基础上,通过各种逻辑运算复合而成的。例如比率、比例等类型的指标。

衍生指标也会对应实际的统计需求。

# 5. 维度模型设计(DWD、DIM)

维度模型的设计参照上述得到的业务总线矩阵即可。事实表存储在 DWD 层,维度表存储在 DIM 层。

# 6. 公共汇总模型设计(DWS)

汇总模型的设计参考上述整理出的指标体系(主要是派生指标)即可。

一张 DWS 表通常包含业务过程相同统计周期相同统计粒度相同的多个派生指标。

注意,最近 1/7/30 日,这是三个不同的周期,所以需要分三张 DWS。

汇总表与事实表的对应关系如下:

  • 粒度相同:统计结果的结构相同,主键就是粒度。

  • 业务过程、统计周期相同:依赖同样的事实表,一次即可计算出来。

# 相关术语解释

名词术语 解释
数据域 指面向业务分析,将业务过程或者维度进行抽象的集合。其中,业务过程可以概括为一个个不可拆分的行为事件,在业务过程之下,可以定义指标;维度是指度量的环境,如买家下单事件,买家是维度。为保障整个体系的生命力,数据域是需要抽象提炼,并且长期维护和更新的,但不轻易变动。在划分数据域时,既能涵盖当前所有的业务需求,又能在新业务进入时无影响地被包含进已有的数据域中和扩展新的数据域
业务过程 指企业的业务活动事件,如下单、支付、退款都是业务过程。请注意,业务过程是一个不可拆分的行为事件,通俗地讲,业务过程就是企业活动中的事件
时间周期 用来明确数据统计的时间范用或者时间点,如最近 30 天、自然周、截至当日等
修饰类型 是对修饰词的一种抽象划分。修饰类型从属于某个业务域,如日志域的访问终端类型涵盖无线端、PC
修饰词 指除了统计维度以外指标的业务场景限定抽象。修饰词隶属于一种修饰类型,如在日志域的访问终端类型下,有修饰词 PC 端、无线端等
度量/原子指标 原子指标和度自含义相同,基于某一业务事件行为下的度盟,是业务定义中不可再拆分的指标,具有明确业务含义的名词,如支付金额
维度 维度是度量的环境,用来反映业务的一类属性,这类属性的集合构成一个维度,也可以称为实体对象。维度属于一个数据域,如地理维度(其中包括国家、地区、省以及城市等级别的内容)、时间维度(其中包括年、季、月、周、日等级别的内容)
维度属性 维度属性隶属于一个维度,如地理维度里面的国家名称、国家 ID、省份名称等都属于维度属性
派生指标 派生指标 = 一个原子指标 + 多个修饰词(可选)+ 时间周期。可以理解为对原子指标业务统计范围的圈定。如原子指标:支付金额,最近 1 天海外买家支付金额则为派生指标(最近 1 天为时间周期,海外为修饰词,买家作为维度,而不作为修饰词)

# 元数据

# 元数据定义

按照传统的定义,元数据(Metadata)是关于数据的数据。

元数据打通了源数据、数据仓库、数据应用,记录了数据从产生到消费的全过程。

元数据主要记录数据仓库中模型的定义、各层级间的映射关系、监控数据仓库的数据状态及 ETL 的任务运行状态。

在数据仓库系统中,元数据可以帮助数据仓库管理员和开发人员非常方便地找到他们所关心的数据,用于指导其进行数据管理和开发工作,提高工作效率。

将元数据按用途的不同分为两类:技术元数据(Technical Metadata)业务元数据(Business Metadata)

  • 技术元数据是存储关于数据仓库系统技术细节的数据,是用于开发和管理数据仓库使用的数据。

  • 业务元数据从业务角度描述了数据仓库中的数据,它提供了介于使用者和实际系统之间的语义层,使得不懂计算机技术的业务人员也能够 “读懂” 数据仓库中的数据。

# 元数据价值

元数据有重要的应用价值,是数据管理、数据内容、数据应用的基础,在数据管理方面为集团数据提供在计算、存储、成本、质量、安全、模型等治理领域上的数据支持。

例如在计算上可以利用元数据查找超长运行节点,对这些节点进行专项治理,保障基线产出时间。在数据内容方面为集团数据进行数据域、数据主题、业务属性等的提取和分析提供数据素材。例如可以利用元数据构建知识图谱,给数据打标签,清楚地知道现在有哪些数据。在数据应用方面打通产品及应用链路,保障产品数据准确、及时产出。例如打通 MaxCompute 和应用数据,明确数据资产等级,更有效地保障产品数据。

# 元数据应用

数据的真正价值在于数据驱动决策,通过数据指导运营。通过数据驱动的方法,我们能够判断趋势,从而展开有效行动,帮助自己发现问题,推动创新或解决方案的产生。这就是数据化运营

对于元数据,可以用于指导数据相关人员进行日常工作,实现数据化 “运营”。

比如对于数据使用者,可以通过元数据让其快速找到所需要的数据;对于 ETL 工程师,可以通过元数据指导其进行模型设计、任务优化和任务下线等各种日常 ETL 工作;对于运维工程师,可以通过元数据指导其进行整个集群的存储、计算和系统优化等运维工作。

# 数据质量

数据质量是数据分析结论有效性和准确性的基础,也是这一切的前提。

如何评估数据质量的好坏,业界有不同的标准,而阿里巴巴对数据仓库主要从四个方面进行评估,即完整性准确性一致性及时性

阿里巴巴提出了一套数据质量建设方法,如下图:

# 数据资产等级

阿里巴巴将数据分为五个等级,即毁灭性质全局性质局部性质一般性质未知性质,不同性质的重要性依次降低,具体定义如下。

  • 毁灭性质,即数据一旦出错,将会引起重大资产损失,面临重大收益损失,造成重大公关风险。

  • 全局性质,即数据直接或者间接用于集团级业务和效果的评估、重要平台的运维、对外数据产品的透露、影响用户在阿里系网站的行为等。

  • 局部性质,即数据直接或间接用于内部一般数据产品或者运营/产品报告,如果出现问题会给事业部或业务线造成影响,或者造成工作效率损失。

  • 一般性质,即数据主要用于小二的日常数据分析,出现问题几乎不会带来影响或者带来的影响极小。

  • 未知性质,不能明确说出数据的应用场景,则标注为未知。

对于不同的数据资产等级使用英文 Asset 进行标记,毁灭性质标记为 A1 等级,全局性质标记为 A2 等级,局部性质标记为 A3 等级, 一般性质标记为 A4 等级,未知性质则标记为 Ax 等级。此外,如果一份数据出现在多个应用场景中,则遵循就高原则。

上次更新时间: 2022年03月04日 12:27:53