数据湖的不可能三角
数据湖概述
提到数据湖就要先说一下数据仓库,数据仓库是集成多业务系统数据、面向主题的、专门用于数据查询分析的数据组织形式。当业务系统数据量不断增大、业务系统数量不断增多以后,数据仓库的出现就会成为必然。原始数据入仓时需要经过一系列清洗转换,以及深度组织才能满足业务的需要。因此数据仓库要解决的核心问题是:回答业务中已有的问题。这些问题必须事先定义好。
那么事先没想到的问题(潜在数据价值)怎么办?如果按照数据仓库的解决思路,需要业务先提出问题,再基于该问题进一步建模。这样发现问题、提出问题、解决问题的链路就会很长,而且由于数据仓库的数据是高度组织的,如果要回答新问题涉及的数据粒度较细就需要再从原始数据加工获得,代价很大。如果这样的情况很多,整个过程就吃不消了。
基于这样的背景,数据湖出现了。数据湖是为了满足海量原始数据存储分析的一项技术(方案),尽量多的原始数据“入湖”,并尽量保持原有的信息量,再基于全量数据理论上就可以发掘任意数据价值。说到这里,数据湖的两个主要作用呼之欲出,一个是数据存储,数据湖需要保留全量原始数据;另一个是数据分析,从技术上来讲就是数据计算,即数据变现的过程。
那么现在数据湖建设在这两方面表现的怎么样呢?
由于数据湖存储的是全量原始数据,结构化数据、半结构化数据、非结构化数据,无论何种类型都要原封不动地存进数据湖,因此本质上面临的是海量数据存储问题。这与数据仓库大多使用数据库存储结构化数据有很大不同。而且,数据入湖越快越好,这样不仅有助于充分发掘各种主题数据的关联价值,在数据安全性、完整性等方面也能得到很好保障。
可喜的是,这种海量原始数据存储需求受益于硬件存储与云平台技术的长足进步,已经不再是问题,无论采用自建的存储集群,还是云厂商提供的存储服务,都能很好满足。
现在难的是数据处理!数据湖数据五花八门,各种类型的数据处理方式也不尽相同。其中最核心也最麻烦的是结构化数据处理,无论是历史沉淀还是业务新增,结构化数据处理仍然是重中之重,甚至很多半结构化和非结构化数据计算最后都会转到结构化数据计算上。
目前结构化数据处理的主要方式仍然是以 SQL 为主的数据库相关技术,就是原来数据仓库的那些能力。换句话说,数据湖上的结构化数据计算仍然要依靠数据仓库(数据库)才能完成。现在几乎所有数据湖也是这么干的,建设数据湖解决了原始全量数据存储问题以后,在此基础上再建设数据仓库完善贴合业务的数据处理能力,这就需要将数据湖数据再经 ETL 导入数据仓库。更先进一点的做法是采用一些自动化机制,识别数据湖中哪些数据需要入仓,在系统空闲的时候将数据从数据湖导入数据仓库,这就是现在喊的很热的“湖仓一体”的主要功能。其实不管数据入仓采用何种形式(还有数仓通过外部表的方式访问数据湖数据的,但效率很差),当前数据湖的组成大概是这样:数据湖 = 海量数据存储 + 数据仓库 + 其他引擎(如非结构化数据处理)。
那么通过这种方式构建的数据湖会有啥问题呢?
数据湖的不可能三角
数据湖有三个重要满足点,既要保持数据的原样(全量信息入湖),也要可以方便计算使用(数据变现),还希望建设成本低廉(显然的)。但是,当前的技术方案无法同时满足这三点。
保有原信息是数据湖建设的初衷,只有数据原样入湖保持原汁原味才能发挥最大价值。达到这个目标最简单的方法是数据湖保持一套与数据源完全一致的数据存储介质,原来是 MySQL 数据湖中就有一个 MySQL 对应,原来是 MongoDB 数据湖中就有一个 MongoDB… 。这样就可以充分保证原始数据不变,还可以沿用各类数据源的计算能力。虽然很难跨源计算,但自身数据的计算都能完成,基本能够达到可计算的目标(图①部分)。
但这样做的缺点也很明显,数据湖建设成本太高。不仅要准备多个与原来相同的介质,将多年积累的数据源全部复制一遍,这个工作量太大了;而且如果数据来源商业软件,付费再采购岂不是更加推高建设成本。好一点的做法可以使用相同类型的介质,比如 Oracle 数据可以采用 MySQL 存储,这样成本会降低一些,但代价依然很高。而且这样做以后原来能计算的情况很可能就做不了或很难完成。
那么退一步,不要求数据信息与原始一模一样,将数据存储在数据库中从而达到可计算的目的同时又能满足低成本的建设要求(图②部分),这样是否可以呢?答案仍然是否定的。这种方案极度依赖于关系数据库,要将数据都整理到一个数据库中从而达到可计算的目的。
然而,数据整理过程中很容易造成信息丢失,导致不满足数据湖建设的目标(全量信息入湖)。比如将 MongoDB 数据转存到 MySQL/Hive 中就会发现实现很困难。MongoDB 中的很多数据类型和集合之间的关系在 MySQL 中并不存在,比如嵌入式的数据结构、数组和哈希等集合类型、多对多关系的实现。这些问题并不是简单通过数据迁移就能解决的,而需要在迁移之前先对部分数据结构进行重构,这就要进行一系列精细整理才能实现,但这又不符合低成本的要求了,需要事先投入相当人工和时间成本去梳理业务并设计目标数据组织方式。如果不进行精细整理就会丢失信息,进一步导致后续的分析统计错误,有些错误很隐蔽很难发现。
更常见的做法是采用文件存储(或者数据库中的大字段)。将原始数据原封不动地导出到文件,这时丢失的信息量并不大,基本可容忍,数据还能保持完整。文件存储有很多好处,比如使用更加灵活,拥有更强的开放性,I/O 效率更高等。而且使用文件(系统)存储同时也符合低成本的建设目标。
但文件存储的问题是文件没有计算能力(大字段也类似),基于文件存储就无法达到可计算的目标。不可能三角的确很难突破。
无论如何,当前数据湖建设总会面临全量信息的存储和使用矛盾:在低技术成本(数据能快速入湖)的要求下,要全信息量就不能算,要算就不能保有全信息量。这与数据湖要达到的开放性背道而驰。
这个问题本质上是数据库开放性不足和强约束性之间的矛盾,数据库要计算数据就必须入库才行,入库就要满足数据库的各类约束,需要经过一些列数据整理,信息就会丢失。不用数据库(比如文件)又无法满足强计算需求,当然自己硬编码的确也可以实现这些计算,但复杂度过高,远没有数据库方便。
其实,如果有一个开放的计算引擎就可以解决这个问题,具备足够强的计算能力对未经整理的多样性数据进行实时计算,包括混合跨源计算。
开放的数据湖计算引擎 SPL
开源 SPL 就是这样一个可应用在数据湖中提供开放计算能力的结构化数据计算引擎。借助 SPL 的多源混算能力就可以直接基于多种原始(原汁原味)数据进行计算,无论数据湖构建时采用与数据源一致的类型,还是通过文件存储都可以直接计算。而数据整理可以逐步进行,数据湖构建可以更加从容。
开放且完善的计算能力
多数据源混合计算
SPL 支持多种数据源,RDB、NoSQL、JSON/XML、CSV、Webservice 等都可以连接,并进行混合计算。这样数据湖存储的各类原始数据就可以直接利用起来,无需整理就可以发挥数据价值,节省“入库”动作,保证数据使用的灵活与高效性,符合数据湖灵活性要求。
有了这个能力以后,数据湖构建之初就能为应用提供数据服务,而不用等原来数据整理、入库、建模等一系列长链路长周期过程完成后才能服务。而且这种方式更加灵活,可以根据业务需要提供实时响应。
文件计算支持
特别地,SPL 对文件的很好支持使得文件也拥有强计算能力,这样将数据湖数据存储在文件系统中也可以获得与数据库接近甚至超越的计算能力。即在前述不可能三角的第③部分基础上增加数据计算能力,从而让不可能三角变得可能。
除了文本文件,SPL 还可以天然支持 JSON 等多层数据格式处理,这样 NoSQL 以及 RESTful 等数据不用转换就可以直接使用,非常方便。
A |
||
1 |
=json(file("/data/EO.json").read()) |
|
2 |
=A1.conj(Orders) |
|
3 |
=A2.select(Amount>1000 && Amount<=3000 && like@c(Client,"*s*")) |
条件过滤 |
4 |
=A2.groups(year(OrderDate);sum(Amount)) |
分组汇总 |
5 |
=A1.new(Name,Gender,Dept,Orders.OrderID,Orders.Client,Orders.Client,Orders.SellerId,Orders.Amount,Orders.OrderDate) |
关联计算 |
完善的计算能力
SPL 提供了完善的计算能力,基于离散数据集(而非关系代数)模型可以获得与 SQL 一样的完备计算性,同时在 SPL 敏捷语法与过程计算支持下数据处理比 SQL 更简单。
SPL 丰富的计算类库
直接访问源数据
再将 SPL 的开放能力延伸一下。如果数据源与数据湖的数据同步没完成但还需要使用这部分数据怎么办?原来就只能等着了,现在有了 SPL 我们甚至可以直接对接数据源进行计算,或者与数据湖中已有数据进行混合计算都可以。逻辑上可以把数据源作为数据湖的一部分使用,这样可以获得更高的灵活性。
数据整理后的高性能计算
引入 SPL 以后,数据仓库就变成可选项了。SPL 自身拥有完善的强计算能力,同时还提供了基于文件的高性能存储。将原始数据 ETL 后存储在 SPL 存储中还可以获得更高的性能,同时文件系统具备使用灵活、易于并行等特性。
SPL 提供了两种高性能文件存储类型:集文件和组表。集文件采用了压缩技术(占用空间更小读取更快),存储了数据类型(无需解析数据类型读取更快),支持可追加数据的倍增分段机制,利用分段策略很容易实现并行计算,保证计算性能。组表支持列式存储,在参与计算的列数(字段)较少时会有巨大优势。组表上还实现了 minmax 索引,同时支持倍增分段,这样不仅能享受到列存的优势,也更容易并行提升计算性能。
SPL 也很容易实施并行计算,发挥多 CPU 的优势。SPL 有很多计算函数都提供并行机制,如文件读取、过滤、排序只要增加一个 @m 选项就可以自动实施并行计算,同时也可以显示编写并行程序,通过多线程并行提升计算性能。
特别地,SPL 能支持很多 SQL 无法支持的高性能算法。比如常见的 TopN 运算,在 SPL 中 TopN 被理解为聚合运算,这样可以将高复杂度的排序转换成低复杂度的聚合运算,而且还能扩展应用范围。
A |
||
1 |
=file(“data.ctx”).create().cursor() |
|
2 |
=A1.groups(;top(10,amount)) |
金额在前 10 名的订单 |
3 |
=A1.groups(area;top(10,amount)) |
每个地区金额在前 10 名的订单 |
这里的语句中没有排序字样,也不会产生大排序的动作,在全集还是分组中计算 TopN 的语法基本一致,而且都会有较高的性能,类似的算法在 SPL 中还有很多。
通过这些机制,SPL 可以跑出超过传统数据仓库数量级的计算性能。整理后数据的存储和计算问题得以很好解决,数据仓库在数据湖中就真地不再是必需品了。
更进一步,使用 SPL 还可以针对整理好的数据和未整理原始数据进行混合计算充分发挥各种类型的数据价值,而不用等所有数据整理好才能计算使用,数据湖的灵活性得以充分扩展。
有了 SPL 以后,数据湖建设的很多步骤就可以并行了,原来只能串行(先导入、再整理、再使用等等),数据整理与数据使用可以同时进行,面对原始不规范的各类数据也能直接计算。边使用,边整理,只有这样循序渐近的模式才能建设好数据湖。
英文版