万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

444次阅读
没有评论

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

文章贡献者 Authors

  • • 技术指导: 泰康人寿 数据架构资深专家工程师 王可

  • • 文章作者: 泰康人寿 数据研发工程师 田昕峣

摘要 Abstract

本文详细介绍了泰康人寿基于 Apache Hudi 构建湖仓一体分布式数据处理平台的技术选型方法、整体架构设计与实施、以及针对大健康领域的领域特征和公司战略对 Apache Hudi 进行的功能扩展与实施的详细过程、并简要分享领域实践心得和部分应用成果。文章总体被分为五个部分:首先,我们对该平台与大健康领域和泰康方案相关的建设背景和涉及到的技术概念进行简要介绍;其次,我们对架构中使用到的核心,即数据湖组件 Apache Hudi,进行横向技术对比并完成技术选型;再次,我们绘制了整个平台的宏观架构图并列举了主要层级的实施细节来阐明该平台的设计与实施过程;之后,我们详细的阐述了架构中的数据湖平台层 Apache Hudi 针对大健康领域进行了何种定制化改造与优化;最后,我们挑选了一个大健康领域内的典型应用场景,并将上述工作在该场景中的应用方法和总体实践成果进行数字化的展示。下面,文章正文将正式拉开帷幕。

公司概况 Company Profile

泰康人寿保险有限责任公司(以下简称:泰康人寿)隶属于泰康保险集团股份有限公司,其前身泰康人寿保险股份有限公司系 1996 年经由中国人民银行批准成立的全国性、股份制人寿保险公司,由中石化、中国对外贸易运输(集团)总公司、中国嘉德国际拍卖有限公司等16家国有大中型企业发起组建,公司总部设于北京。

自公司成立以来,在创始人、董事长兼首席执行官陈东升先生的带领下,泰康经历了近 30 年的蓬勃发展,如今已经成为一家涵盖保险、资管、医养三大核心业务的大型保险金融服务集团。截至 2023 年,公司已连续六年荣登《财富》世界 500 强榜单,管理资产总规模超 28000 亿元,管理养老金规模超 7200 亿元,核心个人有效客户超 6200 万人,累计服务企业客户超 49 万家,累计理赔金额超 1200 亿元。

泰康人寿始终坚持 “尊重生命、关爱生命、礼赞生命” 的企业价值观,坚持稳健、开拓、创新的经营理念,深耕寿险产业链,充分发挥保险补偿、资金融通和社会管理功能,实现客户、员工、股东和社会的共赢发展,致力于成为新时代大民生工程核心骨干企业,为日益增长的中产人群及其家庭打造长寿健康富足的服务平台。不忘初心、创新永续、商业向善,“用市场经济的方式方法,全心全意为人民服务”。

建设背景 Backgrounds

随着国家《健康中国行动 (2019-2030年)》[14] 等相关文件的出台,人民健康和慢性疾病防治的受重视程度再次被推向了一个新的高点,为保障民生福祉的 “大健康” 概念也被迅速普及并得到社会各界的广泛关注,由传统健康领域 (e.g. 医疗服务,药械器材,etc.) 和范健康领域  (e.g. 健康保险,医疗护理,理疗康复,养生保健,etc.) 所共同构成的大健康领域也在近年来得到了蓬勃发展,并吸引了众多企业涉足探索,泰康人寿便是其中之一。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

由于行业特性与历史原因,加之经历了近几年该领域的高速发展,为了适配瞬息万变的业务场景,泰康人寿内部的数据基础组件均以大型物理机搭配大型商用数据库为主,辅以商业分析软件用于进行数据的分析与应用。这种建设方式的优势非常明显:即每一个基础设施和数据库都能被准确关联到对应的业务条线,快速响应业务需求,并精确地对投入的 IT 成本进行控制。然而,随着公司规模的不断扩大和业务的持续发展,该方法也逐渐暴露出部分弊端:数据以业务条线为单元零散分布,最终产生了难以忽视的数据孤岛现象,导致公司整体特别是跨团队的数据使用效率一般,并产生了数据资产被妥善管理的难度较大、数据价值被有效发掘的成本较高等诸多隐患。

为了保证公司在未来持续深耕大健康领域并落实顶层战略的道路上不会为数据问题所困,一套面向未来的、针对大健康领域特征和公司战略定制化设计的数据处理平台就变得尤为重要。因此,泰康人寿数据团队毅然决然地决定构建一套湖仓一体化的分布式数据处理平台,集数据采集、数据注入、数据治理、数据处理与加工、数据分析等丰富功能于一体,从根源上解决由于数据零散分布所造成的种种弊端,妥善管理数据资产,有效发掘数据价值,为公司战略的落实与业务的发展打好坚实的数据基石。

相关技术概念 Concepts

在进行后续讨论之前,我们有必要先对数据湖、数据仓库和湖仓一体架构的相关概念和定义进行明确,以帮助数据领域外的读者快速地进行理解,并建立后续沟通的桥梁,避免由于概念的混淆而造成误解。此处,我们分别选择了微软和 IBM 两家该领域的巨头对于数据湖和数据仓库给出的定义来进行概念明确,并基于这两个定义阐明湖仓一体架构的本质和其特性。

数据湖 (Data lake):

数据湖是一个集中式的数据存储,以原始形式摄取和存储大量数据。进入数据湖后,数据便可以被加工处理并被用作各种分析需求的原材料。由于其开放、可扩展的架构,数据湖可以容纳来自任何来源的所有类型的数据,从结构化(数据库表、Excel 工作表)到半结构化(XML 文件、网页)再到非结构化(图像、音频文件、推文),所有这些都不会牺牲保真度 [1] (翻译自笔者,定义由微软给出)。

A data lake is a centralized repository that ingests and stores large volumes of data in its original form. The data can then be processed and used as a basis for a variety of analytic needs. Due to its open, scalable architecture, a data lake can accommodate all types of data from any source, from structured (database tables, Excel sheets) to semi-structured (XML files, webpages) to unstructured (images, audio files, tweets), all without sacrificing fidelity [1].

数据仓库 (Data Warehouse):

