返回

从Kafka依赖到直连接入:Snowpipe Streaming Elastic Channels生产实践

RSS Snowflake Engineering (Medium) AI 逐段翻译 发布 2026-09-25 22:01 收录于 09-26

有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。

DataHot 速览

文章介绍用 Snowpipe Streaming Elastic Channels 替代 Kafka 等中间消息总线,直接将数据流式写入 Snowflake 的生产级架构。作者用一个三行 SDK 调用从 MacBook 直接将 1,010 行数据流入 Snowflake,并展示了持久化确认、实时分析和异常检测能力。实现覆盖 RBAC、密钥对认证、Python SDK 生产者、Dynamic Tables 实时转换、至少一次投递去重与监控,所有 SQL 均在真实 Snowflake 账户验证并附完整代码仓库。

原收录理由(待核验):为数据工程师提供了替代 Kafka 缓冲层的可落地流式接入方案,含认证、去重、实时转换与监控全链路细节,对湖仓与实时分析架构选型有直接参考价值。

本文目录 17 节
  1. 从 Kafka 依赖到直接摄取:使用 Snowpipe Streaming 弹性通道的生产架构
  2. 前后架构对比
  3. 为何这在当下意义重大:自 2026 年 9 月 15 日起全面可用
  4. 弹性通道究竟是什么
  5. 实现方案
  6. 基础:RBAC 与对象层次结构
  7. 流式表
  8. 生产者:替代 Kafka 的三行代码
  9. 生产模式——有界确认窗口:
  10. 认证:密钥对,而非密码
  11. 使用动态表进行实时转换
  12. 监控与可观测性
  13. 验证结果
  14. 权衡
  15. 生产环境注意事项
  16. 代码仓库
  17. 关键要点

译文

AI 逐段翻译

从 Kafka 依赖到直接摄取:使用 Snowpipe Streaming 弹性通道的生产架构

我如何用三行 SDK 调用替换掉中间消息总线,并从一台 MacBook 直接将 1,010 行流式写入 Snowflake——具备持久化确认、实时分析和异常检测。

Snowflake 架构图,展示了从基于 Kafka 的流式传输向使用 Snowpipe Streaming 弹性通道、动态表和实时分析进行直接摄取的转变。
简而言之: Snowpipe Streaming 弹性通道(2026 年 9 月 15 日全面可用)让你可以将数据直接流式写入 Snowflake——无需 Kafka、无需连接器、无需暂存层。本文详细介绍了我构建并端到端验证的一套生产实现:RBAC、密钥对认证、Python SDK 生产者、用于实时转换的动态表、针对至少一次投递的去重以及监控——每一行 SQL 都已执行,每一项声明都已在实时 Snowflake 账户上验证。包含完整代码仓库。

多年来,将数据流式传入 Snowflake 的默认架构看起来都一样:应用程序产生事件,Kafka(或 Kinesis,或 Pub/Sub)对其进行缓冲,连接器将其排入 Snowflake。消息总线的存在仅仅是为了落地数据。不是为了扇出。不是为了重放。不是为了多个消费者。只是为了把行写入一张表。

这种架构可行,但代价不菲:要运维一个 Kafka 集群、配置一个连接器、维护一个模式注册表,而且延迟下限以分钟而非秒计。当唯一的消费者是 Snowflake 时,消息总线就是一种没有架构用途的架构依赖。

Snowpipe Streaming 弹性通道消除了这种依赖。生产者通过一个隐式的、由服务器扩展的通道直接写入 Snowflake。无需通道生命周期、无需偏移量管理、无需代理。SDK 处理批处理、压缩和重试。Snowflake 负责扩展。其结果是架构更简单、组件更少、延迟更低,并且定价模型与数据量挂钩而非与基础设施挂钩。

本文详细介绍了我构建并端到端验证的一套生产级实现——从创建 Snowflake 对象到从一台 MacBook 进行实时流式传输,并使用动态表进行实时转换,使用监控视图提供运维可见性。

前后架构对比

架构差异显而易见:移除了三个组件(Kafka 集群、模式注册表、连接器),新增了一个隐式组件(完全由 Snowflake 管理的弹性通道)。信任边界从你的基础设施转移到 Snowflake 的摄取服务。

为何这在当下意义重大:自 2026 年 9 月 15 日起全面可用

