随着企业数据量的增长,数据仓库的重要性越来越凸显。一个好的数据仓库架构,不仅要能处理海量数据,还要保证高可用和高并发。本文从架构设计的角度,详细介绍了如何构建一个高可用、高并发的数据仓库,包括分层设计、存储计算分离、元数据管理、任务调度、数据质量、权限安全等方面。如果你正在做数据仓库相关的工作,希望这篇文章能给你一些参考。
一、为什么需要好的数据仓库架构
先说说为什么需要好的数据仓库架构吧。
现在的企业,数据量越来越大,业务越来越复杂。每天产生的数据从GB级到TB级甚至PB级,这些数据来自各个业务系统,格式各异,质量参差不齐。如何把这些数据整合起来,进行清洗、加工、分析,为业务决策提供支持,是数据仓库要解决的核心问题。
如果数据仓库的架构设计得不好,会出现很多问题。比如数据处理慢,一个任务跑几个小时甚至几天;比如数据不一致,不同系统出来的数据对不上;比如系统不稳定,经常出故障,影响业务使用;比如扩展性差,数据量增长之后系统扛不住,只能推倒重来。
所以,一个好的数据仓库架构非常重要。它不仅要满足当前的需求,还要能适应未来的增长。高可用保证系统稳定运行,不因为单点故障而中断;高并发保证能同时处理大量的任务和查询,不因为数据量增长而变慢。
我们团队在过去几年里,从零开始搭建了公司的数据仓库,中间踩了很多坑,也积累了一些经验。下面把我们的架构设计思路分享给大家。
二、整体架构设计
我们的数据仓库整体架构分为几层:数据源层、数据接入层、数据存储层、数据计算层、数据服务层、数据应用层。
数据源层:就是各个业务系统的数据库,比如MySQL、PostgreSQL、MongoDB等,还有日志数据、第三方数据等。这些是数据仓库的源头。
数据接入层:负责把数据源的数据抽取到数据仓库里。我们用了多种接入方式,包括全量同步、增量同步、实时同步、日志采集等。
数据存储层:负责存储数据仓库的各种数据。我们用了HDFS作为底层存储,上面用Hive表来管理数据。同时也用了一些列式存储格式,比如Parquet和ORC,来提升查询性能。
数据计算层:负责数据的清洗、转换、加工等计算任务。我们主要用Spark来做离线计算,用Flink来做实时计算。
数据服务层:负责把加工好的数据提供给下游使用。包括数据API、数据查询服务、数据推送等。
数据应用层:就是数据的最终使用者,比如BI报表、数据分析、机器学习、业务系统等。
这几层之间是松耦合的,每层都有明确的职责,通过标准的接口进行交互。这样的好处是,每层都可以独立扩展和升级,不会互相影响。
三、分层设计:ODS、DWD、DWS、ADS
数据仓库内部,我们按照经典的分层设计,分成了ODS、DWD、DWS、ADS四层。
ODS层(Operational Data Store):操作数据层,也叫贴源层。这一层的数据和数据源保持一致,基本不做清洗和转换,只是把数据原样同步过来。这样做的好处是,保留了原始数据,如果后面的加工出了问题,可以从ODS层重新跑。
ODS层的数据通常是按天分区的,每天同步一次。对于需要实时处理的数据,我们也会做实时同步,但是实时数据和离线数据分开存储,避免互相影响。
DWD层(Data Warehouse Detail):明细数据层。这一层对ODS层的数据做了清洗、脱敏、标准化等处理,但是保留了明细粒度,不做聚合。比如,把订单表和用户表关联起来,补全用户信息,但是还是每一条订单一条记录。
DWD层是数据仓库的核心层,大部分的数据清洗和标准化工作都在这一层完成。这一层的数据质量直接影响上层的数据质量,所以我们对DWD层的要求很高,有严格的数据质量校验。
DWS层(Data Warehouse Summary):汇总数据层。这一层对DWD层的明细数据做了聚合,按主题和维度进行汇总。比如,按天、按地区、按商品类别汇总的销售额、订单量等。
DWS层的数据是面向分析的,通常是宽表,包含了常用的维度和指标。这样下游查询的时候,不需要再做复杂的关联和聚合,直接查DWS层的表就可以了,查询速度很快。
ADS层(Application Data Store):应用数据层。这一层是直接面向应用的,根据具体的业务需求,从DWS层或者DWD层提取数据,做进一步的加工。比如,某个报表需要的特定指标,某个机器学习模型需要的特征数据等。
ADS层的数据是个性化的,不同的应用有不同的ADS表。这一层的灵活性很高,可以根据业务需求快速调整。
这种分层设计的好处是:职责清晰,每层做自己的事情;数据复用,底层的数据可以被多个上层应用使用;便于维护,出了问题可以定位到具体的层;可以逐步优化,从下往上逐层提升数据质量。
四、存储计算分离
在架构设计中,我们采用了存储计算分离的方案。
传统的数据仓库,存储和计算是耦合的,比如传统的MPP数据库,数据存在节点上,计算也在节点上做。这种架构的问题是,存储和计算不能独立扩展。如果数据量增长了,需要加存储节点,但是计算能力也跟着增加了,可能用不上;如果计算需求增长了,需要加计算节点,但是存储也跟着增加了,可能浪费。
存储计算分离的架构,把存储和计算分开。存储用HDFS或者对象存储,计算用Spark或者Presto等计算引擎。存储和计算可以独立扩展,需要更多存储就加存储节点,需要更多计算就加计算节点,灵活度很高。
我们的具体做法是:
- 存储层用HDFS,数据以Parquet格式存储,按分区组织
- 计算层用Spark做离线计算,用Presto做交互式查询
- 计算节点是无状态的,可以随时增减,不影响存储
这种架构的好处是:
- 弹性扩展:计算资源可以根据需求动态调整,高峰期加节点,低峰期减节点,节省成本
- 多引擎共享:同一份数据,可以被不同的计算引擎访问,比如Spark批处理、Presto查询、Flink实时处理等
- 存储成本低:HDFS的存储成本比专用的数据仓库设备低很多
- 容错性好:存储有副本机制,计算节点故障可以自动重试
当然,存储计算分离也有它的挑战。最大的挑战是数据本地化的问题。传统架构中,计算和数据在同一个节点,数据不需要网络传输,速度快。存储计算分离之后,计算需要从存储节点拉数据,网络IO可能成为瓶颈。
为了解决这个问题,我们做了一些优化:
- 用列式存储格式(Parquet),减少数据扫描量
- 合理设计分区和分桶,让查询只扫描需要的数据
- 用缓存层,把热点数据缓存到计算节点的内存或者SSD里
- 优化网络,用万兆网卡,减少网络传输的时间
经过这些优化,存储计算分离的性能基本能满足我们的需求,而且弹性和成本的优势非常明显。
五、高可用设计
高可用是数据仓库的基本要求。数据仓库是很多业务系统的依赖,如果数据仓库出了问题,下游的报表、分析、模型都会受影响。所以我们在架构设计中,把高可用放在很重要的位置。
我们的高可用设计主要包括以下几个方面:
1. 存储高可用
HDFS默认有三个副本,数据存储在不同的节点上,即使一个节点挂了,数据也不会丢。我们还做了跨机架的副本分布,确保一个机架出问题,数据也不会丢。
对于重要的数据,我们还做了异地备份,每天把关键数据备份到另一个机房。虽然成本高一些,但是能保证极端情况下的数据安全。
2. 计算高可用
Spark和Flink都有完善的容错机制。Spark的RDD有血缘关系,某个分区计算失败了,可以根据血缘重新计算。Flink有checkpoint机制,可以从最近的checkpoint恢复。
我们的任务调度系统也做了高可用。调度器是主备模式,主节点挂了,备节点自动接管。任务执行失败了,会自动重试,重试次数和间隔可以配置。
3. 服务高可用
数据服务层的API和查询服务,都是多实例部署的,前面有负载均衡。一个实例挂了,负载均衡会自动把流量切到其他实例,用户无感知。
我们还做了服务降级。当系统压力大的时候,可以自动降级一些非核心的服务,保证核心服务的正常运行。
4. 监控和告警
完善的监控是高可用的保障。我们监控了数据仓库的各个层面:存储的容量和使用率、计算资源的使用情况、任务的运行状态、数据的质量、服务的响应时间和错误率等。
任何指标异常,都会触发告警,通知值班人员。我们还做了告警分级,严重的告警电话通知,一般的告警消息通知,避免告警疲劳。
六、高并发设计
高并发是数据仓库的另一个重要要求。随着数据应用的增多,同时运行的任务和查询越来越多,系统必须能支撑高并发。
我们的高并发设计主要包括以下几个方面:
1. 资源隔离
不同的业务线、不同类型的任务,用不同的资源队列。比如,离线计算用一个队列,交互式查询用一个队列,实时计算用一个队列。这样不同类型的任务不会互相影响,不会因为一个大的离线任务把所有资源占满,导致查询都卡住。
我们还可以给不同的队列设置不同的资源配额和优先级。核心业务的队列资源多、优先级高,非核心业务的队列资源少、优先级低。这样保证核心业务的资源需求。
2. 查询优化
对于交互式查询,我们做了很多优化。比如,用列式存储减少扫描量,用分区裁剪减少数据量,用预计算把复杂的聚合提前算好,用缓存把热点查询的结果缓存起来。
我们还限制了单个查询的资源使用,比如最大扫描的数据量、最长的执行时间。避免一个不合理的查询把整个系统拖垮。
3. 任务调度优化
对于离线任务,我们有一个智能的调度系统。它会根据任务的依赖关系、资源需求、优先级等,合理安排任务的执行顺序和资源分配。
比如,有依赖关系的任务,等上游任务完成了再执行;资源需求大的任务,在资源充足的时候执行;优先级高的任务,优先分配资源。这样可以最大化资源利用率,也能保证重要任务按时完成。
4. 弹性伸缩
我们的计算集群支持弹性伸缩。在任务高峰期(比如凌晨的批量计算时间),自动增加计算节点;在低峰期,自动减少计算节点。这样既能满足高峰期的并发需求,又能节省成本。
弹性伸缩是基于资源使用率来触发的。当集群的CPU或者内存使用率超过阈值持续一段时间,就自动加节点;当使用率低于阈值持续一段时间,就自动减节点。
七、元数据管理
元数据是数据仓库的"数据字典",它记录了数据仓库里有哪些表、每个表有哪些字段、字段是什么意思、数据的来源和去向、任务的依赖关系等。
元数据管理非常重要。没有好的元数据管理,数据仓库就是一个黑盒,没人知道数据是怎么来的,出了问题也不知道怎么排查。
我们的元数据管理包括:
1. 技术元数据:表的结构、字段类型、分区信息、存储格式、数据量等。这些是数据的技术属性,通常可以自动采集。
2. 业务元数据:表和字段的业务含义、指标的计算公式、数据的业务归属等。这些需要业务人员和数据人员共同维护。
3. 血缘关系:数据的来源和去向。比如,某个ADS表的数据来自哪些DWS表,这些DWS表又来自哪些DWD表。血缘关系对于数据溯源和影响分析非常重要。
4. 任务元数据:任务的定义、依赖关系、执行历史、运行状态等。
我们用了一个开源的元数据管理工具(Apache Atlas),并在上面做了一些定制开发。所有的表和字段都有详细的元数据记录,用户可以通过一个Web界面查询和搜索。
有了完善的元数据,用户找数据、理解数据、使用数据都方便了很多。出了问题,也能通过血缘关系快速定位到源头。
八、数据质量
数据质量是数据仓库的生命线。如果数据质量不好,数据仓库里的数据就不可信,下游的分析和决策就会出错。
我们建立了一套完整的数据质量保障体系:
1. 数据规范:制定了统一的数据规范,包括命名规范、类型规范、分区规范、指标定义规范等。所有的表和字段都必须遵循规范,从源头上保证数据的一致性。
2. 质量校验:在数据加工的各个环节,都有质量校验。比如,ODS层校验数据的完整性和一致性,DWD层校验数据的准确性和标准化,DWS层校验指标的合理性。校验不通过的数据,会被拦截并告警。
常见的校验规则包括:非空校验、唯一性校验、范围校验、枚举值校验、关联校验、波动校验等。
3. 数据监控:对关键的数据指标做监控,比如数据量、空值率、重复率、指标的日环比和周同比等。如果出现异常波动,自动告警。
4. 问题处理流程:建立了数据质量问题的处理流程。发现问题之后,要记录问题、定位原因、修复数据、总结经验,防止类似问题再次发生。
九、权限和安全
数据仓库里存储了企业的大量核心数据,权限和安全非常重要。
我们的权限和安全设计包括:
1. 认证:所有访问数据仓库的用户,都需要经过统一的身份认证。我们用了公司的统一登录系统,支持单点登录。
2. 授权:基于角色的访问控制(RBAC)。不同的角色有不同的权限,比如管理员有全部权限,分析师有查询权限,开发人员有读写权限,普通用户只有特定表的查询权限。
权限可以精确到表级和列级。对于敏感数据(比如用户的手机号、身份证号),只有特定的角色才能查看,而且查看的时候会做脱敏处理。
3. 审计:所有的数据访问操作都有审计日志,记录了谁、在什么时候、访问了什么数据、做了什么操作。审计日志是安全追溯的重要依据。
4. 数据脱敏:对于敏感数据,在存储和展示的时候都做脱敏。比如,手机号只显示前三位和后四位,中间用星号代替。这样即使数据泄露了,也不会造成太大的影响。
十、写在最后
数据仓库的架构设计是一个复杂的系统工程,涉及到存储、计算、调度、元数据、数据质量、权限安全等方方面面。没有完美的架构,只有适合自己业务的架构。
我们的架构也是在不断演进的。从最开始的简单脚本,到现在的分层架构、存储计算分离、高可用高并发,中间经历了很多次的重构和优化。这个过程虽然辛苦,但是每一次优化都让系统更稳定、更高效、更易用。
如果你正在做数据仓库相关的工作,希望这篇文章能给你一些参考。也欢迎大家在评论区交流讨论,分享你们的架构设计和经验教训。
最后用一句话结束本文:"架构设计没有银弹,只有不断的演进和优化。"愿每一个数据工程师都能构建出稳定、高效、易用的数据仓库。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录