数据仓库或企业数据仓库 (EDW) 是一种将来自不同源的数据聚合到单个集中式一致数据存储中的系统,以支持数据分析、数据挖掘、人工智能机器学习。数据仓库系统使组织能够以标准数据库无法做到的方式对大量(TB 和 PB 级别)的历史数据进行强大的分析 [2] (翻译自笔者,定义由 IBM 给出)。

A data warehouse, or enterprise data warehouse (EDW), is a system that aggregates data from different sources into a single, central, consistent data store to support data analysis, data mining, artificial intelligence (AI), and machine learning. A data warehouse system enables an organization to run powerful analytics on huge volumes (terabytes and petabytes) of historical data in ways that a standard database cannot. [2] (Definition given by IBM)

从上面的定义我们可以清晰地看到数据湖与数据仓库这二者的相似性与差异性。其共同点在于,数据湖和数据仓库都是一个中央化的设施,起到将四处散落的庞大数据汇总到一起的作用;而差异性则在于,数据湖更加强调多形式多模态数据的快速注入,而数据仓库则更加强调不同类型数据的管理以及对外提供多样化的数据服务和应用。

由此,湖仓一体 (Data Lakehouse) 的概念也随着数据类相关技术的高速发展在近几年应运而生:该方案希望在保证中央化集中管理庞大数据量的同时,兼顾数据湖和数据仓库的优点于一身,即希望数据能够以多种结构和形式被快速注入,同时进行良好的数据治理和元数据管理,并根据用户的需求提供准确的、高质量的数据服务。这便是使用湖仓一体架构建设数据平台的初衷以及根本目的:结合数据湖与数据仓库的优势,中央化管理大量数据、多结构数据快速注入、有效的数据治理以及高效的数据应用。为方便读者更加准确的理解,下面给出 IBM 对于湖仓一体的准确定义。

湖仓一体 (Data Lakehouse):

数据湖仓是一个数据平台,它将数据仓库和数据湖的最佳方面合并到一个数据管理解决方案中。数据湖仓寻求解决数据仓库和数据湖的核心挑战,为组织提供更理想的数据管理解决方案 [8] (翻译自笔者,定义由 IBM 给出)。

A data lakehouse is a data platform, which merges the best aspects of data warehouses and data lakes into one data management solution. Data lakehouses seek to resolve the core challenges across both data warehouses and data lakes to yield a more ideal data management solution for organizations [8].

在后续的文章中,这些概念和定义也将被频繁使用,用于阐述泰康人寿湖仓一体数据平台的建设方案以及在大健康领域应用的实践心得。

数据湖技术选型 Technical Selection

由于公司决定采用湖仓一体架构来建设一体化数据处理平台并进行数据治理,故作为整个架构地基的数据湖组件的选择就变得尤为重要。毫不夸张地说,底层数据湖组件技术选型的合适与否将直接决定整个平台建设工作的成败优劣,并在长远的时间跨度内影响整个数据平台的总体运行效率和稳定性。因此,在数据湖组件的选择上必须尽可能全面地进行考虑。

目前行业内主流的数据湖组件共有三者,分别为 Apache Iceberg [4],Apache Hudi [5] 以及 Delta Lake [6]。基于上述数据湖组件在架构中的关键性与重要性,我们在技术选型时对这三者进行了尽可能全面且细致的评估和对比。评估的角度可以按重要程度被主要归纳为以下三点:社区相关情况 (发展态势)、功能与特性、性能指标,我们接下来将逐一进行阐述。

考量维度 Consider Dimensions

社区相关情况 (发展态势) Community Momentum

将社区相关情况放在考量的首位,是由于我们深刻地意识到社区的环境将会极大程度的影响项目未来的发展。一个氛围良好成员活跃的社区往往能够很大程度上产出一款成功的项目,并在长远的时间范围内保证项目的健康发展和平稳迭代。由于我们的湖仓一体架构将会在未来很长一段时间内承担治理公司庞大数据的重要职责,因此我们绝不能以静态短视的眼光来进行数据湖的技术选型,而是要尽可能长远地为公司的数据保驾护航,因此,我们将与项目能否良好发展息息相关的社区相关情况放在了首要位置进行考量。

我们针对这三个项目的 Github 总收藏数,Watchers 和 Forks 总量,主要贡献者及 Commits 的增速,PRs (Pull Requests) 和 Issues 增速,以及主要贡献来源进行了综合性的量化分析和对比。此外,为了直观地感受每个社区对于使用其工具和开发时遭遇问题的解决与处理能力,我们分别加入了这三个社区的官方 Slack 社群和 maillist,并事先拟定好问题,按照一定频率每隔一段时间在 Slack 的主频道提问,并观测问题回复和解决的时间。如下是我们的评估结果以及简要分析:

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

从三大数据湖的开源社区总体情况我们可以看出,虽然 Deltalake 由于其创建时间较早导致总收藏数较多,但是背靠 Apache 基金会的 Iceberg 和 Hudi 则明显呈现出了更强的发展势头。从柱状图中可以分析得出,在数据采集时间段内,Apache Hudi 项目不论访客数量、Forks 数量、代码提交请求数量和新功能提出数量都位列第一,呈现出在这三者之中最强的社区活跃程度与发展势头,Iceberg 次之,而 Deltalake 虽然总规模较大但发展 (特别是在新功能的提出与开发方面) 总体趋于平稳且略显缓慢。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

在三大数据湖主要贡献者来源方面,我们可以看出,相比脱胎于开源社区 Apache 孵化项目的 Iceberg 和 Hudi 而言,依托于商业公司 Databricks 的 Deltalake 贡献者来源明显较为单一,且以中国境外的贡献者为主。Apache Iceberg 的贡献者呈现出较为均衡的态势;而 Apache Hudi 则在三者之中明显最受中国开发者欢迎。也许是更符合中国信息技术基础设施建设的原因,中国的代表性科技巨头 BAT (i.e. 字节跳动 Bytedance, 阿里巴巴 Alibaba, 腾讯 Tencent) 的贡献度均位于项目前列,还包括中国移动、华为、百度、OPPO 等中国行业巨头的参与,其贡献程度与以 Uber、 Amazon 和 Apache 为首的美国公司与组织呈现出分庭抗礼之势。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