弹性通道于 2026 年 9 月 15 日达到全面可用。这一区别很重要——这不是一个你用来做原型、然后指望它能存活下来的预览功能。它是生产级的,在所有 AWS、Azure 和 GCP 商业区域均可使用,并享有 Snowflake 的标准 SLA 支持。

让 GA 版本在架构上具有重大意义的,不是任何单一能力,而是它们如何组合。你能获得持久的逐次追加确认,因此你的生产者可以确切知道 Snowflake 何时承担了对数据的责任。你能在 Java、Python 和 Node.js 中获得即发即忘和可等待的追加方法,因此 SDK 能适配你应用程序已有的任何并发模型。你能获得基于回调的结果跟踪,并带有调用方提供的令牌,因此将已确认(或失败)的内容关联回你的源事件无需任何外部簿记。

值得内化的实际约束是:这是至少一次投递,而非精确一次。Snowflake 做了一个刻意的权衡——不提供顺序保证、不提供偏移量令牌、不提供通道协调——以换取大幅简化的生产者体验和自动的服务器端扩展。如果你的管道无法容忍重复,你要么在下游处理去重(就像本实现用动态表所做的那样),要么改用命名通道。需要 SDK 版本 1.8.0 或更高。

弹性通道究竟是什么

Snowflake 中的一条流式管道有一个隐式的 ELASTIC 通道。多个生产者可同时向其追加数据。Snowflake 将追加操作分配到由服务器管理的资源上,无需应用程序创建、命名、打开、关闭或恢复通道。

端到端路径:

  1. SDK 获取一个句柄,通过 get_elastic_channel() 在数据到达时追加行。SDK 在内部进行批处理。
  2. Snowflake 持久地缓冲该追加操作并返回持久化确认——Future 成功完成。
  3. 管道处理行在服务器端进行:验证模式、应用转换、提交到目标表。
  4. 行变为可查询在表处理完成后(实践中约 5 秒)。

关键区别:确认意味着持久,而非可查询。一旦 Future 完成,生产者就可以释放其保留的副本。处理和查询可见性随后到来。

投递语义: 至少一次。无顺序保证。如果生产者在一次不确定的失败后重试,目标表可能包含重复项。这就是为什么每一行都需要一个稳定的事件标识符以供下游去重。

无需 DDL。 在此实现中没有 CREATE PIPE 或 CREATE CHANNEL 语句。当 SDK 调用 get_elastic_channel() 并追加第一行时,Snowflake 会自动创建一个名为 <TABLE_NAME>-STREAMING 的默认管道(在我们的例子中是 SENSOR_READINGS-STREAMING),并带有一个隐式的 ELASTIC 通道。你可以在第一次生产者运行后验证这一点:

SHOW PIPES IN SCHEMA SNOWPIPE_STREAMING_DEMO.STREAMING;
-- Returns: SENSOR_READINGS-STREAMING (is_snowflake_managed = true)

自动创建的管道包含 MATCH_BY_COLUMN_NAME=CASE_INSENSITIVE 和 CLUSTER_AT_INGEST_TIME=TRUE(由于目标表定义了聚类键,因此会自动应用)。你无法 ALTER 或 DROP 这个默认管道——Snowflake 完全管理它。

实现方案

基础:RBAC 与对象层次结构

该实现采用三层角色层次结构,将管理、摄取和分析分开:

-- Role hierarchy
CREATE ROLE IF NOT EXISTS STREAMING_ADMIN;
CREATE ROLE IF NOT EXISTS STREAMING_PRODUCER;
CREATE ROLE IF NOT EXISTS STREAMING_ANALYST;

GRANT ROLE STREAMING_PRODUCER TO ROLE STREAMING_ADMIN;
GRANT ROLE STREAMING_ANALYST  TO ROLE STREAMING_ADMIN;
GRANT ROLE STREAMING_ADMIN    TO ROLE ACCOUNTADMIN;

STREAMING_PRODUCER 仅获得 INSERT 权限——没有 SELECT,没有 DELETE,没有 DDL。该角色用于外部生产者进行密钥对认证。原则是:即使生产者凭证被泄露,也只能追加数据,而无法读取或修改现有数据。注意:如果你在目标表上启用 ENABLE_SCHEMA_EVOLUTION = TRUE(如本实现所做),摄取角色还需要对表具有 EVOLVE SCHEMA 或 OWNERSHIP 权限,自动添加列才能生效。没有该权限时,摄取会成功,但新字段会被静默忽略,而不会创建列。

数据库遵循按关注点划分模式的模式:

