一份《福布斯》的最新报告指出,一些证券经纪商和交易公司能够比竞争对手更快地获取并分析数据,从而“在大众之前的微秒级时间里以最佳价格成交。就时间而言优势微乎其微,但在洞察速度带来的竞争优势上却极其巨大。”
在评估分析解决方案时,洞察速度至关重要——组织能越快地根据数据变化做出响应,就越具竞争力。在许多场景中,为得到所需洞察,数据必须先被转换。正如第 3 章《设置数据模型与数据摄取》简要讨论的那样,你可以采用 ETL(在外部应用中读取源数据、执行转换并加载结果),也可以采用 ELT(先把数据加载进 Amazon Redshift,再利用其计算能力就地转换)。
本章将首先比较 ELT 与 ETL 策略,帮助你在构建数据仓库时做出选择。随后我们会深入 Redshift 针对分析场景打造的特性,说明如何执行库内转换(In-Database Transformation) ,以及如何利用内置的调度与编排能力运行管道。接着介绍 Redshift 如何把 ELT 策略更进一步,让你访问全部数据——即使这些数据并未加载进 Redshift。最后,我们会说明在何时采用外部转换策略更合适,并展示如何使用 AWS Glue Studio 构建 ETL 流水线。
比较 ELT 与 ETL 策略
无论采用 ELT 还是 ETL,二者都能支持数据平台的共同目标:清洗、转换与汇总,以便将数据加载到报表数据模型中。这些都很耗资源,主要差异在于计算发生的位置:要么在 ETL 服务器上,要么在数据仓库平台上。
- ETL:从多个来源读取数据,使用 ETL 引擎的函数与能力完成转换。
- ELT:同样抽取多源数据,但先加载进数据仓库,再用熟悉的 SQL 语义执行转换。
选择时可考虑以下因素:
性能与可扩展性
ETL 过程依赖 ETL 服务器的资源,需要负责人正确管理与扩容。你可以用 Spark 等计算平台并行化转换;AWS Glue 也提供了Serverless 的 ETL 管道选项。ELT 则利用数据仓库的计算资源;对 Amazon Redshift 而言,就是利用 MPP 架构的威力来执行转换。历史上常偏好在库外转换,以把负载从数据仓库移走;但现代数据仓库(含 Redshift)可弹性扩展并支持混合负载,令 ELT 更具吸引力。再者,数据仓库天生就是为处理与转换海量数据而设计的,ELT 作业通常更快;同时避免了 ETL 进出网络搬运数据的瓶颈。
灵活性
无论何种策略,转换代码都应有开发生命周期。ETL 通常由具备专门技能的团队在外部应用中管理。ELT 则把原始数据留在平台内,分析师可用熟悉的 SQL 编写转换,快速原型化并校验业务逻辑;平台所有者负责优化与调度,从而缩短交付周期。
元数据管理与编排
采用 ELT 时,平台方需要记录作业、依赖与调度。ETL 工具通常自带能力来捕获并组织源/目标/作业特征等元数据与数据血缘,并能跨多数据平台编排作业与依赖。
结论:选择 ETL 还是 ELT 取决于具体分析负载的需求:数据源特性、转换要求,以及性能与扩展性需求。为弥补各自短板,许多团队采用混合方案:利用 ETL 工具的元数据管理与编排优势,同时将实际转换下推为 SQL(ELT) 。在“外部转换”部分我们将进一步展开。
库内转换(In-Database Transformation)
面对当今多样且高速的数据,平台设计需同时具备可扩展与灵活。Amazon Redshift 持续迭代,提供在同一位置处理全部数据的库内转换(ELT)能力。作为 ANSI SQL 兼容的关系数据库,Redshift 支持常见 SQL 语法,并提供现代数据平台中的高级函数,如窗口函数、HyperLogLog、递归 CTE 等。除这些常见功能外,Redshift 还提供若干分析特有能力:例如对半结构化数据的原地查询;以及可扩展平台功能的用户自定义函数(UDF)与用于打包转换逻辑的存储过程(Stored Procedures) ,支持根据入参返回结果集,或实现装载与管理型操作(如加载事实、维度或聚合表)。
半结构化数据
半结构化数据不符合传统关系库的严格模式,常见于 Web 日志、传感器数据或 API 消息,因为这些应用常需表达嵌套关系,一次传输更高效。它包含数组、嵌套结构等复杂值,常见格式如 JSON。虽然可用第三方工具在库外转换,但需要工程投入维护代码且性能未必更优。无论访问S3 上的外部数据还是本地已加载数据,Redshift 通过 PartiQL 语法分析与转换半结构化数据,并提供特殊数据类型 SUPER 用于原生存储(从 S3 访问时在目录中会体现为 struct/array)。
下面的示例引用存放于 Amazon S3 的文件。你可以创建 external schema 来编目该文件,并将该前缀下的文件映射为一张外部表。
示例 4-1. 从 JSON 数据创建外部表
CREATE external SCHEMA IF NOT EXISTS nested_json
FROM data catalog DATABASE 'nested_json'
IAM_ROLE default
CREATE EXTERNAL DATABASE IF NOT EXISTS;
DROP TABLE IF EXISTS nested_json.nested_json;
CREATE EXTERNAL TABLE nested_json.nested_json (
c_name varchar,
c_address varchar,
c_nationkey int,
c_phone varchar,
c_acctbal float,
c_mktsegment varchar,
c_comment varchar,
orders struct<"order":array<struct<
o_orderstatus:varchar,
o_totalprice:float,
o_orderdate:varchar,
o_order_priority:varchar,
o_clerk:varchar,
o_ship_priority:int,
o_comment:varchar
>>> )
row format serde 'org.openx.data.jsonserde.JsonSerDe'
with serdeproperties ('paths'='c_name,c_address,c_nationkey,c_phone,
c_acctbal,c_mktsegment,c_comment,Orders')
stored as inputformat 'org.apache.hadoop.mapred.TextInputFormat'
outputformat 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
location 's3://redshift-immersionday-labs/data/nested-json/';
该数据文件位于 us-west-2 区域;你的 Redshift 也需在该区。示例使用了 默认 IAM 角色,请确保授予读取该 S3 位置及访问 AWS Glue Data Catalog 的权限。
示例 4-2. 访问顶层属性
SELECT cust.c_name,
cust.c_nationkey,
cust.c_address
FROM nested_json.nested_json cust
WHERE cust.c_nationkey = '-2015'
AND cust.c_address like '%E12';
使用 PartiQL 可访问嵌套结构。
示例 4-3. 反嵌套属性(外部)
SELECT cust.c_name,
cust_order.o_orderstatus,
cust_order.o_totalprice,
cust_order.o_orderdate::date,
cust_order.o_order_priority,
cust_order.o_clerk,
cust_order.o_ship_priority,
cust_order.o_comment
FROM nested_json.nested_json cust,
cust.orders.order cust_order
WHERE cust.c_nationkey = '-2015'
AND cust.c_address like '%E12';
此外,也可把半结构化数据加载到本地表并用 SUPER 存储。
示例 4-4. 从 JSON 创建本地表
DROP TABLE IF EXISTS nested_json_local;
CREATE TABLE nested_json_local (
c_name varchar,
c_address varchar,
c_nationkey int,
c_phone varchar,
c_acctbal float,
c_mktsegment varchar,
c_comment varchar,
orders SUPER);
COPY nested_json_local
from 's3://redshift-immersionday-labs/data/nested-json/'
IAM_ROLE default REGION 'us-west-2'
JSON 'auto ignorecase';
同样需要为默认 IAM 角色授予读取该 S3 位置的权限。
示例 4-5. 反嵌套属性(本地)
SET enable_case_sensitive_identifier TO true;
SELECT cust.c_name,
cust_order.o_orderstatus,
cust_order.o_totalprice,
cust_order.o_orderdate::date,
cust_order.o_order_priority,
cust_order.o_clerk,
cust_order.o_ship_priority,
cust_order.o_comment
FROM nested_json_local cust,
cust.orders."Order" cust_order
WHERE cust.c_nationkey = '-2015'
AND cust.c_address like '%E12';
若输入包含大小写混合的标识符,需设置
enable_case_sensitive_identifier。更多示例见在线文档。
用户自定义函数(UDF)
当内置函数无法满足需求时,Redshift 支持三类标量 UDF:SQL、Python 与 Lambda(详见官方文档)。标量函数每次调用返回一个值(通常对应每行一值)。
-
SQL UDF:复用 SQL 语法,确保一致逻辑、减少重复代码。
示例 4-6. SQL UDF 定义(脱敏)CREATE OR REPLACE function f_mask_varchar (varchar, varchar) returns varchar immutable AS $$ SELECT case $2 WHEN 'ssn' then substring($1, 1, 7)||'xxxx' WHEN 'email' then substring(SPLIT_PART($1, '@', 1), 1, 3) + 'xxxx@' + SPLIT_PART($1, '@', 2) ELSE substring($1, 1, 3)||'xxxxx' end $$ language sql;示例 4-7. SQL UDF 调用
SELECT f_mask_varchar (name, NULL) mask_name, name, f_mask_varchar (email, 'email') mask_email, email, f_mask_varchar (ssn, 'ssn') mask_ssn, ssn FROM Customer; -
Python UDF:利用 Python 代码转换数据,可引入自定义库。
示例 4-8. Python UDF 定义(解析 UA)CREATE OR REPLACE FUNCTION f_ua_parser_family (ua VARCHAR) RETURNS VARCHAR IMMUTABLE AS $$ FROM ua_parser import user_agent_parser RETURN user_agent_parser.ParseUserAgent(ua)['family'] $$ LANGUAGE plpythonu;示例 4-9. Python UDF 调用
SELECT f_ua_parser_family (agent) family, agent FROM weblog; -
Lambda UDF:与外部组件交互(DynamoDB、ElastiCache、外部 API、外部脱敏等),可用多种语言实现。
示例 4-10. Lambda 函数(KMS 加密) (Python 代码略,同原文)
示例 4-11. 关联到 Redshift 的 Lambda UDFCREATE OR REPLACE EXTERNAL FUNCTION f_kms_encrypt (key varchar, value varchar) RETURNS varchar(max) STABLE LAMBDA 'f-kms-encrypt' IAM_ROLE default;请为默认 IAM 角色授予调用该 Lambda 的权限。
示例 4-12. Lambda UDF 调用
SELECT f_kms_encrypt (email) email_encrypt, email FROM customer;
更多 Python/Lambda UDF 详情可参考相应博客文章。
存储过程(Stored Procedures)
Redshift 存储过程是用户自定义对象,用于执行一组 SQL 与逻辑操作。它存放在数据库中,授予权限的用户可执行。与“每次仅处理一行并返回一个值”的标量 UDF 不同,存储过程可以包含 DDL、DML 与 SELECT,也可不返回值,并支持循环与条件表达式。
常见用途:封装数据转换、数据校验与业务操作,替代 Shell 脚本或复杂 ETL/编排工具。将 ETL/ELT 的逻辑步骤完整封装在过程里,可按需增量提交或全成全败。所有处理在仓库内完成,无需跨网络搬运数据,并可利用 MPP 的批量处理优势。由于采用 PL/pgSQL,通常无需学习新语言;许多遗留存储过程可小改后迁移。AWS 还提供 AWS SCT 辅助将他库代码转换为 Redshift 的 PL/pgSQL。
示例 4-13. 存储过程定义(增量装载)
CREATE OR REPLACE PROCEDURE lineitem_incremental()
AS $$
DECLARE
yr CONSTANT INTEGER := 1998;
mon CONSTANT INTEGER := 8;
query VARCHAR;
BEGIN
TRUNCATE stage_lineitem;
query := 'COPY stage_lineitem ' ||
'FROM ''s3://redshift-immersionday-labs/data/lineitem-part/' ||
'l_orderyear=' || yr || '/l_ordermonth=' || mon || '/''' ||
' IAM_ROLE default REGION ''us-west-2'' gzip delimiter ''|''';
EXECUTE query;
MERGE INTO lineitem
USING stage_lineitem s ON s.l_orderkey=lineitem.l_orderkey
AND s.l_linenumber = lineitem.l_linenumber
WHEN MATCHED THEN DELETE
WHEN NOT MATCHED THEN INSERT
VALUES ( s.L_ORDERKEY, s.L_PARTKEY, s.L_SUPPKEY, s.L_LINENUMBER,
s.L_QUANTITY, s.L_EXTENDEDPRICE, s.L_DISCOUNT, s.L_TAX,
s.L_RETURNFLAG, s.L_LINESTATUS, s.L_SHIPDATE, s.L_COMMITDATE,
s.L_RECEIPTDATE, s.L_SHIPINSTRUCT, s.L_SHIPMODE, s.L_COMMENT);
END;
$$ LANGUAGE plpgsql;
同样需要为默认 IAM 角色授予读取相应 S3 位置的权限。
示例 4-14. 调用存储过程
CALL lineitem_incremental();
更多关于 Redshift 存储过程的内容,可参阅“Bringing Your Stored Procedures to Amazon Redshift”博客。
调度与编排(Scheduling and Orchestration)
当你开始考虑编排数据流水线时,需要评估工作流的复杂度以及对外部流程的依赖。有些用户需要管理带有复杂依赖关系的多套系统;如果作业失败或错过 SLA,你可能还需要高级通知能力。在这种情况下,可以考虑第三方调度工具。常见的企业级作业调度工具包括 Tivoli、Control-M、AutoSys,它们都已与 Amazon Redshift 集成,能够发起连接并执行一条或多条 SQL 语句。AWS 也提供了 Amazon Managed Workflows for Apache Airflow(MWAA) 服务(基于开源的 Apache Airflow 项目)。如果你已经在使用 Airflow 工作流并希望迁移上云,这会很有用。
不过,如果你可以基于时间触发加载作业,就可以利用 Query Scheduler(查询调度器) 。使用查询调度器时,控制台 UI 将基于 Amazon Redshift Data API 和 EventBridge 这些基础服务。
要用查询调度器触发简单的时间型查询,请进入 Query Editor V2,准备好你的查询,然后点击 Schedule(图 4-1)。本例中,我们用一条 COPY 语句加载 stage_lineitem 表。
设置连接(图 4-2)以及调度器在执行查询时将要假设(assume)的 IAM 角色。在后续对话框中,从列表中选择适用的 Amazon Redshift 数据仓库,以及对应的账号与区域。本例我们使用“Temporary credentials(临时凭证) ”连接。更多其他连接策略,请参见第 2 章“Getting Started with Amazon Redshift”。
图 4-1. Schedule 按钮
图 4-2. 选择连接
接着,设置将要执行的查询名称及可选的描述(图 4-3)。查询内容会从编辑器页面复制过来。
图 4-3. 设置查询
然后,设定基于时间的计划表——可使用 Cron 表达式,或通过单选项进行配置(图 4-4)。可选地,你还可以选择是否将执行事件投递到 Amazon SNS 主题以便接收通知。点击 Save Changes 保存计划。
图 4-4. 设置计划
要查看已计划的查询列表,进入 Query Editor V2 的 Scheduled queries 页面(图 4-5)。
图 4-5. 已计划查询列表
要管理计划作业,点击某个已计划的查询。在该页面你可以修改、停用或删除该作业;也可以查看历史记录,其中包含开始/结束时间以及作业状态(见图 4-6)。
图 4-6. 查看计划历史
你也可以在 EventBridge 中看到被创建的资源。进入 EventBridge Rules 页面,会注意到新增了一条 Scheduled 规则(图 4-7)。
图 4-7. 定时规则
检查该规则的 Target(图 4-8),你会看到 Redshift cluster 作为目标类型,以及执行查询所需的参数。
图 4-8. 定时规则目标
访问全部数据(Access All Your Data)
为完整体现 ELT 的能力,Amazon Redshift 支持即使未预先加载的数据也可访问。Redshift 的计算层能够在无需独立处理服务器的情况下处理你的数据,并使用前述所有转换功能。无论是“外部 Amazon S3 数据”、“外部业务型数据(Operational Data) ”,还是“外部 Amazon Redshift 数据”,你都可以在 Redshift 中用熟悉的 ANSI SQL 提交查询;只有相关的数据会被 Redshift 计算层处理。它们还可以与本地数据联接,并用于填充 Redshift 本地表。
外部 Amazon S3 数据(External Amazon S3 Data)
Amazon Redshift 允许你用简单 SQL 读写存放在 Amazon S3 的外部数据。访问 S3 上的数据增强了数据的互操作性——除 Redshift 外,Amazon Athena、Amazon EMR、Presto 及任何能访问 S3 的计算平台都可访问同一份 S3 数据。借助该功能,Redshift 可以把外部 S3 表与 Redshift 本地磁盘上的表进行联接。在预置集群模式下,Redshift 会利用一组称为 Amazon Redshift Spectrum 的节点群来处理 S3 数据;Spectrum 会将诸如谓词下推、聚合等优化应用在 Spectrum 计算层,从而提升查询性能。可下推到 Spectrum 的谓词运算符包括 =、LIKE、IS NULL、CASE WHEN 等;同时,多种聚合与字符串函数也可下推(如 COUNT、SUM、AVG、MIN、MAX)。
Redshift Spectrum 处理 S3 数据时的计算规模可达预置集群切片数的 10 倍,计费为 $5/TB 扫描量。而在 Serverless 模式下查询 S3 数据,会在 Redshift 的计算资源上处理,其成本包含在 RPU 计费内。
查询外部 S3 数据依赖外部元数据目录来组织数据集的数据库与表。你将该数据库映射到一个 Redshift 的 schema,并通过 IAM 角色提供访问凭据以决定权限级别。下面的示例中(示例 4-15),你的元数据目录是 AWS Glue Data Catalog,其中包含名为 externaldb 的数据库;若不存在,该命令会创建它。我们把此数据库映射到新的 schema externalschema,并使用附加在数据仓库上的默认 IAM 角色。如果你的数据位于 EMR 集群或自管 Hadoop 环境中,亦可映射到 Hive Metastore。创建 external schema 的更多选项见在线文档。
示例 4-15. 创建外部 S3 schema
CREATE EXTERNAL SCHEMA IF NOT EXISTS externalschema
FROM data catalog DATABASE 'externaldb'
IAM_ROLE default
CREATE EXTERNAL DATABASE IF NOT EXISTS;
此处使用默认 IAM 角色,请确保其具备管理 AWS Glue Data Catalog 的权限。
创建完 external schema 后,你就能像查询本地表一样查询外部数据。示例 4-16 展示了把外部表与本地数据联接查询的方式:
示例 4-16. 访问外部 S3 表
SELECT
t.returnflag,
t.linestatus,
c.zip,
sum(t.quantity) AS sum_qty,
sum(t.extendedprice*(1-t.discount)*(1+t.tax)) AS sum_charge
FROM externalschema.transactions t
JOIN public.customers c on c.id = t.customer_id
WHERE t.year = 2022 AND t.month = 1
GROUP BY t.returnflag, t.linestatus, c.zip;
该查询通过筛选仅限外部表中 2022-01 的数据并做简单聚合。在预置集群下,过滤与部分聚合会在 Spectrum 层执行,从而减少传回计算节点的数据量,提升性能。
由于查询本地存储的数据性能最佳,最佳实践是将最新/最热数据加载在 Redshift,本地查询;而把低频访问数据从外部源查询。按此策略,可确保最热数据最接近计算端,并采用对分析最优的格式。示例 4-17 展示了如何将最新一月数据装入本地 transaction 表,同时历史数据仍在 S3;对用户呈现统一视图,但访问最热数据时会从本地读取。
示例 4-17. 合并(Union)S3 与本地数据
CREATE VIEW public.transactions_all AS
SELECT … FROM public.transactions
UNION ALL
SELECT … FROM externalschema.transactions
WHERE year != date_part(YEAR, current_date)
AND month != date_part(MONTH, current_date);
WITH NO SCHEMA BINDING;
对外部表必须使用
WITH NO SCHEMA BINDING,以确保向 S3 装载数据时不受 Redshift 绑定影响。
更多 Spectrum 优化技巧请参考官方最佳实践博客。
外部业务型数据(External Operational Data)
联邦查询(Federated Query) 允许你直接查询事务型数据库中的数据,以实现实时的数据集成与简化 ETL。借助联邦查询,你可向用户提供实时洞察。典型场景是:数据仓库通过批处理装载数据,但有实时分析需求——可以将 Redshift 的批量数据与事务库中的最新数据组合呈现。联邦查询还会把源库的元数据以外部表形式暴露,使 Tableau、Amazon QuickSight 等 BI 工具也能查询这些联邦源。这样即可无缝查询业务数据、简化 ETL 管道,并构建迟绑定(late-binding)视图把业务数据与 Redshift 本地数据结合。截至 2022 年,支持的事务库包括 Amazon Aurora PostgreSQL/MySQL 与 Amazon RDS for PostgreSQL/MySQL。
联邦查询通过 TCP/IP 连接到业务数据源,并映射为 external schema。你需提供数据库类型、连接信息,以及通过 AWS Secrets Manager 管理的连接凭据。示例 4-18 中,数据库类型为 POSTGRES,连接信息包含 DATABASE、SCHEMA 与 DB 的 URI。创建 external schema 的更多选项见在线文档。
示例 4-18. 创建 external schema
CREATE EXTERNAL SCHEMA IF NOT EXISTS federatedschema
FROM POSTGRES DATABASE 'db1' SCHEMA 'pgschema'
URI '<rdsname>.<hashkey>.<region>.rds.amazonaws.com'
SECRET_ARN 'arn:aws:secretsmanager:us-east-1:123456789012:secret:pgsecret'
IAM_ROLE default;
使用了默认 IAM 角色;请确保其具备从 Secrets Manager 读取名为
pgsecret的密钥的权限。
创建完成后,你就能像本地表一样查询这些表(示例 4-19)。同样加入了仅限 2022-01 的过滤。联邦查询会智能下推谓词,以减少在源库扫描的数据量,显著提升性能。
示例 4-19. 访问外部表
SELECT
t.returnflag,
t.linestatus,
c.zip,
sum(t.quantity) AS sum_qty,
sum(t.extendedprice*(1-t.discount)*(1+t.tax)) AS sum_charge
FROM federatedschema.transactions t
JOIN public.customers c ON c.id = t.customer_id
WHERE t.year = 2022 AND t.month = 1
GROUP by t.returnflag, t.linestatus, c.zip;
由于联邦查询会在事务系统上执行查询,请谨慎限制扫描数据量。一个好实践是:历史数据放在 Redshift 本地表,仅访问联邦库中的最新数据。
此外,联邦查询还能简化 ETL。常见的 ETL 模式是 Upsert(插入或更新/删除)。过去通常需要:全量或增量抽取 → 落地到接近仓库的位置(如 S3)→ 用 COPY 装入临时表 → 基于暂存数据对目标表执行 MERGE。借助联邦查询,你可以绕过 S3 增量抽取与 COPY,直接在源库“就地查询”。示例 4-20 展示了如何用一条 MERGE 把 customer 表与业务源同步。
示例 4-20. 用 MERGE 做增量更新
MERGE INTO customer
USING federatedschema.customer p ON p.customer_id = customer.customer_id
AND p.updatets > current_date-1 and p.updatets < current_date
WHEN MATCHED THEN UPDATE SET customer_id = p.customer_id,
name = p.name, address = p.address,
nationkey = p.nationkey, mktsegment = p.mktsegment
WHEN NOT MATCHED THEN INSERT (custkey, name, address, nationkey, mktsegment)
VALUES ( p.customer_id, p.name, p.address, p.nationkey, p.mktsegment )
更多联邦查询优化技巧,参见“Best Practices for Amazon Redshift Federated Query”;想进一步简化 ETL,可参考“Build a Simplified ETL and Live Data Query Solution Using Amazon Redshift Federated Query”。
外部 Amazon Redshift 数据(External Amazon Redshift Data)
Redshift 数据共享(Data Sharing) 让你可以直接查询另一个 Redshift 数据仓库(RA3 预置或 Serverless)的 RMS(托管存储) 中的实时数据。这样,生产端数据仓库中的数据就能在消费端被访问。与其他外部数据源类似,数据共享会把生产端的元数据以外部表形式暴露给消费端,使其无需创建本地副本即可查询。这支持新的数仓用例,如分布式数据所有权、不同工作负载的执行隔离。第 7 章“Collaboration with Data Sharing”将深入讨论。下面通过 SQL 展示如何配置 datashare,以及在 ETL/ELT 中的用法。如何在控制台启用与配置数据共享,请见在线文档。
第一步,了解生产端与消费端数据仓库的 namespace。在各自数据仓库上执行(示例 4-21):
示例 4-21. 当前命名空间
SELECT current_namespace;
然后,在生产端创建 datashare 对象,并将 schema 与表加入其中(示例 4-22)。
示例 4-22. 创建 datashare
CREATE DATASHARE transactions_datashare;
ALTER DATASHARE transactions_datashare
ADD SCHEMA transactions_schema;
ALTER DATASHARE transactions_datashare
ADD ALL TABLES IN SCHEMA transactions_schema;
接着,引用消费端的 namespace 向其授予使用权限(示例 4-23)。
示例 4-23. 授权使用 datashare
GRANT USAGE ON DATASHARE transactions_datashare
TO NAMESPACE '1m137c4-1187-4bf3-8ce2-CONSUMER-NAMESPACE';
最后,在消费端创建一个数据库,引用 datashare 名称及生产端的 namespace(示例 4-24)。
示例 4-24. 在消费端创建数据库
CREATE DATABASE transactions_database from DATASHARE transactions_datashare
OF NAMESPACE '45b137c4-1287-4vf3-8cw2-PRODUCER-NAMESPACE';
Datashare 也可跨账号授予;此场景需要由 datashare 的管理员执行额外步骤,详见在线文档。
创建完外部数据库后,你就能像本地表一样查询(示例 4-25),与外部 S3/业务数据的示例类似,并带有 2022-01 的过滤。
示例 4-25. 访问 datashare
SELECT
t.returnflag,
t.linestatus,
c.zip,
sum(t.quantity) as sum_qty,
sum(t.extendedprice*(1-t.discount)*(1+t.tax)) as sum_charge
FROM transactions_database.transcations_schema.transactions t
JOIN public.customers c on c.id = t.customer_id
WHERE t.year = 2022 AND t.month = 1
GROUP by t.returnflag, t.linestatus, c.zip;
可以设想这样的组织结构:A 部门负责销售交易,B 部门负责客户关系。B 部门想识别最优/最差客户以开展定向营销。无需维护一个共享数据仓库或复制数据,每个部门可各自使用独立的 Redshift,并对自己的数据负责;B 部门直接查询 A 部门的交易数据,构建并维护自己的聚合,与既有的营销活动与情感分析数据进行联接以制定营销方案。
更多数据共享内容,参见“Sharing Amazon Redshift Data Securely Across Amazon Redshift Clusters for Workload Isolation”和“Amazon Redshift Data Sharing Best Practices and Considerations”。
外部转换(External Transformation)
在需要使用外部工具进行数据转换的场景下,Amazon Redshift 可以通过 JDBC/ODBC 驱动(由第三方应用内置或单独下载)连接到你选择的 ETL 平台。与 Amazon Redshift 集成的常见 ETL 平台包括第三方工具 Informatica、Matillion、dbt,以及 AWS 原生工具 AWS Glue。ETL 工具有助于管理数据流水线的各个组件:它们提供作业仓库来组织与维护元数据,使组织不必把所有逻辑都写在 SQL 脚本和存储过程里;它们还具备调度能力,便于作业编排——如果你没有使用 AWS 原生的“调度与编排”,这会很有用。
部分 ETL 工具还能将转换逻辑“下推(push down) ”。当你的作业读写的目标都是 Amazon Redshift 时,可以在 ETL 工具的可视化界面设计作业,但不把数据抽取到 ETL 服务器上计算,而是把逻辑转译成在 Amazon Redshift 上运行的 SQL 语句。这种策略在处理海量数据转换时性能很强,但也可能占用用户用于分析的数据仓库资源。如果你不使用下推能力(例如作业并非同时读写 Redshift,或你希望把转换从仓库卸载出去),就要确保 ETL 工具对 Redshift 的读写方式足够高效。
正如第 3 章“搭建数据模型与数据摄取”所述,装载数据最高性能的方式是使用 COPY 语句。得益于 AWS 与 Informatica、Matillion 等厂商的合作,AWS 确保这些厂商提供了按此策略实现的连接器。举例来说,在图 4-9 的 Informatica x Amazon Redshift 架构中,如果你把目标设置为 Redshift、并指定了 S3 作为中间暂存区,工具不会直接 INSERT 到目标表,而是先写入 Amazon S3,再通过 COPY 语句加载到目标表。对 UPDATE/DELETE 也采用类似策略:先写入暂存表,然后在加载后执行更新/删除。这种优化之所以可行,是因为 AWS 与多家软件厂商合作,帮助用户更容易地使用工具并确保数据管道的高性能。更多第三方 ETL 工具最佳实践可参见以下指南:
- Informatica—Amazon Redshift Connector Best Practices
- Matillion—Amazon Redshift Best Practices for ETL Processing
- dbt—Best Practices for Leveraging Amazon Redshift and dbt
图 4-9. Informatica 与 Amazon Redshift 架构
AWS Glue
AWS Glue 是原生的无服务器数据集成服务,常用 Python 或 Scala 编写转换逻辑并在数据处理引擎上运行。借助 Glue(图 4-10),你可以读取 Amazon S3 数据、执行转换,并将数据写入 Amazon Redshift 以及其他数据平台。Glue 让发现、准备、迁移与集成多源数据(用于分析、ML 与应用开发)更容易。它提供多种引擎:Glue for Apache Spark、Glue for Ray、Glue for Python Shell。可根据工作负载特征与开发/分析人员偏好选择合适引擎。
图 4-10. 使用 AWS Glue 进行 ETL 集成
自 AWS Glue V4 起,提供了全新的 Amazon Redshift Spark 连接器与 JDBC 驱动,可用于构建 Spark 应用,在数据摄取与转换管道中对 Amazon Redshift 读写。新的连接器与驱动支持将 连接(join) 、聚合、排序、标量函数 等关系型操作从 Spark 下推到 Redshift,减少需要处理的数据量、提升作业性能;还支持基于 IAM 的角色以实现单点登录,并与 AWS Secrets Manager 集成以安全管理密钥。
为管理 Glue 作业,AWS 提供了可视化创作工具 AWS Glue Studio。它遵循与前述第三方 ETL 工具相似的最佳实践,但由于与 AWS 的深度集成,构建与管理数据管道所需步骤更少。
下面在示例 4-26 中,我们构建一个作业:从 Amazon S3 加载增量交易数据,并以键 (l_orderkey, l_linenumber) 合并(merge)进 Redshift 中的 lineitem 表。
示例 4-26. 创建 lineitem 表
CREATE TABLE lineitem (
L_ORDERKEY varchar(20) NOT NULL,
L_PARTKEY varchar(20),
L_SUPPKEY varchar(20),
L_LINENUMBER integer NOT NULL,
L_QUANTITY varchar(20),
L_EXTENDEDPRICE varchar(20),
L_DISCOUNT varchar(20),
L_TAX varchar(20),
L_RETURNFLAG varchar(1),
L_LINESTATUS varchar(1),
L_SHIPDATE date,
L_COMMITDATE date,
L_RECEIPTDATE date,
L_SHIPINSTRUCT varchar(25),
L_SHIPMODE varchar(10),
L_COMMENT varchar(44));
注册 Amazon Redshift 目标连接
进入 Create connection 新建 Glue 连接,命名并选择连接类型 Amazon Redshift(见图 4-11)。
图 4-11. Redshift 连接命名
接着从你帐号与区域内自动发现的 Redshift 数据仓库列表中选择实例,设置数据库名与访问凭据。可直接设置用户名/密码,或使用 AWS Secrets Manager。最后点击 Create connection(图 4-12)。
图 4-12. 选择 Redshift 连接实例
构建并运行 AWS Glue 作业
在 AWS Glue Studio → Jobs 页面创建作业(图 4-13),本例选择 Visual with a source and target。将 target 修改为 Amazon Redshift 并点击 Create。
图 4-13. 创建 Glue 作业
随后你会看到作业的可视化编排界面。首先选中数据源节点并把源类型设为 S3(图 4-14)。本例中设置为 s3://redshift-immersionday-labs/data/lineitem-part/;选择解析细节(格式、分隔符、转义符等)。我们的文件为 CSV、管道符 | 分隔、无表头。最后点击 Infer schema。
图 4-14. 配置 Amazon S3 源
如果你已经建立了用于 Athena、EMR 或 Redshift 外部表的数据湖,也可选择 Data Catalog table 作为源。
接着进行数据转换(图 4-15)。默认会有一个 ApplyMapping 节点,同时也可进行联接、拆分、聚合等多种转换(参见“Editing AWS Glue Managed Data Transform Nodes”文档)。选择 Transform 节点并将目标字段与源字段对齐。本例由于源数据无表头,注册时使用了通用列名(col#),需将其映射到 lineitem 表中对应列。
图 4-15. 应用字段映射
然后设置 Amazon Redshift 目标(图 4-16)。选择 Direct data connection,并设置 schema(public)与表(lineitem)。你还可配置处理新记录的方式:全部插入,或设置键以便对需重处理的数据进行更新。我们的用例选择 MERGE,设置键为 l_orderkey 与 l_linenumber。这样作业运行时会先把数据加载到暂存表,然后依据目标表中的既有数据执行 MERGE,在删除旧数据/更新后再插入新数据。
图 4-16. 配置 Redshift 目标
保存与运行前,还需设置作业细节(图 4-17),如用于运行作业的 IAM 角色与脚本文件名。该角色需要访问 S3 数据位置,并可被 AWS Glue 服务假设(assume) 。创建并设置角色后,点击 Save and Run 执行作业。
图 4-17. 设置作业详情
可在 Runs 选项卡查看作业运行详情,包括作业 ID 与运行统计信息(图 4-18)。
图 4-18. 作业运行详情
若要让 Glue 访问 S3,而你尚未创建 VPC Endpoint,需要先创建;详见在线文档。
作业完成后,可进入 Amazon Redshift 控制台查看查询与装载(图 4-19):你会看到创建临时表、加载 S3 文件、执行合并(删除旧数据、插入新数据)等查询历史。
图 4-19. Redshift 查询历史
小结
本章介绍了在 Amazon Redshift 中进行数据转换的多种方式。凭借 Redshift 对“全部数据(不论是否预装载) ”的访问能力,你可以快速、轻松地对数据湖、业务系统或其他 Redshift 数据仓库中的数据执行转换;并可用 Redshift 查询调度器实现基于时间的作业编排。最后,我们说明了 Redshift 与第三方 ETL/编排厂商的合作如何提供最优的执行性能,并与组织中既有工具顺畅集成。
下一章将讨论当你的工作负载发生变化时,Amazon Redshift 如何弹性扩展;也会介绍 Serverless 如何自动伸缩,以及你如何控制预置集群的扩容策略;并讲解如何通过最佳实践获得 性价比更高 的 Redshift。