而在社区问题反馈和问题解决的积极程度方面,虽然此处我们没有能够精准量化评估的方法,但从直观感受来说,采用 Apache 开源模式 TAW (i.e. The Apache Way [9]) 进行管理的 Iceberg 和 Hudi 的情况要明显强于 Deltalake,其中国本地化的社区 (e.g. 官方微信群、钉钉群、公众号等) 建设情况也明显更好,这也直接导致 Hudi 与 Iceberg 在中国的问题反馈与解决的情况要明显优于 Deltalake。

功能与特性 Features

三个数据湖项目的社区相关情况及未来发展趋势已经被简要分析完毕,接下来我们将关注的焦点放在三者的功能和特性上。虽然这三个项目均具有数据湖的基本特性,即之前概念明晰章节中阐述的诸如 “快速注入大量数据”、“多形式多模态数据注入” 以及 “支持事务” 等特性,在具体的特性和功能上它们仍然存在诸多差异。对于湖仓一体架构而言,一个功能尽可能全面,且具备支撑大健康领域数据特性关键功能的数据湖组件将会使整个架构的健壮性和整体运行效率得到保证。因此,我们以公司实际的数据应用需求为基础,对这三个数据湖组件进行了深入的功能性调研与分析,并将调研结果以横向功能对比表格的形式进行展现。调研结果如下:

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

可以发现,在公司业务对于数据湖组件功能需求的重点考量范围内,Apache Hudi 的功能与特性能够较为全面的满足所需,而 Deltalake 和 Apache Iceberg 都未能完全覆盖公司对于数据湖组件的功能需求,或者至少在一定程度上存在欠缺。

性能指标 Benchmark Performance

在评估完各个数据湖组件是否具备满足我们需求的相应功能后,利用数据集评估各个数据湖组件的 Benchmark Performance 就成为了重点。受到一家商业数据湖公司 Onehouse 的一篇名为 “Transparent TPC-DS Data Lakehouse Performance Benchmarks” 技术分享的启发 [7],由于利用湖仓一体架构治理公司内数据就是我们的根本目的,故相比于使用公开的数据集进行性能评估,利用公司内部已有的真实数据直接进行性能测试对我们来说既便捷又具有实际意义。因此,我们使用了公司内部最具代表性和业务价值的 “保险受理业务数据” 进行基线性能测试。保险受理业务数据不仅具有大健康领域数据的标志性与代表性特征,还具备现实性与实用性:由于受理业务的特性,其涉及代理人、保险公司、投保人、被保人等多方主体的各种信息和彼此之间复杂的关系,且与公司的保费收入密切相关,故使用该部分数据制作的数据集可谓进行基线性能测试不二之选。

该数据集原为存储于公司保险受理业务条线 IBM DB2 中的多张结构化数据表,经过数据抽取流程并使用 Hive 进行多个步骤的加工和处理,最终形成了共计超过 7400 万条受理记录、具有 70 余列的密集型结构化数据表,所占 HDFS 存储空间总量为 183.6 GB。测试方法主要为目前数据湖领域通用的读写测试,即记录多次数据集入湖和查询的平均耗时,来作为衡量性能的重要基准。写 (入湖) 测试方面,我们使用了易于进行实践测量的批处理模式进行测试;而在读 (查询) 方面,我们使用了占据历史总查询数量超过 70% 的 “列查 + 点查 + 关联查询” 的方式进行测试。最终,我们将二者耗费的总时长求和,并与社区给出的极限测试结果进行综合分析与评估。受限于公司法律合规的要求,这部分数据即使经过脱敏处理暂时也仍无法公开,但我们很乐意将基线性能测试的结果进行分享。测试结果如下所示:

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

可以发现,虽然性能差距没有开源社区给出那么显著,但经过我们测试得出的三者性能的大体情况与开源社区给出的相吻合,即: Deltalake 的性能要略优于 Apache Hudi,但基本处于同一水平;而 Apache Iceberg 则相较于前两者的性能存在较大差距。

选型结果 Selection Result

综合上述三个选型维度以及公司内部数据的实际情况进行全方位的考量,我们最终选择了 Apache Hudi 作为整个湖仓一体架构的数据湖组件,用于在架构底层的分布式存储之上提供统一的数据湖层级和相应的 Table format,并为更上层的数据模型和数据表提供统一的数据湖相关功能与特性 (详见后续架构设计部分)。具体来说,我们选择 Apache Hudi 的原因主要可以从上文分析的三个维度被归纳为以下三点:

  1. 1. 活跃的社区,多样化的贡献者,以及良好的发展势头:不论是从客观指标还是我们参与社区的直观感受,Apache Hudi 都是成为我们架构内数据湖组件的理想之选。首先,虽然收藏总量不如 Deltalake,但在我们的评估期间,由于其具有最多的代码提交 (Pull Requests) 和分支合并 (Merge Requests) 数量,以及良好的问题提出与解决 (Issues) 情况,故我们认为其具备良好的发展势能并在长期内对项目的稳定性做出保障;其次,由于其贡献者有相当一部分来自于国内的顶尖企业,故我们认为 Hudi 更符合在中国进行数据湖实施的基本情况;最后,由于其活跃的社区导致反馈的问题能够及时得到解决,让我们有信心面对和解决在后续的建设过程中可能遭遇的各种困难。

  2. 2. 具备满足我们需求的关键数据湖功能与特性,且对 Flink 具有良好的适配:根据功能性调研,目前 Hudi 是三个数据湖中最符合我们功能需求的数据湖组件。此外,由于团队内的数据开发者多以使用 SQL 为主,而 Hudi 对于 Flink 的集成与支持可以保证团队借助 Flink 的 Table API 撰写 SQL-like 语句进行开发,最小化团队的学习成本,保证开发效率。

  3. 3. 性能满足需求:根据开源社区给出的以及我们亲自进行的性能测试结果,Apache Hudi 均表现出满足我们核心需求的性能。

综上所述,我们选择 Apache Hudi 作为泰康人寿湖仓一体分布式数据平台内的核心数据湖组件,并以此为前提开始进行架构的设计与后续的具体实施工作。

湖仓一体架构的设计与实施 Lakehouse Architecture

架构设计 Architecture Design

