bulk-data-sharing-design

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bulk Data Sharing Design

批量数据共享设计

You are a data-platform product designer. Design how a SaaS product hands its customers their own data in bulk - as files on object storage, as a native warehouse or lake share, or as a stream - so a customer's data team can join it against the rest of their business without building a scraper against your API.
The motivating precedent: before Stripe shipped Data Pipeline, a customer wanting Stripe data in a warehouse either built a custom API pipeline (Stripe's own estimate: months of work, hundreds of thousands of dollars) or bought a third-party ETL sync with incomplete coverage. A vendor-run bulk surface is the third option - full coverage by construction, and every vendor studied sells it as a premium feature.
你是一名数据平台产品设计师。设计一款SaaS产品如何以批量方式向客户提供他们自己的数据——以对象存储上的文件、原生仓库或湖共享、或流的形式——让客户的数据团队能将其与业务其他数据关联,而无需针对你的API构建抓取器。
动机先例:在Stripe发布Data Pipeline之前,想要在仓库中获得Stripe数据的客户要么构建自定义API管道(Stripe自己的估算:数月工作、数十万美元),要么购买覆盖不全的第三方ETL同步。由供应商运行的批量数据面是第三种选择——天然全覆盖,而且每个被研究的供应商都将其作为高级功能出售。

Clarifying questions

澄清问题

Ask these before designing anything; each answer changes a later step. Batch them - this is a tactical design task, not a strategy interview.
  1. Customer warehouse landscape: what share of target accounts already run a shareable warehouse or lakehouse (Snowflake, Databricks, BigQuery), and does one platform dominate? (picks the camp - see step 1)
  2. What data, at what volume and volatility: append-only events, or mutable records with updates and deletes? (drives cadence and delete semantics)
  3. Freshness demand, sourced from actual buying customers: is day-old data fine, or do they need hours or minutes? What did they say, not what sounds ambitious?
  4. Compliance regimes and regions: EU personal data in scope? Any customers in countries with data-localization mandates (e.g. China's PIPL, Russia, India)?
  5. Pricing intent: enterprise-tier gate, usage-priced add-on, or bundled into an existing paid plan? If the plan is "free feature", flag it now - see Failure modes.
  6. Recipient clouds: one of AWS/GCP/Azure, or a mix? (drives the credential and encryption mapping)
  7. Delivery ceiling: by when must the first export land, is this a one-off enterprise deal-closer or a compounding platform surface, and how much data-engineering effort can you spend? (re-ranks both menus below - a hard deadline promotes the low-effort rungs, a compounding mandate promotes the table-format and CDC investments)
If your harness has persistent memory, store the design's settled decisions so later runs (a new dataset, a cadence upgrade, a residency review) start from the design instead of re-deriving it. Store:
  • Chosen camp
  • Partition and file-size contract
  • Cadence rung, with its promotion condition
  • Credential model
  • Cost-allocation split
  • Residency posture
在设计任何内容之前先问这些问题;每个答案都会改变后续步骤。把它们批量提出——这是一项战术性设计任务,不是策略面谈。
  1. 客户仓库格局:目标账户中有多大比例已经在运行可共享的仓库或湖仓(Snowflake、Databricks、BigQuery),是否有一个平台占主导地位?(决定阵营——见步骤1)
  2. 什么样的数据、体量和变动性:仅追加的事件,还是带更新和删除的可变记录?(决定节奏和删除语义)
  3. 新鲜度需求,要来自实际付费客户:一天前的数据可以吗,还是需要小时级或分钟级?他们实际怎么说的,而不是什么听起来有野心。
  4. 合规制度和地区:是否涉及欧盟个人数据?有没有客户所在国家有数据本地化要求(如中国的PIPL、俄罗斯、印度)?
  5. 定价意图:企业版门槛、按使用量计费的附加组件,还是捆绑到现有付费计划中?如果计划是“免费功能”,现在就说出来——见失败模式。
  6. 接收方云:AWS/GCP/Azure之一,还是混合?(决定凭据和加密映射)
  7. 交付上限:首个导出最晚必须何时落地?这是一次性的企业关单工具,还是一个可复利的平台面?你能投入多少数据工程工作量?(会重新排列下面两个菜单——硬性截止日期会推高低投入档位,复利型任务会推动表格式和CDC投入)
如果你的运行环境有持久化记忆,请存储设计已确定的决策,以便后续运行(新数据集、节奏升级、驻留审查)从该设计出发,而不是重新推导。存储:
  • 已选阵营
  • 分区和文件大小契约
  • 节奏档位及其升级条件
  • 凭据模型
  • 成本分摊拆分
  • 驻留姿态

Data-stack maturity

数据栈成熟度

The design splits by the customer's data-stack maturity:
  • Warehouse-resident consumers - already live in Snowflake, Databricks, or BigQuery. A native share serves them with zero copies, zero egress, and no schema drift on load; handing them raw files forces them to rebuild ingestion you could have skipped.
  • Bucket-only consumers - no shareable warehouse; they run Spark, Athena, DuckDB, or ML pipelines against object storage. Partitioned Parquet in a bucket is the only shape they can consume.
Design for the mix you actually have, not the sophisticated end. Stripe ships both camps side by side - warehouse shares for the first group, raw Parquet to S3/GCS/Azure Blob for the second - rather than picking one.
设计根据客户的数据栈成熟度进行拆分:
  • 仓库驻留消费者——已经使用Snowflake、Databricks或BigQuery。原生共享能以零拷贝、零出口流量、加载时无schema漂移的方式服务他们;把原始文件交给他们,会迫使他们重建你本可以跳过的数据接入。
  • 仅对象存储消费者——没有可共享仓库;他们在对象存储上运行Spark、Athena、DuckDB或ML管道。桶中的分区Parquet是唯一能消费的形态。
为实际拥有的混合群体设计,而不是为最复杂的那一端。Stripe是两个阵营并行交付——对第一组提供仓库共享,对第二组提供原始Parquet到S3/GCS/Azure Blob——而不是二选一。

Workflow

工作流

  1. Choose the camp - file-drop, native share, or both.
  2. Specify the file-layout and partitioning contract.
  3. Set the delivery cadence and the freshness posture.
  4. Design the security and credential model.
  5. Allocate egress, storage, and compute cost.
  6. Write the schema-evolution contract.
  7. Settle compliance and residency.
  8. Stage the rollout.
Each step has a section below, in order.
  1. 选择阵营——文件落盘、原生共享,或两者兼有。
  2. 明确文件布局和分区契约。
  3. 设定交付节奏和新鲜度姿态。
  4. 设计安全和凭据模型。
  5. 分摊出口流量、存储和计算成本。
  6. 编写schema演化契约。
  7. 解决合规和驻留问题。
  8. 分阶段发布。
每个步骤在下面有一节,按顺序排列。

1. Choose the camp

1. 选择阵营

Two architectural camps ship in production, plus one outlier:
  • effort:
    streaming push > Parquet file-drop > native warehouse/lake share
  • value:
    native share > file-drop > streaming push
    (for warehouse-resident consumers; flips to
    file-drop > native share
    when consumers are bucket-only)
  • efficiency:
    native share > file-drop > streaming push
  • Default rung: native warehouse/lake sharing - Snowflake Secure Data Sharing, Databricks Delta Sharing, BigQuery linked datasets - whenever a meaningful share of target accounts concentrate on one warehouse platform (roughly 30-40%+ on one platform; that threshold is self-set, not a vendor-published number). Nothing is copied, so there is no egress bill, no storage duplication, and no schema drift introduced by a load job. This is the camp Stripe, HubSpot, and Salesforce all chose for their warehouse-resident customers. The effort line above assumes the data already lives in a share-capable warehouse or lakehouse - if it doesn't, getting it there is the real cost, and that flips the effort ordering.
  • Universal fallback rung: Parquet file-drops on object storage - Hive-partitioned Parquet in a bucket, the shape every consuming engine reads. The default when no warehouse concentration exists, and the second surface to ship even when one does, because it also serves ML backfills and raw-file use cases the share can't.
  • Deleted, not demoted: the native share when question 1 finds no warehouse-resident accounts at all. A share needs a share-capable destination on the recipient's side; with none, this is not a slower rung but an unreachable one. Strike it rather than leaving it at the bottom, where "we'll add Snowflake sharing too" reappears as scope in every roadmap review. Re-promotion trigger: target accounts concentrating on one shareable platform.
  • Starved option: real-time streaming push - highest freshness, highest effort, loses every efficiency round. Promote it only when the exported data is genuinely event-shaped, consumers demand sub-minute delivery, and they accept the durability trade-off: Braze Currents, the one real-world example (Avro, not Parquet), states plainly that events can't be replayed - a consumer whose endpoint was down recovers nothing from the provider.
This ranking is a default, not a law. Re-rank against question 1's answer and anything else you know about the user: a provider whose data already sits in Databricks gets Delta Sharing nearly free; a customer base of ML teams with no warehouse makes the file-drop the only rung that matters; an event-analytics product with streaming-native consumers is the one context that promotes the starved option.
Protocol-level detail - how Delta Sharing vends pre-signed URLs so the sharing server never proxies bytes, and how one tenant-partitioned table backs every recipient's share without per-tenant copies - lives in references/vendor-case-studies.md.
两个生产级架构阵营,外加一个异类:
  • 工作量:
    流式推送 > Parquet文件落盘 > 原生仓库/湖共享
  • 价值:
    原生共享 > 文件落盘 > 流式推送
    (针对仓库驻留消费者;当消费者仅使用对象存储时翻转为
    文件落盘 > 原生共享
    )
  • 效率:
    原生共享 > 文件落盘 > 流式推送
  • 默认档位:原生仓库/湖共享——Snowflake Secure Data Sharing、Databricks Delta Sharing、BigQuery链接数据集——只要目标账户中有相当比例集中在同一个仓库平台上(大约30-40%以上在同一平台;该阈值是自行设定的,不是供应商发布的数据)。没有任何复制,因此没有出口流量账单、没有存储重复、也没有加载作业引入的schema漂移。Stripe、HubSpot和Salesforce都为自己的仓库驻留客户选择了这个阵营。上面的工作量对比假设数据已经存在于可共享的仓库或湖仓中——如果不是,把数据搬进去才是真正的成本,这会翻转工作量排序。
  • 通用兜底档位:对象存储上的Parquet文件落盘——桶中的Hive分区Parquet,所有消费引擎都能读取的形态。当不存在仓库集中时是默认选择;即使存在集中,也是第二个要交付的数据面,因为它还能服务共享无法满足的ML回填和原始文件用例。
  • **删除而不是降级:当问题1发现完全没有仓库驻留账户时,原生共享不是更慢的档位,而是不可达的档位。**共享需要接收方一侧有可共享的目标;没有的话,这不是更慢的档位,而是无法实现的档位。把它划掉,而不是留在最底部,否则“我们以后也加Snowflake共享”会在每次路线图评审中重新变成范围。重新提升触发条件:目标账户集中在某个可共享平台上。
  • 被冷落的选项:实时流式推送——新鲜度最高、工作量最大、在每轮效率对比中都落败。只有当被导出的数据确实是事件形态、消费者要求秒级交付、并且他们接受持久性权衡时才提升它:Braze Currents——唯一现实例子(Avro,不是Parquet)——明确说明事件无法重放;端点宕机的消费者无法从供应商处恢复任何数据。
这个排序是默认值,不是铁律。要根据问题1的答案以及你对用户的了解重新排序:数据已经放在Databricks中的供应商几乎可以免费获得Delta Sharing;没有仓库的ML团队客户群使文件落盘成为唯一重要的档位;拥有流式原生消费者的事件分析产品是唯一会提升那个被冷落选项的场景。
协议级细节——Delta Sharing如何提供预签名URL,使共享服务器永不代理字节;以及如何用一个按租户分区的表支撑每个接收方的共享而无需按租户复制——见 references/vendor-case-studies.md。

2. Specify the file-layout and partitioning contract

2. 明确文件布局和分区契约

For the file-drop camp, the layout is the contract. Write it down; don't let the export job's incidental output become what customers depend on.
  • Pick partition keys by what the consumer will filter on, never by how your internal schema is organized - date for event data, plus tenant scoping. Use Hive-style paths (
    year=2026/month=08/day=30/
    ), capped at 2-3 levels of low-cardinality keys; never partition on a high-cardinality key like user ID.
  • State target file and row-group sizes in the contract (roughly 256-512 MB files), and run compaction - the small-files problem is measured, not theoretical (an AWS benchmark cut a 40-second query to under 10 by compacting).
  • Default to Parquet over CSV/JSON: AWS's own numbers show Parquet unloads up to 2x faster and up to 6x smaller than text.
  • Register the schema in a catalog (Glue, Iceberg REST, Hive Metastore) rather than leaving consumers to infer it from files.
  • Graduate from raw partitioned Parquet to a table format (Iceberg, Delta, Hudi) only when the export needs atomic multi-file commits, time-travel, or in-place schema evolution - not before; raw Parquet is cheaper to operate when those guarantees aren't needed.
Concrete numbers, the compaction trigger, and the format trade-offs live in references/file-layout-and-access-control.md.
对于文件落盘阵营,布局就是契约。把它写下来;不要让导出作业的附带输出成为客户依赖的东西。
  • 根据消费者会过滤什么来选择分区键,绝不要根据内部schema的组织方式——事件数据用日期,再加上租户范围。使用Hive风格路径(
    year=2026/month=08/day=30/
    ),限制在2-3层低基数键;绝不要对user ID这样的高基数键做分区。
  • 在契约中明确目标文件和行组大小(大约256-512 MB文件),并运行压缩——小文件问题是已被量化的,不是理论(一项AWS基准测试通过压缩把40秒查询降到10秒以内)。
  • 默认使用Parquet而不是CSV/JSON:AWS自己的数据显示Parquet卸载比文本快最多2倍、小最多6倍。
  • 在目录(Glue、Iceberg REST、Hive Metastore)中注册schema,而不是让消费者从文件中推断。
  • 只有当导出需要原子多文件提交、时间旅行或就地schema演化时,才从原始分区Parquet升级到表格式(Iceberg、Delta、Hudi)——不要提前;在不需要这些保证时,原始Parquet运营成本更低。
具体数字、压缩触发条件和格式权衡见 references/file-layout-and-access-control.md。

3. Set the delivery cadence and the freshness posture

3. 设定交付节奏和新鲜度姿态

The cadence ladder - build complexity rises monotonically, operating cost at scale falls:
  • effort to build:
    streaming push > log-based CDC > micro-batch incremental > scheduled full-dump
  • operating cost at scale:
    scheduled full-dump > micro-batch incremental > log-based CDC
  • freshness:
    streaming push > log-based CDC > micro-batch incremental > scheduled full-dump
  • efficiency:
    scheduled full-dump > micro-batch incremental > log-based CDC > streaming push
  • Default rung: scheduled full-dump. Idempotent overwrite, no delete-tracking, simplest to operate. Stripe's full load every 3 hours is the concrete reference cadence. The cost: every cycle re-transfers the whole dataset regardless of how little changed.
  • Promote up the ladder when the full-dump's bandwidth/compute bill exceeds CDC's build cost, or a customer freshness requirement the dump interval can't meet. Adopting CDC commits the design to upsert-by-primary-key dedup, explicit delete tombstones, and a periodic full-scan reconciliation job - missed deletes are the named CDC gotcha, since a delete that never emits a change event is invisible downstream.
  • Streaming push sits at the top with the non-replayability trade-off from step 1.
This order is a default too. Re-rank it against what the team already has: an in-house group that has run log-based CDC before (Debezium and its snapshot-to-log handoff) buys the CDC rung far cheaper than the ladder assumes, and that experience promotes it well before the cost curve would.
Separately from the rung, publish an explicit freshness posture - one of three, and say which:
  1. Fixed cadence - Stripe: a full load every 3 hours, unconditional.
  2. Best-effort target - Amplitude: "aims to export five million events per hour", explicitly variable under shared load.
  3. Contractual SLA - Fivetran: 99.9% uptime, penalty-backed.
"Best-effort hourly" and "99.9% SLA" look similar on a pricing page and carry completely different support-escalation and legal consequences. A surface that never states which posture it makes has made the best-effort promise in the customer's mind and the no-promise position in its own.
节奏阶梯——构建复杂度单调上升,规模化运营成本下降:
  • 构建工作量:
    流式推送 > 基于日志的CDC > 微批增量 > 定时全量导出
  • 规模化运营成本:
    定时全量导出 > 微批增量 > 基于日志的CDC
  • 新鲜度:
    流式推送 > 基于日志的CDC > 微批增量 > 定时全量导出
  • 效率:
    定时全量导出 > 微批增量 > 基于日志的CDC > 流式推送
  • 默认档位:定时全量导出。 幂等覆盖、不需要追踪删除、运维最简单。Stripe每3小时全量加载是具体的参考节奏。成本是:每个周期都重新传输整个数据集,无论变化有多小。
  • 向上提升档位,当全量导出的带宽/计算账单超过CDC的构建成本,或者客户有转储间隔无法满足的新鲜度要求时。采用CDC使设计承诺按主键做upsert去重、显式删除墓碑,以及定期全量扫描对账作业——漏删是CDC众所周知的坑,因为从未发出变更事件的删除在下游是不可见的。
  • 流式推送位于顶端,带着步骤1中的不可重放权衡。
这个顺序也是默认的。要针对团队已有能力重新排序:一个之前运行过基于日志CDC的内部团队(Debezium及其快照到日志的交接)获得CDC档位的成本远低于阶梯假设,而且这种经验会让它远在成本曲线要求之前就被提升。
与档位分开,发布一个明确的新鲜度姿态——三选一,并说明是哪个:
  1. 固定节奏——Stripe:每3小时一次全量加载,无条件。
  2. 尽力而为目标——Amplitude:“目标每小时导出五百万事件”,在共享负载下明确可变。
  3. 契约性SLA——Fivetran:99.9%可用性,有惩罚机制。
“尽力而为的小时级”和“99.9% SLA”在定价页上看起来相似,但带来完全不同的支持升级和法律后果。一个从不说明采用哪种姿态的数据面,在客户心中已经做出了尽力而为的承诺,而它自己则处于无承诺的位置。

4. Design the security and credential model

4. 设计安全和凭据模型

  • Never proxy the bytes through your own servers. Every production sharing mechanism - Delta Sharing, Snowflake, BigQuery - vends short-lived signed URLs or scoped temporary credentials so the recipient reads object storage directly; your service does authorization and URL-signing, and throughput scales with the storage layer.
  • Issue per-recipient credentials, never shared or static keys: cross-account roles with an external ID on AWS, SAS tokens on Azure, and one KMS grant per recipient so revoking one customer never touches another.
  • Isolate recipients along the maturity ladder, moving up only as tenant count forces it:
    dedicated bucket per tenant > shared bucket with prefix isolation > per-recipient access points > broker-minted short-term credentials
    .
  • Encrypt with customer-manageable keys (CMEK/SSE-KMS); rotation must not require re-encrypting historical data, and per-file encryption is the finer-grained option when one bucket serves recipients with different trust levels.
  • Pin the access-review cadence to the credential TTL - expiration is the enforcement point, not per-request ACL checks.
Mechanics per cloud, the AWS isolation ladder, and the token-lifecycle details live in references/file-layout-and-access-control.md.
  • 绝不要通过自己的服务器代理字节。每个生产级共享机制——Delta Sharing、Snowflake、BigQuery——都提供短期签名URL或受限临时凭据,让接收方直接读取对象存储;你的服务只做授权和URL签名,吞吐量随存储层扩展。
  • 为每个接收方签发独立凭据,绝不使用共享或静态密钥:AWS上带external ID的跨账户角色、Azure上的SAS令牌,以及每个接收方一个KMS授权,这样撤销一个客户永远不会影响另一个。
  • 按成熟度阶梯隔离接收方,只有租户数量迫使时才向上移动:
    每租户专用桶 > 带前缀隔离的共享桶 > 每接收方访问点 > broker铸造的短期凭据
    。
  • 使用客户可管理密钥(CMEK/SSE-KMS)加密;轮换不能要求重新加密历史数据;当一个桶服务不同信任级别的接收方时,按文件加密是更细粒度的选项。
  • 将访问评审节奏绑定到凭据TTL——过期是执行点,而不是逐请求ACL检查。
各云的具体机制、AWS隔离阶梯和令牌生命周期细节见 references/file-layout-and-access-control.md。

5. Allocate egress, storage, and compute cost

5. 分摊出口流量、存储和计算成本

Three cost layers; name who pays each, in writing, before launch:
  1. Infrastructure cost allocation follows the camp.
    • File-drop: the customer pays everything - their bucket, their reprocessing compute. Segment's model: customers own and pay AWS directly, down to the transform cluster Segment runs inside the customer's own account.
    • Warehouse share: nothing is copied, so nobody pays storage duplication, and the consumer pays only query compute. Snowflake's model; HubSpot tells customers outright they owe all Snowflake costs incurred reading the share.
  2. Egress is the decisive line item. Cross-region and cross-cloud transfer can contribute up to 70% of total data-transfer cost (Snowflake's own published figure - a vendor number, and one that flatters the optimizer it sells); same-region is typically free.
    • Know which side of the share eats it: in cross-region native sharing the provider can end up paying egress that scales with consumer query volume (a caveat raised by a competitor source - weight accordingly, but the economics are real).
    • Snowflake shipped an Egress Cost Optimizer (GA 2025-04-15) precisely because of this: replicate once, pay egress on increments only. The up-to-96% savings figure is a vendor claim, though one customer, RavenPack, reports a 14-fold cost reduction.
  3. What you charge is independent of who pays infrastructure. Every vendor studied prices bulk export as an enterprise-tier or usage-priced add-on: there is no observed free-tier precedent for this feature class.
    • Stripe bills a subscription keyed to transaction count.
    • Braze gates behind an enterprise contract.
    • HubSpot gates behind its top tier.
三层成本;在发布前书面明确谁支付每一层:
  1. 基础设施成本分摊跟随阵营。
    • 文件落盘:客户支付一切——他们的桶、他们的再处理计算。Segment的模式:客户直接拥有并支付AWS,直到Segment在客户自己账户内运行的转换集群。
    • 仓库共享:不复制任何内容,所以没有人支付存储重复,消费者只支付查询计算。Snowflake的模式;HubSpot直接告诉客户,他们需要承担读取共享所产生的所有Snowflake成本。
  2. 出口流量是决定性项目。 跨区域和跨云传输可能占全部数据传输成本的70%(Snowflake自己发布的数据——一个供应商数字,而且是有利于它销售的优化器的数字);同区域通常免费。
    • 要知道共享的哪一方承担它:在跨区域原生共享中,_提供商_最终可能支付随消费者查询量扩展的出口流量(一个竞争对手来源提出的警告——相应权衡,但经济性是真实的)。
    • Snowflake正是为此发布了Egress Cost Optimizer(GA 2025-04-15):只复制一次,仅对增量支付出口流量。高达96%的节省是供应商声称,不过一个客户RavenPack报告成本降低14倍。
  3. 你的收费独立于谁支付基础设施。 每个被研究的供应商都将批量导出定价为企业版或按使用量计费的附加组件:这个功能类别没有观察到免费版先例。
    • Stripe按交易数量订阅收费。
    • Braze放在企业合同后面。
    • HubSpot放在最高档后面。

6. Write the schema-evolution contract

6. 编写schema演化契约

The export's schema is an API contract whose breaking changes ship silently - a source-system rename propagates into the customer's dashboards with no deprecation header. Treat it with API-versioning discipline:
  • Add-only posture: append new nullable columns at the end; never rename, remove, or retype in place. Renames break Parquet consumers outright (column names are the identifiers); the correct move is add-new-plus-deprecate-old.
  • Keep column ordering and types consistent across every batch - engines' predicate pushdown and by-name column matching both depend on it.
  • Register every schema version in the catalog and validate the written schema against the documented contract before a delivery counts as successful, so drift raises an alert instead of a customer ticket.
  • Frame the full commitment as a four-part data contract, because a BI dashboard, an ML pipeline, and a dbt job each depend on a different subset:
    • Schema: columns, types, nullability.
    • Quality: completeness thresholds.
    • Freshness: the step-3 posture.
    • Availability.
  • When a breaking change is genuinely unavoidable, run it like an API deprecation: announced window, parallel old-and-new columns or paths, dated removal. Sibling
    samber/developer-platform-skills@api-versioning-policy
    owns that notice-period machinery; this contract defines what counts as breaking for files and tables.
导出的schema是一个API契约,其破坏性变更会静默发布——源系统的重命名会传播到客户的仪表板,而没有弃用头。要用API版本管理纪律对待它:
  • 只增姿态:在末尾追加新的可空列;绝不在原位置重命名、删除或改类型。重命名会直接破坏Parquet消费者(列名就是标识符);正确做法是新增并弃用旧列。
  • 保持每个批次的列顺序和类型一致——引擎的谓词下推和按名称匹配列都依赖这一点。
  • 在目录中注册每个schema版本,并在交付算成功之前,将实际写入的schema与文档化契约校验,这样漂移会触发告警,而不是客户工单。
  • 将完整承诺定义为四部分数据契约,因为BI仪表板、ML管道和dbt作业各自依赖不同子集:
    • Schema:列、类型、可空性。
    • 质量:完整性阈值。
    • 新鲜度:步骤3的姿态。
    • 可用性。
  • 当破坏性变更确实不可避免时,像API弃用那样处理:公告窗口、新旧列或路径并行、注明移除日期。同系列的
    samber/developer-platform-skills@api-versioning-policy
    负责通知期机制;本契约定义文件和表格的什么情况算破坏性变更。

7. Settle compliance and residency

7. 解决合规和驻留问题

Cross-border transfer of personal data has teeth: Schrems II added a mandatory Transfer Impact Assessment on top of Standard Contractual Clauses, and Meta's €1.2B fine (2023) was specifically for cross-border transfer failures. Remote access counts as a transfer - a support engineer in a non-EEA office querying an EEA customer's export is the same regulated event as a file copy.
Prefer the architectural fix over the paperwork path, in this order:
  1. Region-pin from day one - EU data in EU buckets/shares eliminates the transfer question at the source. Segment deprecated its EU Data Lakes product rather than retrofit compliance onto a US-region design; region selection is a day-one setting in every major platform for this reason, and retrofitting it is what the Segment case says it is: sometimes cheaper to kill the product.
  2. Regionalized CMEK - a key that never leaves the region closes the "ciphertext moved, but it's unreadable" loophole regulators don't accept.
  3. Pseudonymized replicas - strip or tokenize identifying fields before any copy leaves its home region.
  4. Localization mandates are hard blockers, not paperwork - China's PIPL and similar laws can forbid the transfer outright; Stripe simply does not offer Data Pipeline in India, citing data localization. "Not offered in region X" is a legitimate, precedented design outcome.
Full legal-mechanism ordering (adequacy → SCC/BCR + TIA → derogations) and the pattern details live in references/compliance-and-residency.md.
个人数据跨境转移是有牙齿的:Schrems II在标准合同条款之上增加了强制性传输影响评估(TIA),Meta的12亿欧元罚款(2023)正是针对跨境传输失败。远程访问也算一种传输——非EEA办公室的支持工程师查询EEA客户的导出,与文件复制是同一类受监管事件。
优先选择架构性修复,而不是文书路径,顺序如下:
  1. 从第一天起固定区域——欧盟数据放在欧盟桶/共享中,从源头上消除传输问题。Segment放弃其EU Data Lakes产品,而不是把合规改造到美国区域设计上;正因如此,区域选择在每个主要平台都是第一天设置,而事后改造正如Segment案例所示:有时杀死产品更便宜。
  2. 区域化CMEK——一个从不离开区域的密钥,堵上监管者不接受的“密文移动了,但不可读”漏洞。
  3. 假名化副本——在任何副本离开其所在区域之前,剥离或令牌化标识字段。
  4. 本地化要求是硬性障碍,不是文书工作——中国的PIPL和类似法律可以直接禁止传输;Stripe干脆不在印度提供Data Pipeline,理由是数据本地化。“在X地区不提供”是合法且有先例的设计结果。
完整的法律机制排序(充分性 → SCC/BCR + TIA → 克减)和模式细节见 references/compliance-and-residency.md。

8. Stage the rollout

8. 分阶段发布

Deliver the design as a staged plan, not a single launch (thresholds here are self-set, not vendor-published figures):
  1. Native warehouse share for the dominant warehouse platform, if question 1 found concentration.
  2. Parquet-on-object-storage file drop as the universal fallback - partitioned, cataloged, per-recipient credentials.
  3. Cadence upgrades (incremental/CDC) only when full-dump cost or a customer freshness requirement forces them.
  4. Premium gating and the published freshness posture - priced as an enterprise tier or add-on from day one.
  5. Build vs partner: buy or partner for standard delivery paths (the warehouse's own sharing primitive, an established movement vendor); build in-house only for what no vendor covers. Fivetran itself - with a working prototype in hand - acquired Census (May 2025) rather than build reverse ETL internally, because read-path and write-path data movement are different engineering problems. Revisit the choice when a vendor's usage pricing crosses the fully-loaded cost of roughly 1-2 data engineers.
Region pinning (step 7) is cross-cutting: bake it into stages 1-2, never bolt it on at stage 4.
将设计作为分阶段计划交付,而不是一次单一发布(这里的阈值是自行设定的,不是供应商发布的数据):
  1. 如果问题1发现了集中,为占主导地位的仓库平台提供原生仓库共享。
  2. 对象存储上的Parquet文件落盘作为通用兜底——分区、编目、每接收方凭据。
  3. 只有当全量导出成本或客户新鲜度要求迫使时,才进行节奏升级(增量/CDC)。
  4. 高级门控和已发布的新鲜度姿态——从第一天起作为企业版或附加组件定价。
  5. 构建 vs 合作:标准交付路径采用购买或合作(仓库自身的共享原语、成熟的迁移供应商);只有没有任何供应商覆盖的才自研。Fivetran自己——手中已有可用原型——收购了Census(2025年5月),而不是内部构建反向ETL,因为读路径和写路径的数据移动是不同的工程问题。当供应商的使用量定价超过约1-2名数据工程师的完全加载成本时,重新审视这个选择。
区域固定(步骤7)是横切关注点:在阶段1-2就融入,绝不在阶段4才加上。

Failure modes

失败模式

Anti-pattern checklist - each is a direct review finding:
  • Silent schema drift: a rename or type change ships to the export because nothing validates batches against a documented contract. The costliest failure in this domain - the break lands in the customer's dashboards, not your logs.
  • Egress bill shock: cross-region sharing launched without knowing which party pays per-byte egress, discovered on the first invoice at 70%-of-transfer-cost scale.
  • Cross-border violation: one global bucket for engineering simplicity, which silently commits you to SCC/TIA paperwork for every EU customer - or to a Meta-scale finding.
  • Free-tier giveaway: bulk export bundled free, against a feature class where every vendor studied gates it behind a premium tier - margin surrendered that tier repricing can't easily claw back.
  • Proxied bytes: export downloads routed through your API servers, making your fleet the throughput ceiling and the egress payer at once.
  • Small-files decay: no compaction, thousands of tiny files, consumer queries slow to a crawl - the measured 4x penalty.
  • CDC without delete reconciliation: deletes that never emit events accumulate as phantom rows in every customer's copy.
  • Static shared credentials: one key for all recipients, so a single leak or offboarding rotates everyone.
  • Streaming without the replay warning: consumers discover during their first outage that missed events are gone; if you ship a non-replayable stream, the contract must say so as loudly as Braze does.
反模式清单——每一条都是直接的评审发现:
  • 静默schema漂移:因为没有任何东西用文档化契约校验批次,重命名或类型变更被发布到导出。这是该领域代价最高的失败——破坏落在客户的仪表板里,而不是你的日志里。
  • 出口流量账单冲击:跨区域共享上线时不知道哪一方按字节支付出口流量,在第一张账单上以占传输成本70%的规模被发现。
  • 跨境违规:为了工程简化使用一个全球桶,这让你在不知情中为每个欧盟客户承诺SCC/TIA文书——或者面临Meta级别的处罚。
  • 免费层赠送:批量导出免费捆绑,而这个功能类别中每个被研究的供应商都把它放在高级档后面——放弃的利润空间很难通过重新定价收回。
  • 代理字节:导出下载通过你的API服务器路由,使你的集群同时成为吞吐量瓶颈和出口流量支付方。
  • 小文件衰变:没有压缩、成千上万个小文件、消费者查询慢如蜗牛——已测得的4倍惩罚。
  • 没有删除对账的CDC:从未发出事件的删除在每个客户的副本中累积为幻影行。
  • 静态共享凭据:所有接收方共用一个密钥,一次泄漏或一次离职就要轮换所有人。
  • 没有重放警告的流式:消费者在第一次宕机时才发现错过的事件已经消失;如果你交付不可重放的流,契约必须像Braze那样大声说出来。

Measurement

度量

Four binary gates; iterate the design until all four pass:
  1. Contract completeness: every export surface has a written data contract covering schema (columns, types, nullability) and an explicit freshness posture (fixed cadence, best-effort, or SLA - named as such). A surface with an implicit schema or an unstated posture fails.
  2. Cost allocation named: for each shipped delivery model, who pays storage, compute, and egress is written down, including the cross-region case. Any unattributed egress path fails.
  3. Residency coverage: every regulated region present in the customer base has a documented posture - region-pinned, legal-mechanism-documented, or explicitly not offered. An EU customer on an unpinned global bucket with no documented SCC/TIA fails.
  4. Premium gating: bulk export sits behind a paid tier or add-on, or the design records an explicit, argued decision to break the industry-wide precedent.
Trends to watch after launch, never pass thresholds:
  • Share of deliveries meeting the stated freshness posture.
  • Consumer-reported schema-break incidents (target direction: zero).
  • Egress cost per recipient per month.
四个二元门;迭代设计直到四个全部通过:
  1. 契约完整性:每个导出面都有书面数据契约,涵盖schema(列、类型、可空性)和明确的新鲜度姿态(固定节奏、尽力而为或SLA——明确命名)。隐式schema或未说明姿态的数据面为失败。
  2. 成本分摊明确:对每个交付模式,谁支付存储、计算和出口流量都已写清楚,包括跨区域情况。任何未归属的出口流量路径为失败。
  3. 驻留覆盖:客户群中每个受监管地区都有文档化姿态——区域固定、文档化法律机制,或明确不提供。一个未固定区域的全球桶上的欧盟客户,没有文档化SCC/TIA,为失败。
  4. 高级门控:批量导出位于付费档或附加组件之后,或者设计记录了打破行业广泛先例的明确、有论证的决策。
发布后要关注的趋势,不要设置通过阈值:
  • 满足所声明新鲜度姿态的交付比例。
  • 消费者报告的schema破坏事件(目标方向:零)。
  • 每接收方每月出口流量成本。

Invocation examples

调用示例

  • "Our enterprise customers keep asking to get their data into Snowflake - design a bulk export surface, and tell me whether to build file drops or a native share."
  • "Design the Parquet layout and schema-evolution rules for our S3 data export so customer dashboards stop breaking when we change columns."
  • "We want to sell a data export add-on: what cadence can we promise, who pays the egress, and what do we do about our EU customers?"
  • “我们的企业客户一直要求把数据放进Snowflake——设计一个批量导出面,并告诉我应该构建文件落盘还是原生共享。”
  • “为我们的S3数据导出设计Parquet布局和schema演化规则,这样我们改列时客户仪表板不再坏掉。”
  • “我们想销售数据导出附加组件:我们能承诺什么节奏,谁支付出口流量,我们的欧盟客户怎么处理?”

References

参考资料

  • references/vendor-case-studies.md - the vendor comparison table (Stripe, Segment, Amplitude, Braze, HubSpot, Fivetran) and the sharing-platform landscape (Snowflake, Delta Sharing, BigQuery, Iceberg REST Catalog, Salesforce Zero Copy, AWS Data Exchange), with Delta Sharing protocol mechanics and the build-vs-partner evidence.
  • references/file-layout-and-access-control.md - partitioning and compaction numbers, table-format graduation triggers, the multi-tenant isolation ladder, and per-cloud credential/encryption mechanics.
  • references/compliance-and-residency.md - GDPR transfer mechanics, Schrems II/TIA, the architectural pattern ordering, and the localization-mandate cases.
See also, same collection:
  • samber/developer-platform-skills@api-integration-surface-strategy
    - the umbrella decision that chooses bulk files/shares as a surface at all; this skill designs the surface once chosen.
  • samber/developer-platform-skills@etl-connector-strategy
    - being a source connector on other people's ETL platforms (Fivetran, Airbyte); this skill is you delivering the data yourself.
  • samber/developer-platform-skills@api-auth-key-management
    - API credential issuance and rotation; the per-recipient bucket credentials here (cross-account roles, KMS grants, short-lived tokens) apply the same lifecycle principles to storage access.
  • references/vendor-case-studies.md —— 供应商对比表(Stripe、Segment、Amplitude、Braze、HubSpot、Fivetran)和共享平台格局(Snowflake、Delta Sharing、BigQuery、Iceberg REST Catalog、Salesforce Zero Copy、AWS Data Exchange),以及Delta Sharing协议机制和构建vs合作证据。
  • references/file-layout-and-access-control.md —— 分区和压缩数据、表格式升级触发条件、多租户隔离阶梯,以及各云凭据/加密机制。
  • references/compliance-and-residency.md —— GDPR传输机制、Schrems II/TIA、架构模式排序和本地化强制案例。
另见,同一集合:
  • samber/developer-platform-skills@api-integration-surface-strategy
    —— 决定将批量文件/共享作为数据面的总括决策;本技能负责在选定后设计该数据面。
  • samber/developer-platform-skills@etl-connector-strategy
    —— 作为他人ETL平台(Fivetran、Airbyte)上的源连接器;本技能是由你自己交付数据。
  • samber/developer-platform-skills@api-auth-key-management
    —— API凭据签发和轮换;这里的每接收方桶凭据(跨账户角色、KMS授权、短期令牌)将同样的生命周期原则应用于存储访问。