三个 Snowflake 模式的分层层次结构。底层的 STREAMING 保存来自 Elastic Channel 的原始摄取表。中间的 ANALYTICS 运行动态表进行实时转换。顶层的 MONITORING 保存可观测性视图和告警。箭头向上流动。

流式表

主要摄取目标处理 IoT 传感器遥测数据:

CREATE OR REPLACE TABLE SENSOR_READINGS (
    EVENT_ID    STRING        NOT NULL,
    DEVICE_ID   STRING        NOT NULL,
    DEVICE_TYPE STRING,
    FACILITY_ID STRING,
    READING_TS  TIMESTAMP_NTZ NOT NULL,
    TEMPERATURE FLOAT,
    HUMIDITY    FLOAT,
    PRESSURE    FLOAT,
    VIBRATION   FLOAT,
    BATTERY_PCT FLOAT,
    METADATA    VARIANT,
    INGESTED_AT TIMESTAMP_NTZ DEFAULT SYSDATE()
)
CLUSTER BY (DEVICE_ID, TO_DATE(READING_TS))
ENABLE_SCHEMA_EVOLUTION = TRUE;

这里有三个设计决策:

  1. EVENT_ID 作为稳定标识符——不是主键约束(Snowflake 不强制唯一性),而是下游动态表中使用的去重键。Elastic Channel 是至少一次语义;这就是你处理它的方式。
  2. ENABLE_SCHEMA_EVOLUTION = TRUE——如果生产者开始发送一个新字段(比如顶层的 SIGNAL_STRENGTH),Snowflake 会自动添加该列。模式演化在持久确认后异步发生。
  3. 按 DEVICE_ID 和日期聚类——通过微分区修剪优化最常见的查询模式(基于设备的时间范围查找)。

生产者:替代 Kafka 的三行代码

Python SDK 生产者非常简单。核心逻辑:

from snowflake.ingest.streaming import StreamingIngestClient

client = StreamingIngestClient.from_table(
    client_name="iot-sensor-producer",
    db_name="SNOWPIPE_STREAMING_DEMO",
    schema_name="STREAMING",
    table_name="SENSOR_READINGS",
    profile_json="profile.json",
)
channel = client.get_elastic_channel()
future = channel.append_row_with_wait(row, row["EVENT_ID"])
future.result()  # Blocks until durable acknowledgment

from_table 创建一个表模式客户端。get_elastic_channel() 返回隐式通道句柄。append_row_with_wait 返回一个 Future,当 Snowflake 持久化数据后完成。这就是整个集成。

SDK 处理批处理(时间和大小阈值)、压缩、瞬时故障重试以及连接管理。基于 Rust 的客户端核心在 Java、Python 和 Node.js SDK 之间共享。

生产模式——有界确认窗口:

pending = deque()
MAX_OUTSTANDING = 500

for row in source:
    if len(pending) >= MAX_OUTSTANDING:
        pending[0].result()  # Back-pressure
        pending.popleft()
    future = channel.append_row_with_wait(row, row["EVENT_ID"])
    pending.append(future)
# Drain remaining
while pending:
    pending.popleft().result()

这会限制内存使用,并在 Snowflake 的确认管道饱和时施加反压。在测试中,使用此模式的 1,000 行数据从单台 MacBook 生产者完成耗时不到 3 秒。

认证:密钥对,而非密码

SDK 通过 profile.json 使用密钥对认证:

{
    "user": "SATISH",
    "account": "mnb51130",
    "url": "https://mnb51130.snowflakecomputing.com:443",
    "private_key_file": "rsa_key.p8",
    "role": "STREAMING_PRODUCER"
}

不存储密码。没有 OAuth 令牌刷新逻辑。私钥保留在生产主机上;公钥通过 ALTER USER ... SET RSA_PUBLIC_KEY 在 Snowflake 中注册。对于生产部署,请将私钥存储在密钥管理器中,并在运行时引用它。

使用动态表进行实时转换

原始流式数据很少可以直接查询。动态表提供具有声明目标延迟的持续转换:

设备健康摘要(1 分钟延迟):

CREATE OR REPLACE DYNAMIC TABLE DEVICE_HEALTH_SUMMARY
    TARGET_LAG = '1 minute'
    WAREHOUSE = COMPUTE_WH