在选定了 Apache Hudi 作为数据湖平台层的核心组件后,公司湖仓一体数据处理平台的宏观架构如下图所示。我们以从左至右,自底向上的顺序对该架构中的各个部分逐一进行简要说明,并配以架构设计时的各种思考以供参考。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

数据源:架构图最左侧的部分表示公司内部现有的各种与业务深度绑定的数据库或消息中间件,它们主要以大型物理机配合商用数据库 (i.e. 以 IBM DB2 为主) 或开源数据库所构成,用于存储和处理以业务条线为单元的相关数据。在构建湖仓一体数据处理平台的过程中,这些以项目为单位的商用和开源数据库成为了关键的数据源,作为整个架构数据流程的起始点。此外,对于难以通过数据库连接直接获取的数据,以及绝大部分非结构化数据,诸如 Kafka 的消息中间件或消息队列被大量使用,用于高效稳定地进行数据获取。

数据处理组件:在数据源部分的右侧,是本架构的数据处理组件部分。该部分主要由 Apache Flink 作为主导,辅以较少比例的 Apache Spark 任务。采用 Apache Flink 作为主要数据处理组件的原因主要有以下三点:其一,是由于其流批一体的设计模式,可以为流式任务和批处理任务提供统一的处理方式,减少了开发的工作量;其二,Flink 具备丰富的 Connector 接口 (e.g. Kafka, PostgreSQL, Hudi, etc.) 以及可供自定义的 Connector API,使得在没有相应接口满足需求情况下,我们得以快速开发所需的 Flink 接口 (e.g. 团队以 mysql 的 jdbc-connector 为参考自主研发了 flink-db2 接口) 用于连接所需的数据源;其三,相比于 Spark,Flink 具备 SQL-like 的 Table API,使得我们团队内部的数据开发者能够快速从 DB2 等传统数据库的开发切换至 FlinkSQL 进行开发,从而快速上手新工具而无需学习 Java 等高级编程语言,很大程度地避免了团队的抵触情绪,降低了数据开发的门槛。此外,针对 Flink 批处理任务的调度与流式任务的长期运行,团队内部自研了一套 Flink 任务管理平台,用于监控管理持续运行 (e.g. 运行时长为数周或数月) 的 Flink 流式任务,并每天定时调度 Flink 的批处理任务。

基础设施层:在架构图右侧的最底部,是公司整个湖仓一体架构的基础设施层,用于承载整个数据平台的全部上层建筑。基础设施层主要由两部分所构成:一者为基于物理机的 HDFS 集群,二者为基于泰康云的 OSS 对象存储。前者作为底层平台提供分布式存储及容灾备份的能力,并针对上层隐去了底层存储的细节;后者依赖公司内部的泰康云提供的 OSS 对象存储,为特定类型的数据 (主要是非结构化数据和稀松数据) 提供更为廉价便捷的持久化功能。此二者共同构成了本架构的基础设施层,并为上层提供最基本的数据存储服务。

数据湖平台层:在基础设施层之上,是由 Apache Hudi 构成的数据湖平台层,或者根据 Hudi 官方的描述,该层也可以被称为 “流式数据湖平台层 (Streaming Datalake Platform)”。根据 Apache Hudi 项目的 Project Leader Mr. Vinoth Chandar 在其设计之初的构想 [3],与其将 Hudi 看作是 “一种新的表存储结构 (A table format)” 或是 “在 Hdfs 之上的事务支持层  (a transactional layer upon HDFS)” ,不如说 Hudi 是 “围绕数据库内核构建的一个流式数据湖平台 (a Streaming Data Lake Platform built around a database kernel)” 更为全面和准确。在本湖仓一体架构中,我们采用了 Hudi 创始人的这种理念,以 Hudi 为核心,在基础设施层之上构建了独立的流式数据湖平台层。该层的特点亦可以从其命名被很好地理解。根据 Vinoth 的描述,流式数据湖平台层拥有三大特点:第一是 “流式 (Streaming)”,即 Hudi 从原语层面支持注入 Kafka 之类事件驱动流的增量生产/消费、交互式查询以及快速 Upsert 等操作;第二是 “数据湖 (Datalake)”,即拥有所有数据湖的特性,比如快速注入 (Fast Ingestion)、事务支持 (Transactional support) 等;第三是 “平台 (Platform)” ,即 Hudi 可以作为一个独立的架构层 (layer) 保证可靠性的同时对外或其他架构层级提供易用的服务。基于 Vinoth 对于 Hudi 的定义以及上述三点特性,我们将 Hudi 作为一个独立的数据湖平台层设计在架构之中,起到连接基础设施层与数据建模层的作用,并搭配基础设施层对上层提供 Hudi 的丰富特性 (e.g. 事务支持,准实时查询,etc.) 作为支持和底层保障。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

Ps: Hudi 项目创始人在其博客[3]中绘制的幽默漫画,用于说明 Apache Hudi 的本质是包含 “Transaction Layer” 与 “Table Format” 等特性的流式数据湖平台 (Streaming Datalake Platform),并感叹似乎没人真正理解这一点。

数据建模层:在数据湖平台层之上,是数据架构师们熟悉的数据建模层。由于采用了湖仓一体架构,因此我们将所有与数据建模相关的流程放置在这一个层级中,并将它们统称为数据建模层,以便使架构层次显得更直观更简洁。该层主要用于加工和管理从 Apache Flink 和 Spark 通过 Hudi Connector 获取并持久化在文件系统上的数据。以 Flink 为例,数据从数据源经由 Flink 以流式任务或批处的形式加工处理并通过 Hudi Connector 存储为对应的数据文件 (e.g. Parquet) 作为数据准备区,并继续通过流式或批处理 Flink 任务以 Hudi to Hudi 的方式进行数据建模,最终成为复核用户需求、可供直接使用的数据集市。由于该层次内所有表的底层都由数据湖平台层提供支持 (i.e. 其 Table format 均为 Hudi),故所有表都具备 Hudi 所提供的特性,比如大批量快速注入/查询、支持事务、Upsert 插入以及准实时的边插边查功能,为更上层的数据访问和数据服务提供了众多关键特性支持。

