物化视图, Materialized View, 在数据管理系统中指将视图的查询和计算的结果保存为一个物理表,这样每次访问视图时,无需重新执行查询,从而提高了查询效率。物化视图针对一些需要做大量频繁的聚合计算,以及复杂关联的场景下,是一个非常行之有效的提高性能降低资源使用的数据架构模式。
(图片来源: https://blog.the-pans.com/caching-partially-materialized-views-consistently/)
取决于视图的更新模式,可以分为全量更新的和实时(增量)更新的两种。
️全量更新
全量更新策略在每次更新时都会清除物化视图中现有的所有数据,并将最新的查询结果集重新插入。这个过程可以理解为执行了TRUNCATE TABLE和INSERT INTO SELECT的组合操作。全量更新虽然简单直接,但在大数据量或高频更新的场景下,其效率和资源消耗可能成为一个问题。
️实时(增量)更新
增量更新策略则更为高效,它仅针对自上次更新以来发生变化的数据部分计算物化视图的差异,并将这些差异应用到物化视图中。增量更新能以更少的资源消耗,提供一个更为实时的数据体验。
实时更新物化视图的适用场景我们周围有很多业务场景需要我们的视图提供当前的状态,例如:
️1. 金融交易系统中的余额更新
在金融系统中,用户的账户余额会频繁变动(如存款、取款、转账、投资等操作)。为了在用户每次交易后,能够实时查看其账户总的余额,通常会使用实时更新的物化视图来确保用户在执行交易后,能够立刻查询到最新的账户状态。
️场景需求:
️示例:
️2. 库存管理系统中的实时库存
在电商平台或仓储系统中,库存的实时管理非常关键。每次销售、退货、补货都需要及时反映到系统中,以避免超卖或库存不足的问题。特别是在使用多平台进行销售时,使用多源汇聚及实时更新的物化视图可以确保在每次库存变更后,系统展示给用户的库存信息是最新的。
️场景需求:
️示例:
3. 实时监控和告警系统
在一些生产系统或 IT 监控平台中,监控指标(如 CPU 利用率、内存占用、网络流量等)会频繁变化。此类系统需要根据实时数据判断是否触发告警。因此,可以通过实时更新技术来随时更新指标的物化视图,以便立即发现异常情况并触发告警。
️场景需求:
️示例:
️4. 客户关系管理(CRM)系统中的实时客户状态
在 CRM 系统中,客户的行为数据(如打电话、发邮件、订单记录等)经常发生变动。业务人员希望能够实时看到客户的最新互动记录、订单状态等,以便根据最新情况及时跟进客户。因此, 在每次客户数据更新时刷新物化视图,使得业务人员在查看客户详情时能够看到最新信息。
️场景需求:
️示例:
️5. 实时推荐系统中的用户行为数据更新
在电商或内容平台的推荐系统中,用户的行为(如点击、浏览、购买等)会实时影响推荐的结果。为了保证推荐结果的实时性,系统可以在每次用户行为数据变更后,使用实时更新物的化视图,从而使推荐系统能根据最新的用户行为数据生成推荐内容。
️场景需求:
️示例:
实时更新物化视图的实现方式,可以分为两大类别:
我们先来看一下第一类,不依赖于第三方组件,直接使用数据库的能力。
️基于数据库自身能力的物化视图实时更新模式
(图片来源:https://oracle-base.com/articles/misc/materialized-views)
️1. Oracle Database
Oracle 通过物化视图(Materialized View)以及物化视图日志(Materialized View Log)来支持基于事务提交的实时刷新。
️2. PostgreSQL
PostgreSQL 可以通过触发器(Trigger)来模拟这一功能。在事务提交时,触发器可以用来更新物化视图。
CREATE OR REPLACE FUNCTION refresh_materialized_view()
RETURNS TRIGGER AS
BEGIN
REFRESH MATERIALIZED VIEW mv_example;RETURN NEW;
END;
LANGUAGE plpgsql;
️3. MySQL
MySQL 并不原生支持物化视图的概念,但可以通过 ️触发器 和 ️表复制 来模拟物化视图功能,配合触发器实现类似 实时更新的效果。
CREATE TRIGGER refresh_mv_trigger
AFTER INSERT ON source_table FOR EACH ROW
BEGIN
-- 手动更新物化视图逻辑
END;
️4. Snowflake
Snowflake 提供了一种称为 ️Materialized Views 的特性,可以为大规模数据集实现增量刷新。虽然 Snowflake 没有提供 ️On Commit Refresh 的功能,但它可以通过 ️自动刷新 实现接近实时的数据更新。
️示例:
CREATE MATERIALIZED VIEW mv_example
AS SELECT column1, COUNT(*)
FROM source_table;
️5. ClickHouse
ClickHouse 提供了一种基于 ️物化视图(Materialized Views) 的机制,能够实现对实时数据的近实时处理。通过依赖表自动触发物化视图的更新。
CREATE MATERIALIZED VIEW mv_example
TO target_table
AS SELECT * FROM source_table;
️6. BigQuery
Google BigQuery 支持 ️物化视图(Materialized View),这些视图并不会在每次数据更改时自动更新,但支持周期性刷新。对于部分业务需求,可以通过触发刷新机制,在数据提交时强制刷新物化视图,达到类似实时更新的效果。
CREATE MATERIALIZED VIEW mv_example
AS SELECT column1, COUNT(*)
FROM source_table;
我们可以看到,除了Oracle 数据库提供了原生的基于事务级别实时更新视图能力之外,其他的都是通过触发器,或者定时自动刷新的方式来模拟。对实时要求比较高的场景,支持上并不理想。
另外,使用数据库自身能力也意味着你只能在数据库内部创建物化视图,对多源,跨库,读写分离,以及不希望给原库增加压力的场景,都无法使用这种模式。在这些时侯,我们需要使用一个支持CDC数据复制和流式计算的实时数据平台来实现。
️基于CDC数据复制和流式计算来实时更新物化视图
这种方案通常需要几个模块一起配合来完成,如:
我们以一个订单宽表为例子来说明这个实现方式。我们有一个MySQL的电商平台,我们希望提供一个包含完整信息的订单API(如客户信息,商品信息,物流信息等)提供给客户的手机端来查询。由于MySQL 的并发查询和关联查询性能有限,我们选择了在能够提供相对较高查询性能,并支持 JSON 结构(API 模型设计)的 MongoDB 里构建一个物化视图的方式来支持这个 API。
换句话来说,假设这个是MySQL 数据库的表结构:
我们希望有这样的一个视图,可以直接用来给到客户端通过order_id 或者 customer_id 来查询客户订单。这个API JSON 的结构可能是下面这样,一个模型里包含了订单,客户地址,付款信息和订单明细。
为了达到这个效果,我们需要将 订单表(ecom_orders)与 订单明细表 (ecom_order_items), 客户信息表(ecomm_customer,形成一个宽表(OrderView),并使用 MySQL Debezium Connector + Kafka Connect + kakfa broker + Kafka Streams 实现持续刷新,这里将会介绍一个完整的步骤来达成这一目标。
️方案步骤
️Prerequisites
️Step 1: Set up Kafka broker, Zookeeper, Schema registry, and Kafka Connect
️Step 2 Install Debezuim Mysql Connector in Kakfa connect
️Step 3 Deploy a Debezium MySQL Connector
If the connector status shows as RUNNING, your MySQL data is now streaming into the Kafka broker in real-time. Each change (insert/update/delete) made to the MySQL database will be captured by debezuim MySQL connector and sent to the Kafka broker.
At this stage, you have successfully set up real-time data streaming from MySQL to Kafka broker.
️Step 4 Real-Time Data Streaming from Kafka broker to MongoDB
Now that the data is streaming in real-time from MySQL to Kafka, you can consume this data and map it to MongoDB using a custom node.JS Script. This application uses the kafkajs streaming library to consume messages from Kafka topics and the mongodb library to store this data in MongoDB.
In this example, we have an eCommerce database with orders, order items and customer details. We consume this data from Kafka topics and enrich order with related customer information and order items before writing it to MongoDB.
️小结
使用Debezium MySQL连接器与Kafka Connect相结合,可以方便地将变更数据捕获(CDC)传输到Kafka代理。通过Node.js中的Kafka Streams库,可以执行实时数据流处理和转换。此配置会从MySQL数据库中捕获更新,实时处理这些更新,并在将数据结果存储到MongoDB之前对其进行转换和映射。
Tap Flow,支持CDC的物化视图构建利器什么是Tap Flow
Tap Flow 是一个TapData 实时数据平台提供的一个流式数据采集和处理的框架。开发者可以使用Tap Flow来实现实时数据复制,实时数据加工处理,多表流式合并,构建实时更新的物化视图等技术场景。
使用上面同样的例子,我们来看看用Tap Flow 会是怎样的一个体验。
使用 Tap Flow 构建一个订单宽表
️主要流程:
️详细步骤:
️Step 1: 安装 Tap Shell, 一个Tap Flow 的Python SDK 和交互式命令行界面
️Step 2: Start and Configure Tap Shell
️Step 3: Start Building Materialized View
Step 3.1: Set Up Connection with Source databases.
️ Step 3.2: Create data pipeline to build wide order data model
️ Step 3.3. Start Data pipeline
Step 3.4. View the flow stats
️ Step 3.5. View Wide Order Data model in MongoDB
️验证物化视图的实时更新效果
执行下述脚本在 ecom_orders table 里新增记录:
️select ️count(*) ️from ecom_orders eo;
Run below select query to see updated prices scripts works
TapFlow是一个编程框架,目前还处于 Preview 状态。它允许您执行实时数据复制、数据处理以及创建物化视图等操作。它由一组API、Python SDK以及Tap CLI(一个命令行实用程序)组成。和常见的实时数据管道或者集成方案(如Kafka ETL)相比,使用Tap Flow 的优势是:
TapFlow 现已开放内测版本,获取方式指路>>>原文文末