AS
SELECT
    DEVICE_ID,
    DEVICE_TYPE,
    FACILITY_ID,
    COUNT(*)                                        AS TOTAL_READINGS,
    ROUND(AVG(TEMPERATURE), 2)                      AS AVG_TEMPERATURE,
    COUNT_IF(TEMPERATURE > 80 OR TEMPERATURE < -10) AS TEMP_ANOMALY_COUNT,
    COUNT_IF(VIBRATION > 50)                        AS VIBRATION_ANOMALY_COUNT,
    COUNT_IF(BATTERY_PCT < 20)                      AS LOW_BATTERY_COUNT
FROM STREAMING.SENSOR_READINGS
GROUP BY DEVICE_ID, DEVICE_TYPE, FACILITY_ID;

去重(处理至少一次语义):

CREATE OR REPLACE DYNAMIC TABLE SENSOR_READINGS_DEDUPED
    TARGET_LAG = '1 minute'
    WAREHOUSE = COMPUTE_WH
AS
SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (
        PARTITION BY EVENT_ID ORDER BY INGESTED_AT DESC
    ) AS _RN
    FROM STREAMING.SENSOR_READINGS
) WHERE _RN = 1;

这是对 Elastic Channel 至少一次投递的架构解答:原始表接受重复数据;去重动态表在一分钟内解决它们。下游消费者查询去重后的表,而不是原始表。

监控与可观测性

生产流式管道需要运维可见性:

数据新鲜度——检测生产者何时停止发送:

CREATE OR REPLACE VIEW DATA_FRESHNESS AS
SELECT
    'SENSOR_READINGS' AS TABLE_NAME,
    MAX(INGESTED_AT)  AS LATEST_INGESTION,
    DATEDIFF('SECOND', MAX(INGESTED_AT), SYSDATE()) AS STALENESS_SECONDS,
    IFF(DATEDIFF('SECOND', MAX(INGESTED_AT), SYSDATE()) > 300,
        'STALE', 'FRESH') AS STATUS
FROM STREAMING.SENSOR_READINGS;

异常检测——基于阈值的传感器读数告警:

CREATE OR REPLACE VIEW SENSOR_ANOMALIES AS
SELECT EVENT_ID, DEVICE_ID, READING_TS, TEMPERATURE, VIBRATION, BATTERY_PCT,
    CASE
        WHEN TEMPERATURE > 80 THEN 'CRITICAL_HIGH_TEMP'
        WHEN VIBRATION > 50   THEN 'HIGH_VIBRATION'
        WHEN BATTERY_PCT < 10 THEN 'CRITICAL_LOW_BATTERY'
    END AS ANOMALY_TYPE
FROM STREAMING.SENSOR_READINGS
WHERE TEMPERATURE > 80 OR VIBRATION > 50 OR BATTERY_PCT < 10;

Snowflake Alert 每 5 分钟检查一次新鲜度,并在数据过期时记录警告——这是生产者健康状况、网络连接或密钥对认证需要调查的信号。

验证结果

我从一台 MacBook(Apple Silicon M3,Python 3.12,SDK v1.8.0)针对一个实时 Snowflake 账户端到端测试了此实现:

六项 Snowflake 管道检查的结果摘要表,全部通过。快速测试:10 行可在约 5 秒内查询。加载测试:1,000 行约 3 秒,约 333 行/秒。动态表在 1 分钟内刷新。去重:1,000 个唯一 EVENT_ID,零重复。监控新鲜度:67 秒陈旧度下为 FRESH。异常检测:60 条低电量警告。

单台 MacBook 的吞吐量并不代表平台的能力——Elastic Channel 支持每张表高达 20 GB/s。但它验证了 SDK、认证、表模式、动态表和监控视图作为一个完整系统都能正常工作。

权衡

三种 Snowflake 摄取选项在七个维度上的比较表。Elastic Channel:至少一次,无顺序保证,复杂度最低,无服务器,应用侧去重。Named Channel:精确一次,每通道顺序,偏移管理,无服务器,偏移令牌去重。Kafka 加 Connector:配置后精确一次,每分区顺序,连接器管理,需要 Kafka 集群,原生扇出。

在以下情况下使用 Elastic Channel:

  • Snowflake 是唯一或主要消费者
  • 至少一次加上下游去重是可接受的
  • 你想要尽可能简单的生产者代码
  • 你需要在不进行通道协调的情况下接入新的生产者

在以下情况下使用 Named Channel:

  • 你需要精确一次投递或严格顺序
  • 你正在从具有自然分区的源读取(Kafka、CDC)
  • 在应用层处理重复数据并不可行