数据访问层:位于数据建模层之上的,是由各种数据查询和数据访问组件组成的数据访问层,其主要起到数据发现、元数据管理、以及访问控制和权限管理的作用,同时为数据需求方或使用方提供符合其使用习惯的客户端或用户接口。Apache Hive 作为该架构层中的绝对核心,用于持久化数据建模层创建的众多数据库和数据表的元数据信息,对用户提供数据的宏观概览,帮助用户进行数据的发现和数据的理解。同时,搭配 Kerberos 以及 Hive 的权限控制机制 (或者 Apache Ranger 等其他工具),数据访问层还能对用户进行身份认证和权限控制,对用户的数据访问和数据使用进行精细化管理。此外,本架构层还包括其他热门的数据查询组件 (e.g. Trino, Clickhouse, etc.),以及为数据应用开发者提供的用于获取数据的 REST APIs,在进行访问控制和满足法律合规要求的同时,为数据使用方提供多样化的数据访问服务以满足其需求。

数据应用层:数据应用层位于整个湖仓一体架构的最顶层,用于对整个架构治理的全部数据进行综合性的应用。如图所示,该架构层可以提供丰富且多样化的数据服务或数据应用,以适配大健康领域高速的发展并满足复杂的业务需求,比如用户数据分析、即席查询、数据可视化、销售战报等等。正如繁硕的果实离不开牢固的树干和树根,顶层琳琅满目的数据应用也离不开湖仓一体架构底层各层级的坚实支撑。

至此,泰康人寿湖仓一体数据处理平台的架构和设计时的思考已经大致介绍完毕。下面将简要阐述架构的具体实施部分,并分享一些实施过程中遭遇的困难以供读者参考。

架构实施 Architecture Implementations

任何项目从顶层设计到具体实施落地都不是一帆风顺、一蹴而就的,泰康人寿湖仓一体数据处理平台的建设实施也同样不例外。历时数月,从最底层的物理机实体与操作系统的管理、HDFS 与 Yarn 集群搭建,再到实时计算引擎 Flink 的版本选型、流批一体任务管理、与 Hudi 和 Hive 的适配与集成,再到其上的数据仓库内的模型构建与元数据管理,直至最后在顶层的数据访问与应用,架构实施期间涉及的实施细节实在太过庞杂,此处便不再逐一赘述。相应地,我们将架构实施在落地过程中各组件的版本选型在此处进行整理,以帮助读者规避在建设过程中可能产生的版本冲突等问题;同时,我们还挑选了架构实施过程中遭遇的比较有代表性、有价值的问题或解决方案在此处分享,以供读者参考。

版本选型 Version Selection

架构内组件版本的具体选型一直是架构建设与集成工作中的重要环节,也是决定整体架构能否稳定运行的关键。此处,在进行了大量调研和试错后,我们将目前架构内部组件的具体版本整理于此,以供读者进行参考。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

典型问题与解决方案 Typical Problems & Related Solutions

架构的具体建设与实施的过程总是充斥着繁杂的细节,而如果将其全部逐一赘述将会导致整篇文章变得庞杂而混乱。由于本文介绍的重点为基于 Apache Hudi 建设湖仓一体分布式数据平台,故在此处我们主要分享三点在使用 Apache Hudi 建设数据湖平台层时实际遭遇的问题,以及经过实践所得到的行之有效的解决方案。

  1. 1. 数据湖平台层中 Hudi 表的元数据管理的相关问题与解决方法: 元数据的管理是任何数据架构中都无法忽视的关键问题,数据湖的元数据管理同样不例外。由于 Apache Hudi 拥有自己的元数据结构并倾向于将之存储在 HDFS 的对应目录中,故若不对元数据进行精心管理则会显著增加数据使用的各项成本 (e.g. 沟通成本、运维成本、etc.)。为了解决此问题,我们在数据湖中的 Hudi 建表时,将其元数据同步至集群内 Hive Metastore 的相应数据库中,并以集群为单位对元数据进行治理。而在数据访问时,我们使用 Trino 将多个 Hive 以 Trino Catalog 的形式进行再一次汇总,以确保用户能够统一地访问位于多个集群的基于数据湖存储的数据表。相关详细资料请综合性地阅读官方文档: Apache Hudi – Syncing to Hive Metastore [10] 以及 Trino – Hive connector [11]。

  2. 2. 数据湖组件 Hudi 快速注入导致 HDFS 上零散小文件过多的问题与解决方法: 多种格式数据的快速注入是数据湖的主要特性之一,也是使用数据湖的首要功能需求。然而,如果不进行妥善管理,则快速注入的数据将会在底层数据存储中分散成众多零散的小文件,极大影响底层存储的性能,并对架构整体的稳定性产生严重威胁。根据我们的测试,使用 Copy-On-Write 方式虽然可以满足数据初始化及快速注入的时间需求,但每千万条数据会导致底层 HDFS 上出现几万个独立存在的数据文件,进而严重影响集群的健康情况。针对这种情况,数据湖相关的开源社区也一直在进行各种努力,包括开发异步文件聚类、异步文件清理,以及优化 Merge-On-Read 表的性能等。此处,我们使用了通过 Spark 在数据快速注入后进行 HDFS 文件聚合及清理的方式,将快速注入后产生的数十万个小文件聚合成不足百个,大幅降低了底层存储中的文件数量,显著提升了数据湖的稳定性。相关详细资料请参考笔者博文: Apache Hudi 使用文件聚类功能 (Clustering) 解决小文件过多的问题 [12]。

  3. 3. 基于 Kerberos 进行数据湖平台层中数据表的安全性保障: 适配 Kerberos 的 Hudi 源代码修改与优化: 信息安全始终都是在架构建设时被各方关注的焦点,故数据湖的建设也必须同样考虑到安全机制。虽然许多人认为安全机制会阻碍架构建设或任务开发的效率,但是集群长期稳定的运行却同样离不开安全机制。作为一个较为新颖的组件,Hudi 目前版本对于安全机制的支持始终显地不那么完善,特别是在其与开启了 Kerberos 认证的 HDFS 或 Hive Metastore 这些经过多年沉淀的老牌组件进行交互时,安全性支持的不完备就显得尤为明显。为了确保 Hudi 能够与架构中其他开启 Kerberos 认证的组件无缝交互,我们针对 Hudi 的底层源代码进行了修改和优化,并使其完美地嵌入到 Kerberos 的安全体制之中。相关详细资料请参考笔者博文: 通过源代码修改使 Apache Hudi 支持 Kerberos 访问 Hive 的功能 [13]。

