Ch 32 跨账号批量同步:双桶桥接架构¶
面包屑
本书主页 › Part V 平台演进 › Ch 32
项目第 2-3 年 · 扩展与迁移期——跨账号安全同步
本章你将学到¶
- 跨账号 Redshift 数据同步的难题与约束
- 双桶桥接架构设计:源卸载→源桶→桥接→目标桶→目标加载
- 三层凭证模型:最小权限与跨账号安全
- DDL 自动克隆与 Glue + boto3(Data API)执行通道
迁移完 SQL Server(Ch 31)后,又一个没想到的挑战出现了:Aurora 内部有多个 AWS 账号(不同业务线的独立账号),需要把账号 A 的 Redshift 数据批量同步到账号 B 的 Redshift。
"同步数据嘛,UNLOAD 出来再 COPY 进去不就行了?"我一开始也这么想。细看就不对了:Redshift UNLOAD 在技术上完全能靠 IAM Role + 目标账号桶策略直接写对方桶,但出于安全隔离,平台不给 Redshift 集群跨账号权限。集群一旦被入侵,影响面会跨账号,安全团队第一个不答应。所以 UNLOAD 只写本账号中转桶。
这个问题我们纠结了一周。有次白板讨论上,"双桶桥接"的方案成型——不是最简单的方案,但是最安全的。这一章就讲这个设计过程。
32.1 跨账号数据同步的难题与约束¶
跨账号同步发生在项目第 2–3 年。SQL Server 迁完了(Ch 31),多账号隔离也立住了(Ch 6),接下来要把账号 A 的 Redshift 业务表批量搬到账号 B。场景很具体:不同业务线各有独立 AWS 账号,合规要求边界清晰,分析又要跨账号汇聚。
我在架构评审会上被问过一句:"UNLOAD 到对方桶不行吗?"技术上完全行。AWS 文档写得很清楚:UNLOAD 靠集群关联的 IAM Role 写 S3,目标账号桶策略把该 Role ARN 写进 Principal,再配 s3:PutObject 等权限,就能跨账号落盘;Spectrum 读跨账号桶也是同一套路。所以"Redshift 不能跨账号 UNLOAD"这句话本身是错的。我早期也差点这么写进设计文档。
真正卡住我们的是安全策略,不是能力。安全团队的立场很硬:Redshift 一旦拿到跨账号写权限,入侵面就从"一个账号的数仓"扩成"能污染对方账号的中转桶"。医药平台的账号隔离是给 GxP / PIPL 审计用的。控制面可以跨账号编排;数据面的常驻计算身份不能轻易跨边界。于是约束变成:
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart LR
subgraph 难题["跨账号同步难题"]
P1[ 安全策略:Redshift 不授跨账号 S3 权限<br/>UNLOAD 只写本账号中转桶]
P2[ 桥接身份与数仓身份分离<br/>只有桥接程序可跨账号]
P3[ 推荐 STS AssumeRole 临时凭证<br/>泄露窗口按小时计而非按轮转周期]
P4[ 需要表结构自动克隆<br/>避免手动建表]
P5[ 需要断点续传和幂等性]
end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class P1,P2,P3,P4,P5 bpProcess
linkStyle default stroke:#697077,stroke-width:2px
图 32-1 跨账号数据同步的难题与约束
图里五条约束不是并列清单:前三条是安全边界,后两条是工程可运维性。白板讨论那一周,我们对比过三条路。一是给 Redshift 跨账号 Role,最简单,安全否决。二是 STS AssumeRole + 直接跨账号写目标桶,符合 AWS 最佳实践,但当时增量校验与断点续传要自己补。三是双桶桥接,桥接程序持凭证,多一跳,但数仓两端保持"同账号 only"。我们选了第三条作为当时可上线的方案,同时把第二条记成终态方向。下一节会讲桥接层为什么落成 rclone,以及它和 STS 的关系。
Trade-off
最简单的方案是给账号 A 的 Redshift 跨账号 S3 权限,直接 UNLOAD 到账号 B 的桶。这违背最小权限:集群一旦被入侵,影响面巨大。我们选了更安全也更复杂的双桶桥接:数仓身份永不跨账号,跨账号动作收敛到可轮转、可审计的桥接身份上。
32.2 双桶架构设计:源卸载→源桶→桥接→目标桶→目标加载¶
C4Container
title 双桶桥接跨账号同步架构 — Container Diagram
Container_Boundary(acct_a, "AWS 账号 A(源)", "源数据所在 AWS 账号——Redshift 只有同账号 S3 权限") {
ContainerDb(rs_a, "Redshift A", "Redshift Provisioned", "源数据仓库:持有完整表结构和业务数据,通过 UNLOAD 将数据导出为 Parquet")
ContainerDb(bucket_a, "源 S3 桶", "S3 Standard", "同账号 S3 桶:Redshift A 的 UNLOAD 目标——Redshift 无需跨账号权限即可写入")
Container(unload, "UNLOAD 作业", "Glue Python Shell", "编排 UNLOAD SQL:选择表→分区 UNLOAD→生成 Parquet 到源桶。支持断点续传和并行分区导出")
}
Container_Boundary(bridge, "跨账号桥接层", "安全域边界——只有桥接程序持有双账号凭证,Redshift 两端均无跨账号权限") {
Container(rclone, "rclone 桥接程序", "rclone + EC2/Glue", "从源桶增量同步 Parquet 到目标桶:支持断点续传、增量校验、大文件分片、带宽限制")
Container(cred_mgr, "凭证管理", "Secrets Manager", "集中存储双账号 AK/SK:源桶只读凭证 + 目标桶只写凭证。自动轮转,日志脱敏。最小权限原则")
}
Container_Boundary(acct_b, "AWS 账号 B(目标)", "目标 AWS 账号——Redshift 从同账号 S3 桶 COPY 加载") {
ContainerDb(bucket_b, "目标 S3 桶", "S3 Standard", "同账号 S3 桶:桥接程序写入 Parquet 后,Redshift B 通过 COPY 命令加载到目标表")
ContainerDb(rs_b, "Redshift B", "Redshift Provisioned", "目标数据仓库:表结构由 DDL 自动克隆(读取源 DDL→重写标识符→依赖排序→幂等执行)")
Container(copy_job, "COPY 作业", "Glue Python Shell", "编排 COPY SQL:从目标桶加载 Parquet 到 Redshift B→校验行数→记录元数据")
Container(ddl_clone, "DDL 克隆", "Glue Python Shell", "自动读取源表结构→标识符重写→外键依赖排序→在目标执行 CREATE TABLE")
}
Rel(unload, rs_a, "执行 UNLOAD:按分区导出表数据为 Parquet", "Glue + boto3 Data API")
Rel(unload, bucket_a, "写入 Parquet 文件到同账号 S3 桶", "S3 PUT (同账号 IAM Role)")
Rel(rclone, bucket_a, "读取 Parquet 文件——增量比对已同步文件", "S3 GET (跨账号 AK/SK)")
Rel(rclone, bucket_b, "写入 Parquet 文件——断点续传支持分片上传", "S3 PUT (跨账号 AK/SK)")
Rel(rclone, cred_mgr, "获取双账号临时凭证——源只读/目标只写", "Secrets Manager API")
Rel(copy_job, bucket_b, "读取 Parquet——校验文件完整性和行数", "S3 GET (同账号 IAM Role)")
Rel(copy_job, rs_b, "COPY 加载——从 Parquet 写入目标表", "Glue + boto3 Data API")
Rel(ddl_clone, rs_a, "读取源表 DDL——pg_catalog / SVV_TABLE_INFO", "Glue + boto3 Data API")
Rel(ddl_clone, rs_b, "在目标执行 CREATE TABLE——依赖排序后幂等执行", "Glue + boto3 Data API")
UpdateElementStyle(rs_a, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(bucket_a, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(unload, $bgColor="#edf5ff", $fontColor="#161616", $borderColor="#0f62fe")
UpdateElementStyle(rclone, $bgColor="#fcf4d6", $fontColor="#161616", $borderColor="#f1c21b")
UpdateElementStyle(cred_mgr, $bgColor="#f6f2ff", $fontColor="#161616", $borderColor="#8a3ffc")
UpdateElementStyle(bucket_b, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(rs_b, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(copy_job, $bgColor="#edf5ff", $fontColor="#161616", $borderColor="#0f62fe")
UpdateElementStyle(ddl_clone, $bgColor="#defbe6", $fontColor="#161616", $borderColor="#198038")
UpdateRelStyle(unload, rs_a, $textColor="#007d79", $lineColor="#007d79")
UpdateRelStyle(rclone, bucket_a, $textColor="#f1c21b", $lineColor="#f1c21b")
UpdateRelStyle(rclone, bucket_b, $textColor="#f1c21b", $lineColor="#f1c21b")
UpdateRelStyle(rclone, cred_mgr, $textColor="#8a3ffc", $lineColor="#8a3ffc")
UpdateLayoutConfig($c4ShapeInRow="5", $c4BoundaryInRow="2")
图 32-2 双桶架构设计:源卸载→源桶→桥接→目标桶→目标加载
数据流详解¶
| 步骤 | 操作 | 账号 | 关键点 |
|---|---|---|---|
| ① UNLOAD | Redshift A 卸载数据到同账号 S3 桶 | A | Redshift 无需跨账号权限 |
| ② 桥接复制 | 用 rclone 从源桶复制到目标桶 | A→B | 桥接程序持双账号凭证 |
| ③ COPY | Redshift B 从同账号 S3 桶加载数据 | B | Redshift 无需跨账号权限 |
表 32-1 数据流详解
跨账号同步时序¶
C4Dynamic
title 双桶桥接 — Dynamic Diagram (UNLOAD → rclone → COPY 时序)
ContainerDb(rs_a, "Redshift A", "Redshift", "源数据仓库")
ContainerDb(bucket_a, "源 S3 桶", "S3", "同账号写入")
Container(rclone, "rclone 桥接", "rclone", "跨账号复制引擎")
ContainerDb(bucket_b, "目标 S3 桶", "S3", "桥接写入目标")
ContainerDb(rs_b, "Redshift B", "Redshift", "目标数据仓库")
RelIndex(1, rs_a, bucket_a, "1. UNLOAD:Glue + boto3 提交 UNLOAD,导出 Parquet 到同账号源桶", "Data API → S3 PUT")
RelIndex(2, bucket_a, rclone, "2. rclone 从源桶跨账号读取 Parquet 文件列表", "S3 GET (跨账号 AK/SK)")
RelIndex(3, rclone, bucket_b, "3. rclone 跨账号写入 Parquet 到目标 S3 桶", "S3 PUT (跨账号 AK/SK)")
RelIndex(4, bucket_b, rs_b, "4. COPY:Glue + boto3 提交 COPY,从同账号目标桶加载", "Data API ← S3 GET")
RelIndex(5, rs_b, bucket_b, "5. 校验:比对源/目标行数 → 记录元数据", "Data API 校验")
UpdateElementStyle(rs_a, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(bucket_a, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(rclone, $bgColor="#fcf4d6", $fontColor="#161616", $borderColor="#f1c21b")
UpdateElementStyle(bucket_b, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateElementStyle(rs_b, $bgColor="#d9fbfb", $fontColor="#161616", $borderColor="#007d79")
UpdateRelStyle(bucket_a, rclone, $textColor="#f1c21b", $lineColor="#f1c21b")
UpdateRelStyle(rclone, bucket_b, $textColor="#f1c21b", $lineColor="#f1c21b")
UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="2")
图 32-3 跨账号同步时序
为什么用 rclone 做桥接¶
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart TB
subgraph rclone桥接的优势["rclone 桥接的优势"]
R1@{ icon: "logos:aws-redshift", form: "rounded", label: Redshift 不需跨账号权限<br/>安全隔离, pos: "b", h: 40 }
R2[ rclone 支持增量同步<br/>只传变化文件]
R3[ rclone 支持断点续传<br/>大表可分批传]
R4@{ icon: "logos:aws-redshift", form: "rounded", label: 桥接程序集中管控凭证<br/>Redshift 无感知, pos: "b", h: 40 }
end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class R1,R2,R3,R4,Redshift,rclone bpProcess
linkStyle default stroke:#697077,stroke-width:2px
图 32-4 为什么用 rclone 做桥接
引申
双桶架构的思路是在两个账号之间插入一个中转层——源和目标都不需要跨账号权限,只有桥接程序持有双账号凭证。有点像国际贸易里的保税仓:出口方和进口方不直接交易,通过中间仓中转。安全性和解耦性都更好。
32.3 三层凭证模型:最小权限与跨账号安全¶
双桶架构把"跨账号"从数仓身上剥下来了,凭证问题却没消失,只是集中到了桥接层。我在实现 UnloadCopyTool 时把凭证拆成三层:每一种身份只做一件事。
工程上,整条管线由配置驱动的任务图串起来:unloadSource / s3Staging / copyTarget 三段配置,依赖是 DDL 克隆 → UNLOAD → SyncS3Staging(rclone)→ COPY → 清理。TaskManager 轮询就绪任务,支持 failOnError 栅栏。这就是下一章自研 DAG 的雏形。桥接那一步对应 SyncS3StagingTask:从 Secrets Manager 读源/目标 S3 凭证,生成 rclone 双 remote 配置,再 rclone copy 做增量同步。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart TB
subgraph 三层凭证["三层凭证模型"]
L1@{ icon: "logos:aws-redshift", form: "rounded", label: 第一层:Redshift IAM Role<br/>用于 UNLOAD/COPY<br/>仅同账号 S3 权限, pos: "b", h: 40 }
L2@{ icon: "logos:aws-secrets-manager", form: "rounded", label: 第二层:数据库凭证<br/>用于连接 Redshift<br/>存 Secrets Manager, pos: "b", h: 40 }
L3@{ icon: "logos:aws-s3", form: "rounded", label: 第三层:桥接凭证<br/>用于 rclone 跨账号复制<br/>可含 STS session_token, pos: "b", h: 40 }
end
L1 --> RS[Redshift 集群]
L2 --> RS
L3 --> RCLONE[rclone 桥接程序]
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class IAM,L1,L2,L3,Manager,RCLONE,RS,Redshift,Role,S3,Secrets,UNLOAD,rclone bpProcess
linkStyle default stroke:#697077,stroke-width:2px
图 32-5 三层凭证模型:最小权限与跨账号安全
| 凭证层 | 用途 | 权限范围 | 存储位置 |
|---|---|---|---|
| Redshift IAM Role | UNLOAD/COPY 到同账号 S3 | 仅同账号 S3 读写 | IAM Role(集群关联) |
| 数据库凭证 | 连接 Redshift 执行 SQL | 数据库级权限 | Secrets Manager(clusterSecret) |
| 桥接凭证 | rclone 跨账号复制 | 源桶只读 / 目标桶只写 | Secrets Manager(可含临时会话) |
表 32-2 三层凭证模型:最小权限与跨账号安全
第三层是我后来反复反思的地方。早期实现把长期 AK/SK 放进 Secrets Manager,rclone 直接用。能跑,泄露窗口却等于轮转周期(当时 90 天)。AWS 推荐 sts.assume_role() 拿临时凭证:默认 1 小时,最长 12 小时,过期自动失效。有意思的是,平台的 rclone 封装其实已经支持 session_token:Secrets 里若带临时会话字段,生成的 rclone conf 会写入 session token。也就是说,从长期密钥迁到"STS 临时凭证灌进同一 Secret",桥接代码几乎不用改。缺的是轮转侧:用 Lambda / EventBridge 定期 AssumeRole,把临时三件套写回 Secrets,而不是人工发 AK/SK。
安全设计原则¶
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart LR
subgraph 安全原则["三层凭证安全原则"]
S1@{ icon: "logos:aws-iam", form: "rounded", label: 推荐 STS AssumeRole<br/>临时凭证按小时过期, pos: "b", h: 40 }
S2@{ icon: "logos:aws-redshift", form: "rounded", label: 每层最小权限<br/>Redshift 永不跨账号, pos: "b", h: 40 }
S3@{ icon: "logos:aws-secrets-manager", form: "rounded", label: 凭证集中管理<br/>全部存 Secrets Manager, pos: "b", h: 40 }
S4@{ icon: "codicon:shield", form: "rounded", label: 日志脱敏<br/>密钥/密码自动 REDACTED, pos: "b", h: 40 }
end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class S1,S2,S3,S4 bpProcess
linkStyle default stroke:#697077,stroke-width:2px
图 32-6 安全设计原则
Trade-off
三层凭证比"一个 Role 管所有"复杂不少,安全性却是实在的。Redshift 集群始终只有同账号权限;即使被入侵,攻击者也没法直接访问对方账号。桥接程序权限最小化(只读写特定桶),日志自动脱敏。
Trade-off:rclone + 长期 AK/SK 是过渡方案,不是终态
这里得诚实交代设计债:桥接程序早期用 rclone + Secrets Manager 长期 AK/SK,这不是 AWS 推荐做法。最佳实践是 STS AssumeRole(临时凭证),外加可选的 S3 Cross-Account Replication。当时选 rclone,是因为要文件级增量比对和断点续传;S3 Replication 当时满足不了我们的校验语义。代价是长期凭证的泄露窗口。路线图分两步:先把 Secret 内容换成 STS 临时三件套(代码已支持 session_token),再评估是否用 S3 Replication / S3 Inventory 校验和替代 rclone 进程。过渡方案能解眼下的痛,不能当成终态。尤其别把"不想用 AssumeRole,凭证管理复杂"当架构理由:assume_role 本身就几行代码,复杂的是轮转与审计闭环。
32.4 DDL 自动克隆与结构迁移¶
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart LR
subgraph DDL克隆["DDL 自动克隆流程"]
READ[读取源表 DDL] --> TRANSFORM[DDL 转换<br/>重写标识符/适配目标]
TRANSFORM --> EXEC[在目标执行 DDL<br/>创建同结构表]
end
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class DDL,EXEC,READ,TRANSFORM bpProcess
linkStyle default stroke:#697077,stroke-width:2px
图 32-7 DDL 自动克隆与结构迁移
| 设计要点 | 说明 |
|---|---|
| 源 DDL 读取 | 通过系统视图查询源表完整 DDL |
| 标识符重写 | 按规则重写表名/schema 名(如加环境前缀) |
| 外键排序 | 有外键依赖的表按依赖顺序创建(被引用表先建) |
| 幂等性 | 目标表已存在则跳过或重建(按配置) |
表 32-3 DDL 自动克隆与结构迁移
引申
DDL 克隆的难点不是"读取 DDL",是"处理依赖关系"。外键约束要求被引用表先于引用表创建。平台通过依赖排序策略(Ch 26 介绍过类似思路)自动计算创建顺序,避免外键冲突。
外键依赖排序这个需求,我第一次跑 DDL 克隆时踩了坑才意识到。当时让脚本按字母序创建表——dim_hospital 在 fact_prescription 前面创建,看起来没问题。但 fact_prescription 有外键引用 dim_doctor,而 dim_doctor 按字母序排在 dim_hospital 之后、fact_prescription 之前——创建 fact_prescription 时 dim_doctor 还不存在,外键约束失败了。从那以后我把依赖排序改成了拓扑排序——读取所有外键约束,按依赖图拓扑排序,无依赖的表可并行创建。这个拓扑排序逻辑和 Ch 26 的表加载顺序排序完全一样——依赖排序是通用模式,不管是 DDL 创建还是数据加载。
32.5 执行通道:Glue + boto3(Data API)为主¶
平台对 Redshift 的所有调用(UNLOAD、COPY、DDL、行数校验)统一走 Glue(Python Shell)+ boto3 redshift-data 客户端,提交给 Redshift Data API 异步执行。这和 Ch 14 的 JDBC 路径是两回事:JDBC / ODBC 只用于从 MySQL、SQL Server、PostgreSQL 等源库摄取,从不用 JDBC 去驱动 Redshift。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#edf5ff','primaryTextColor':'#161616','primaryBorderColor':'#0f62fe','lineColor':'#697077','secondaryColor':'#d9fbfb','tertiaryColor':'#f2f4f8','fontSize':'14px'}}}%%
flowchart TB
SQL[Glue 作业要执行 Redshift SQL] --> API[boto3 redshift-data<br/>execute_statement / batch_execute]
API --> WAIT[DescribeStatement 轮询<br/>两层重试:提交重试 + 等待重试]
WAIT --> DONE[FINISHED → 取结果 / 继续下游]
classDef bpProcess fill:#edf5ff,stroke:#0f62fe,stroke-width:2px,color:#161616
class API,DONE,SQL,WAIT bpProcess
linkStyle default stroke:#697077,stroke-width:2px
图 32-8 执行通道:Glue + boto3(Data API)为主
| 路径 | 机制 | 用途 | 说明 |
|---|---|---|---|
| 主路径(本书默认) | Glue + boto3 → Redshift Data API | UNLOAD / COPY / DDL / 校验 | 异步、无 JDBC、不占集群长连接 |
| 源库摄取(对照) | Glue Spark + JDBC/ODBC Driver | MySQL / MSSQL / PostgreSQL → S3 | 见 Ch 14,与 Redshift 无关 |
表 32-4 Redshift 调用 vs 源库 JDBC:两条互不混淆的路径
为什么不用 JDBC 调 Redshift
Redshift 虽兼容 PostgreSQL 协议,平台仍选 Data API,主要有几条工程理由。Glue / Lambda 是短生命周期计算,长 JDBC 连接和超时、连接池治理不匹配。Data API 用 IAM + Secrets ARN 鉴权,凭证不落作业内存。大表 UNLOAD/COPY 可跑数小时,异步提交加轮询比同步驱动更稳。配置里虽保留过 directConnect 开关(底层是 psycopg2 线协议,也不是 JDBC),生产默认关闭,只作排障备用。
Trade-off
Data API 多了"提交→轮询→取结果"一层,短 DDL 会比同步驱动慢几百毫秒到数秒;换来的是超时免疫,也更贴 Serverless。跨账号同步这种小时级作业,这点开销可以忽略。
本章小结¶
- 跨账号同步难题:UNLOAD 技术上可跨账号,安全策略不给 Redshift 跨账号权限,故只写本账号中转桶
- 双桶桥接:源 UNLOAD→源桶→rclone→目标桶→目标 COPY;数仓两端始终无跨账号权限
- 三层凭证:Redshift IAM Role + DB 凭证 + 桥接凭证;推荐 STS AssumeRole;rclone 已支持
session_token,长期 AK/SK 是过渡 - DDL 自动克隆:读源 DDL→标识符重写→依赖排序→幂等执行
- Redshift 调用统一走 Glue + boto3(Data API);JDBC 仅用于源库摄取
下一章
Ch 33 自研 DAG 调度器与任务编排 —— 跨账号同步涉及复杂任务依赖,接下来看平台为什么自研了一个轻量 DAG 调度器。