在以下情况下保留 Kafka:

  • 多个消费者需要同一个事件流
  • 你需要在 Snowflake 之外进行重放、保留或共享访问
  • Kafka 已被其他架构需求证明是合理的

生产环境注意事项

可能出现的故障:

  • 生产者进程崩溃会丢失内存中的 SDK 缓冲区。未确认的事件必须保留在源端。
  • 如果在未更新生产者私钥的情况下轮换公钥,密钥对认证会过期。
  • 生产者与 Snowflake 之间的网络中断。SDK 会重试瞬态故障,但长时间中断需要生产者端缓冲。

需要监控的内容:

  • DATA_FRESHNESS 视图 — 陈旧度超过你的 SLA 阈值
  • SENSOR_READINGS__ERRORS 表 — 服务端处理失败的行
  • 动态表刷新历史 — 延迟超过 TARGET_LAG
  • ACCOUNT_USAGE.PIPE_USAGE_HISTORY — 摄取积分消耗

哪些会产生费用:

  • 摄取:按摄取的未压缩 GB 计费(当前费率见 Snowflake 消耗表 — 博客公告中引用的是 0.0037 积分/GB)。无基础设施成本。
  • 动态表:每个刷新周期的仓库计算。
  • 监控告警:每 5 分钟消耗仓库计算(不需要时暂停)。

代码仓库

完整实现以 GitHub 就绪的仓库形式提供,包含 36 个文件:

探索该实现:GitHub 上的 Snowpipe Streaming 。

snowflake-snowpipe-streaming/
├── sql/01-foundation/      # Roles, warehouse, database
├── sql/02-streaming-tables/ # Sensor readings, clickstream events
├── sql/03-analytics/       # 4 Dynamic Tables
├── sql/04-monitoring/      # Observability views + alerts
├── sql/05-governance/      # RBAC grants
├── producers/python/       # SDK producers (sensor + clickstream)
├── producers/nodejs/       # Node.js SDK producer
├── producers/rest/         # cURL REST API producers
├── scripts/                # deploy.sh, validate.sh, teardown.sh
├── tests/                  # SQL validation tests
├── macbook_setup.sh        # Validated step-by-step local setup
└── docs/                   # Architecture diagram, runbook
└── logs/                   # setup and run logs at mac terminal

macbook_setup.sh 中的每条 MacBook 命令都针对真实 Snowflake 账户进行了测试,并包含验证期间遇到问题的确切故障排除步骤(Apple Silicon 上的 Python 版本要求、pip 升级要求、虚拟环境激活)。

关键要点

Elastic Channels 的意义不在于 Snowflake 现在能够更快地摄取流式数据。Snowpipe Streaming 已经做到了这一点。其意义在于架构层面:整个基础设施层——仅为落地数据而存在的消息总线——可以从管道中消失。

对于 Kafka 服务于多个消费者、共享重放或保留需求的组织而言,Kafka 仍然是合理的。但对于大量消息总线仅作为 Snowflake 摄取暂存层而存在的管道,Elastic Channels 提供了更简单的架构——组件更少、延迟更低、定价透明,且无需运维任何基础设施。

用于摄取的 Elastic Channels、用于持续转换的动态表,以及用于运维可见性的监控视图,三者结合创建了一个完全存在于 Snowflake 内部的完整流式架构。无外部计算。无连接器配置。无代理调优。生产者追加行。Snowflake 处理其余一切。

这才是真正的架构变革:不是更快的管道,而是更少的管道。

觉得这有用吗? 👏 请鼓掌——这能帮助其他人发现它。

关注以获取 每周 Snowflake 工程深度解析、实用架构见解和技术速览。 ❄️

你可以使用、分享、改编并基于此作品进行构建。对于公开发布或大量改编,请保留署名,并包含指向原始文章或仓库的链接以及作者的 LinkedIn 个人资料。私人和内部使用无需署名。按“原样”提供,仅供教育目的。在生产环境中使用所有示例之前,请先验证和测试。观点仅代表我个人,不代表任何现任或前任雇主。

从 Kafka 依赖到直接摄取:使用 Snowpipe Streaming 的生产架构… 最初发表于 Snowflake Builders Blog: Data Engineers, App Developers, AI, & Data Science on Medium,人们正在那里通过高亮和回应这个故事来继续对话。

这篇内容对你有用吗?

反馈只用于改善内容筛选,不等同于收藏

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存