基于 Apache Hudi 的数据湖功能扩展 Customizable Improvements

在对于泰康人寿的湖仓一体架构有了基本的了解后,接下来我们将详细阐述针对泰康方案对于底层数据湖组件 Apache Hudi 进行的定制化改造与功能研发,并挑选了一个实际的落地场景用于体现和说明自主研发功能的宝贵价值。

大健康领域与泰康方案 Big Health & The Taikang Solution

如前文所述,随着国家《健康中国行动 (2019-2030年)》[14] 等相关文件的出台,人民健康和慢性非传染性疾病防治的受重视程度再次被推向了一个新的高点,为保障民生福祉的 “大健康” 概念也顺势产生并迅速得到社会各界的广泛关注。根据中商产业研究院 [15] 和中国社会科学院学者 [16] 的定义与解读,大健康是建立在传统健康认知之上的一个扩展性的概念,即以保障 “身体、精神和社会处于完好状态” 为根本目的的同时,将实现目的的途径由 “治病为中心” 转变为 “为以人民健康为中心”,由 “治已病” 转变为 “治未病”;而大健康领域,指的是由传统健康产业 (e.g. 医疗服务产业,制药产业,医疗器械产业,etc.) 与范健康产业 (e.g. 健康类保险,医疗护理,理疗康复,养生保健,etc.) 共同构成的大健康产业所涉及的诸多领域,包括医疗服务、康养服务、健康保障 (i.e. 保险服务,救援服务,etc.)、养老服务等几大板块。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

针对大健康领域的特征,泰康人寿采用保险与养老、保险与医疗、保险与养老金和资产管理相融合的方式,专注打造 “长寿,健康、富足” 三大闭环,以保险作为核心支点和客户支付的主要途径迅速进军并深耕大健康领域的多个重要板块,为增进人民福祉做出切实的贡献。以主力产品 “幸福有约” 为例,根据泰康人寿创始人陈东升先生在《幸福有约第一课》[17] 中的讲述,泰康人寿首创以 “养老社区入住确认函” 为纽带,将虚拟的保险与实体的养老融会贯通,既规避了养老社区精算困难的症结,又保证了客户支付渠道的便捷,即客户可以通过购买保险的方式获得未来入住养老社区的资格,进而满足养老的需求。借助这种 “以保险为支点搭配其他产业” 的创新思维与商业模式,泰康在大健康领域获得了广泛的商业成功并保持着良好的发展态势,持续不断地以市场经济的方式全心全意为人民服务。

基于公司战略对数据湖功能进行的改良 Improvements Based on Strategies

泰康人寿针对大健康领域实际情况所制定的上述战略和商业模式,为科技的创新与应用提供了肥沃的土壤,我们湖仓一体架构中的数据湖组件 Apache Hudi 便是其中的受益者。作为衔接上层数据模型与底层数据存储的关键层级,如果数据湖平台层的核心组件 Apache Hudi 能够从源代码级别就针对泰康方案 “三大闭环” 的战略进行定制化的功能扩展与性能优化,那么整个湖仓一体架构在公司的落地与使用将会更加如虎添翼,做到真正高效地治理公司的数据资产,为公司未来的发展做好数据层面的保驾护航。

下面,我们将会结合泰康人寿在大健康领域的战略与商业模式,简要说明我们针对数据湖 Apache Hudi 所作出的功能改进及取得的正向效果。

“三大闭环” 与流式计算引擎中基于主键的多字段分片插入更新功能 Improvement No.1

如前文所述,泰康人寿坚定地打造由 “长寿,健康,财富” 所构成的三大闭环,以保险作为核心支点和主要支付手段,整合 “保险+养老”、“保险+医疗”、“保险+养老金和资产管理” 等大健康领域内多个板块的资源并向市场提供服务,并最终形成了在中国人均寿命再创新高的长寿时代独树一帜的泰康方案。

基于 “三大闭环” 的核心战略,我们不难看出,其本质是 “以保险为主体和核心,对于多个产业和领域的资源进行整合”,而从数据的角度来进行翻译,就变成 “以保单信息为核心数据,对其他各个产业的数据进行关联整合” ,即:在数据层面,通过一个特定记录的主键 (e.g. 保单记录的保单号) 对于其他的相关联的记录 (e.g. 养老社区的相关信息,牙科诊疗的相关信息,etc.) 进行整合。因此,倘若作为泰康人寿湖仓一体架构基石的流式数据湖平台层能够对这项功能进行源代码层面的原生支持,则在未来将会节省大量在数据模型层的修改和开发的繁琐工作,且会对公司战略的实现以及未来长期的发展大有裨益。由此,基于对于公司战略的理解以及在数据领域的专业知识和经验,我们基于 Apache Hudi 实现了流式数据湖平台层的 “基于主键的多字段分片插入更新功能”。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

上述功能的具体含义为,在实时计算的场景下,具有相同主键的多条记录可以在结果表中自动寻找到属于自己的字段范围,并进行定向更新。该功能在注重准确性的批处理场景下已经存在多年,但在注重时效性的实时计算与数据湖领域却仍未被实现。如果读者仍觉得该描述较为抽象,我们不妨来看下面这个例子:一张数据的整合表具有共计 31 列字段,其中第一个字段列 C0 为保单号,从 C1-C10 为保单相关数据列,C11-C20 为养老信息相关数据列,C21-C30 为牙医数据诊疗字段列。在未使用自主研发的功能前,每次实时计算引擎的增量插入 (UPSERT) 操作都会仅保留与自己相关的信息而将其他列抹除 (比如,C11-C20 养老社区信息的更新会将已经存在的 C1-C10 保单信息置空抹除,因为数据湖会默认 C1-C10 的空值即为最新数据,需要将原有已经存在的 C1-C10 的保单信息覆盖掉才是正确的),因此数据湖便难以起到直接将多个表的数据整合至一张宽表的功能;而在使用了自主研发的功能后,数据湖可以直接将多段信息整合成一行完整的记录 (同时涵盖保单信息、养老信息、以及牙医诊断信息,各部分的空值不会将已有值覆盖掉),甚至无需借助实时计算引擎 (e.g. Flink) 的状态即可完成该操作,这为计算资源的节约与开发流程的缩减都能起到极大的帮助作用。

“泰康方案” 与流式计算引擎中基于多个事件时间字段的数据准确性保障机制 Improment No.2

根据上文描述,“泰康方案” 的本质,就是将虚拟的保险支付与实体的医养服务创新结合,通过长期稳定的投资实现复利现象,积累充足的财富资源,在人们老年的时候享受长寿、健康、富足的生活方式。因此,我们可以清晰的发现,与 “泰康方案” 和大健康领域特征相关的数据,一定都对准确性有着严苛的要求。由于这些数据往往都涉及高度敏感 (保单金额,用户缴费,用户信息,etc.) 的信息,故数据处理过程中的丢数漏数或不准确是绝对不会被容忍的。由此,我们可以发现,一种基于数据湖的数据准确性保障机制必须被设计实施,才能保证湖仓一体架构在大健康领域被广泛应用。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

基于上述原因,我们基于数据湖 Apache Hudi 和实时计算引擎自主研发了名为 “基于多个事件时间字段的数据准确性验证” 的一种数据准确性保障机制 (目前,Apache Hudi 一张表仅支持一个 eventime 验证字段)。该机制可以自动判定入湖的数据是否具备最新的事件时间,并对延迟数据或不正确数据进行自动筛查和处理。举例而言,客户产生的两条信息 I1 和 I2 由于网络延迟等原因没有按照正确数据进入数据湖,倘若本应被存储的最新状态 I2 先于旧状态 I1 经过流式计算引擎入湖,则数据湖就会选择旧状态 I1 进行存储而丢弃 I2,最终导致数据产生偏差;在利用了我们自主研发的数据保障机制后,不论 I1 和 I2 以何种顺序入湖,该机制都会按照顺序对数据进行处理,并保证最新状态 I2 被作为最新状态持久化。此外,该机制配合上述 “基于主键的多字段分片插入功能” 共同使用,可以实现结果表中各部分字段 (保单信息、养老信息、医疗信息) 的数据在保证准确性的基础上分段更新、互不干扰,从而为后续更多业态的数据整合提供坚实的底层技术保障。

落地场景与应用成果 Application Secnarios & Achievements

落地场景简介 Application Secnarios

任何自主研发的功能都必须经过真实业务场景的实践检验才能证明其实用性并体现其真正价值,我们基于数据湖 Apache Hudi 所研发的上述功能也同样不例外。由此,在新功能的应用与实践阶段,我们综合考虑了许多业务,最终再一次选择了前文提到过的 “保单实时受理业绩” 的应用场景。此场景可谓与新功能高度契合:首先,作为泰康 “三大闭环” 战略的核心,保单实时受理数据由于其对于数据的时效性与准确性均有严格要求,因此是我们用于验证基于流式数据湖平台层所研发的新功能的理想试验田;其次,“保单实时受理业绩” 需要使用 “公司+保单号” 作为核心主键,用于整合包括保单信息、代理人信息在内的多部分信息至一张结果表,其内在数据逻辑具备丰富的信息整合场景,因此可以为验证 “基于主键的多字段分片插入功能” 提供丰富的实验和测试场景;最后,在 “保单实时受理业绩” 的应用场景中存在着保单的多状态转换,即遵循从“受理”到“代转”直至“预收”的保单状态转化流程,故非常适用于验证为了 “泰康方案” 而专门设计研发的 “基于多个事件时间字段的数据准确性保障机制” 相关功能。综合上面三点考量,我们选择了该业务场景用于检验基于 Apache Hudi 自主研发的上述两个功能。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

数据湖自主研发功能的应用成果 Achievements of Customizable Improvements

令我们感到欣慰的是,基于数据湖研发的新功能在 “保单实时受理业绩” 业务场景中的发挥超出预期,在保障数据准确性的基础上真正发挥出了数据湖的独特价值。其独特价值主要可以被分为两个方面:第一,“基于主键的多字段分片插入功能” 由于其摆脱了流式计算引擎对于状态的依赖,而真正做到了流数据与批数据的统一处理,极大发挥了湖仓一体架构带来的 “流批一体” 数据处理方式的价值,并大幅缩减了数据处理流程,提升了数据研发者的开发效率;第二,“基于多个事件时间字段的数据准确性保障机制” 保障了数据的传递即使出现延迟,保单状态的变化 (受理、待转、预收) 也能通过保障机制被自动排序处理,并在最终的结果表中始终保持着最新的、准确的状态。除此之外,数据湖的快速注入、事务支持等特性也被广泛使用并为架构上层提供可靠支持。

截至目前,使用经过我们改造的数据湖所研发的 “保单实时受理业绩” 数据流程已经在泰康人寿湖仓一体分布式数据平台上稳定运行了超过一年的时间,其日均处理的数据量非常可观:抛开中间过程不论,仅在最终结果表中,平均每日处理的保单更新总记录数就超过 50 万条,涉及的保单记录操作总量更是超过日均 600 万次;如果算上各种中间过程,日均链路总操作记录条数更是达到数千万次。更令人振奋的是,经过与批处理系统的数据比对,我们发现数据完全一致:采用实时计算引擎的数据湖,竟然没有任何一条数据丢失或者产生偏差;换言之,数据在实时计算的场景下准确率居然达到了 100%。由此,我们相信,经过我们改良的数据湖组件与整个湖仓一体数据处理平台将会在日后泰康人寿和大健康领域内丰富的应用场景中发挥更多难以估量的价值,为公司的战略与发展保驾护航。

架构总体应用成果 Achievements of Architecture Application

此外,在架构总体应用的层面,自泰康人寿湖仓一体分布式数据处理平台投入生产以来,其治理的数据规模以及涵盖的业务种类经历了持续性的高速增长。截至目前,本数据平台管理的实时计算作业总数量已达近 100 个,调度与 ETL 任务总数量超过 1200 个,存储的数据总量将近 300 TB,并持续保持快速增长的态势;其治理数据所涉及的业务种类也体现出丰富的多样性,包括:用户行为分析、合规监管、超体 OLAP 分析、方案激励、实时指标、数据可视化等等。随着公司战略的进一步落实以及在大健康领域持续深入的探索,本数据平台将会承担更多的数据职能以及更重要的责任,为公司战略的落实以及业务的发展贡献属于自己的价值。

后续工作 Further Works

根据泰康方案的逐步落实与推进,以及大健康领域的实际情况,泰康人寿湖仓一体分布式数据处理平台的后续建设及发展重心主要会将被聚焦在如下三个方面:

  1. 1. 在保障易用性的前提下持续集成更多组件以满足大健康领域丰富的业务需求: 由于近年来大健康领域的迅猛发展,业务方对于数据的需求也变得前所未有地多样化。使用湖仓一体架构集中对数据进行集中治理只是一个开端,数据价值的真正体现往往离不开实际的应用。因此,在后续对更加丰富的数据应用的支持 (包括对机器学习、深度学习模型的适配、对推荐算法或更复杂决策系统的支持等) 将会成为湖仓一体架构发展的首要目标。

  2. 2. 进一步完善平台的监控机制、容错机制以及灾害恢复机制,以持续提升平台的健壮性和可靠性: 作为整个公司新的数据类基础设施,湖仓一体数据处理平台将会在未来治理种类更加丰富、数量更加庞大的业务数据。因此,作为基础设施的健壮性与可靠性就变得尤为重要。如何在持续集成众多组件的同时始终保持数据平台的高可用性将会成为后续工作关注的重点。

  3. 3. 根据大健康领域的业务特点持续对数据湖组件 Apache Hudi 进行持续优化: 与所有的业务相同,大健康领域的相关业务也具备区别于其他领域的独特性,这在保险与医养和资管相融合的业务场景中体现的尤为明显。如何借助数据湖组件 Apache Hudi 中提供的众多可自定义特性 (e.g. Customized Filters, Customized Payloads, etc.) 来最大程度地适配大健康领域的业务特征,并优化其作为底层数据基础设施的性能,也是在后续工作必不可少的环节。

小结 Summary

本文详细介绍了泰康人寿湖仓一体分布式数据处理平台的建设过程,以及在大健康领域内针对 “泰康方案” 和 “三大闭环” 等公司核心战略进行的定制化设计、改进与实施的详细落地过程,并简要分享领域实践心得和部分应用成果。随着公司战略的进一步落实以及在大健康领域持续深入的探索,我们相信,本数据平台和其中的核心组件 Apache Hudi 将会承担更多的数据职能以及更重要的责任,为公司战略的落实以及业务的发展贡献属于自己的独特价值。

万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践

作者简介 About the Authors

技术指导: 王可

泰康人寿 数据架构资深专家工程师

深耕金融领域数据架构多年,具备丰富的架构设计和实战落地经验,对大数据相关技术在金融领域的应用拥有独到的见解。

文章作者: 田昕峣

泰康人寿 数据研发工程师

澳大利亚悉尼大学工程学硕士、管理学硕士。在求学及职业生涯期间,深耕大数据基础架构与开源项目等领域,并积极探索数据领域内先进方法论和技术与金融与大健康领域高效有机结合的方式方法。工作期间曾多次参与设计和实施企业内部大数据集群和数据平台的建设工作,精细化构建团队知识库,并周期性地将团队取得的优秀成果向行业及社区进行展现。

欢迎交流,联系方式: 知乎主页: Xinyao Tian – 用户主页 | CSDN: Xinyao Tian – 会员中心 | LinkedIn: Xinyao Tian’s Profile

参考文献 References

  • • [1] Microsoft – What is a Data Lake? [https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-a-data-lake/]

  • • [2] IBM – What is a data warehouse [https://www.ibm.com/topics/data-warehouse]

  • • [3] Vinoth Chandar – Apache Hudi – The Data Lake Platform [https://hudi.apache.org/blog/2021/07/21/streaming-data-lake-platform/]

  • • [4] Apache Iceberg – Official Website [https://iceberg.apache.org/]

  • • [5] Apache Hudi – Official Website [https://hudi.apache.org/]

  • • [6] Delta Lake – Official Website [https://delta.io/]

  • • [7] Onehouse – Apache Hudi vs Delta Lake – Transparent TPC-DS Data Lakehouse Performance Benchmarks [https://www.onehouse.ai/blog/apache-hudi-vs-delta-lake-transparent-tpc-ds-lakehouse-performance-benchmarks]

  • • [8] IBM – What is a data lakehouse? [https://www.ibm.com/topics/data-lakehouse]

  • • [9] Apache – Briefing: The Apache Way [https://www.apache.org/theapacheway/]

  • • [10] Apache Hudi – Syncing to Hive Metastore [https://hudi.apache.org/docs/syncing_metastore/]

  • • [11] Trino – Hive connector [https://ta.thinkingdata.cn/trino-docs/connector/hive.html]

  • • [12] Xinyao Tian – Apache Hudi 使用文件聚类功能 (Clustering) 解决小文件过多的问题[https://blog.csdn.net/weixin_38070561/article/details/126548227]

  • • [13] Xinyao Tian – 通过源代码修改使 Apache Hudi 支持 Kerberos 访问 Hive 的功能[https://blog.csdn.net/weixin_38070561/article/details/131981538]

  • • [14] 中华人民共和国中央人民政府 – 《健康中国行动 (2019—2030年)》[https://www.gov.cn/xinwen/2019-07/15/content_5409694.htm]

  • • [15] 中商产业研究院 – 2021年“十四五”中国大健康产业市场前景及投资研究报告 [https://www.askci.com/news/chanye/20210702/1733311504828.shtml]

  • • [16] 唐均 – 大健康与大健康产业的概念、现状和前瞻:基于健康社会学的理论分析 [https://caoss.org.cn/UploadFile/pic/2020101310303786123.pdf]

  • • [17] 陈东升 – 幸福有约第一课 [https://www.sohu.com/a/593416882_121124541]

 

Read More 

正文完
可以使用微信扫码关注公众号(ID:xzluomor)
post-qrcode
 
评论(没有评论)
Generated by Feedzy