iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
AI & Data

「知其然,更知其所以然:什麼是 Real-time (Streaming) Pipeline?從造輪子到 Flink 與 RisingWave」系列 第 19

【知其然,更知其所以然】Day19:現實的考量 - 擁抱開源生態

  • 分享至 

  • xImage
  •  

經過 18 天的努力,我們從零開始打造了一個功能相當完整的流式處理框架 SimpleStream:

基礎功能:Filter、GroupBy
高級特性:時間窗口、狀態管理、流式 Join
易用性:SQL 轉換、鏈式 API
教學價值:每個概念都深入解釋原理

但是,當我們準備把它用在生產環境時,現實給了我們一記響亮的耳光。

「老闆問我們什麼時候能上線,我卻連監控都沒有...」
「數據量一大,單機就撐不住了,分散式怎麼搞?」

SimpleStream 的生產環境缺口

缺口 1:監控與可觀測性

# 我們現在的狀況
orders_df.group_by("customer_id").count()

# 生產環境需要知道的事情
- 處理延遲:事件從進入到輸出花了多少時間?
- 吞吐量:每秒處理多少事件?
- 錯誤率:有多少事件處理失敗?
- 資源使用:CPU、內存、網絡使用情況?
- 業務指標:聚合結果的分佈和異常情況?

現實問題

  • 沒有 metrics 收集
  • 沒有 tracing 追蹤
  • 沒有健康檢查
  • 沒有告警機制

簡單解決方案

  • 整合 Prometheus + Grafana 做監控
  • 加入 OpenTelemetry 做鏈路追蹤
  • 提供 /health 端點和心跳檢查
  • 設置 alertmanager 告警規則

缺口 2:分散式處理能力

# 單機限制
- CPU:單機 CPU 核心數有限
- 內存:大狀態無法全部放在內存
- 網絡:單機網絡帶寬有瓶頸
- 存儲:單機磁盤容量和 I/O 有限

# 分散式需求
- 任務分片:如何將計算分散到多台機器?
- 負載均衡:如何保證各機器負載相對均衡?
- 狀態分佈:如何在多機器間分佈和同步狀態?
- 故障轉移:某台機器掛了,任務如何轉移?

簡單解決方案

  • 使用 Kafka 分區做天然的數據分片:Kafka 本身就支持分區,每個分區的數據會自動分散到不同機器上
  • 部署多個 SimpleStream 實例:啟動 3 台機器,每台跑一個 SimpleStream 程序,分別處理 partition-0、partition-1、partition-2
  • 用 Consul/etcd 做服務發現:讓各個實例知道彼此的存在和健康狀態,就像通訊錄一樣
  • 實現簡單的 leader election:多個實例中選一個當老大,負責協調工作分配
  • 分散式資料交換 (Shuffle):當需要按 customer_id 分組時,不同機器間要交換數據,確保相同 customer_id 的數據聚集到同一台機器
  • 分散式執行計劃:複雜查詢拆成多步驟:第一步各機器做 filter,第二步交換數據做 group_by,第三步做聚合

聽起來很簡單?但實際實現每一項都是巨大的工程挑戰。光是 shuffle 機制就涉及網絡通信、數據序列化、錯誤重試、背壓控制等複雜問題。

成熟開源方案的優勢

Apache Flink:流處理的工業標準

// Flink 的強大能力
public class WindowWordCount {

    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        DataStream<Tuple2<String, Integer>> dataStream = env
                .socketTextStream("localhost", 9999)
                .flatMap(new Splitter())
                .keyBy(value -> value.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .sum(1);

        dataStream.print();

        env.execute("Window WordCount");
    }

    public static class Splitter implements FlatMapFunction<String, Tuple2<String, Integer>> {
        @Override
        public void flatMap(String sentence, Collector<Tuple2<String, Integer>> out) throws Exception {
            for (String word: sentence.split(" ")) {
                out.collect(new Tuple2<String, Integer>(word, 1));
            }
        }
    }

}

Flink 給你什麼

  • 完整的分散式架構:JobManager、TaskManager、自動分片
  • 豐富的監控體系:Web UI、Metrics、REST API
  • 強一致性保證:Exactly-once、Checkpointing、State Backend
  • 成熟的生態系統:Kafka、Hadoop、Elasticsearch 整合
  • 活躍的社群:大量文檔、案例、最佳實踐

Apache Spark Streaming:批流統一

// Spark Streaming 的便利性
from pyspark import SparkContext
from pyspark.streaming import StreamingContext

# Create a local StreamingContext with two working thread and batch interval of 1 second
sc = SparkContext("local[2]", "NetworkWordCount")
ssc = StreamingContext(sc, 1)

# Create a DStream that will connect to hostname:port, like localhost:9999
lines = ssc.socketTextStream("localhost", 9999)

# Split each line into words
words = lines.flatMap(lambda line: line.split(" "))

# Count each word in each batch
pairs = words.map(lambda word: (word, 1))
wordCounts = pairs.reduceByKey(lambda x, y: x + y)

# Print the first ten elements of each RDD generated in this DStream to the console
wordCounts.pprint()

ssc.start()             # Start the computation
ssc.awaitTermination()  # Wait for the computation to terminate

Spark 的優勢

  • 批流統一:同一套 API 處理批數據和流數據
  • SQL 支援:直接用 SQL 寫流處理邏輯
  • 機器學習整合:MLlib 無縫整合
  • 大數據生態:與 Hadoop 生態完美整合

總結

經過 19 天的探索,我們深入理解了流式處理的核心原理,也認清了自己造輪子在生產環境的局限性。

知其然,更知其所以然的價值

知其然:我們知道流式處理「是什麼」

  • 事件驅動的數據處理模式
  • 時間窗口、狀態管理、流式 Join 等概念
  • Filter、GroupBy、Aggregate 等基本算子

更知其所以然:我們理解了流式處理「為什麼這樣設計」

  • 為什麼需要 Checkpoint?因為內存狀態在程序重啟後會丟失,流處理需要一個基準點去恢復運作
  • 為什麼需要 Backpressure?因為上下游處理速度不匹配會導致系統崩潰
  • 為什麼分散式處理這麼複雂?因為涉及數據分片、故障轉移、狀態同步等諸多挑戰

這種深度理解的價值在於:

  1. 架構決策更明智:知道每種方案的適用場景和限制
  2. 故障排查更高效:理解底層原理,能快速定位問題根因
  3. 性能調優更精準:知道瓶頸在哪裡,如何針對性優化
  4. 技術選型更準確:理解不同方案的本質差異,而非僅看表面功能

從學習到實踐的平衡

造輪子的價值在於學習和理解,但在時間壓力和實用性考量下,選擇成熟的開源方案往往是更明智的決定。
當你在使用 Flink 時遇到性能問題,因為你理解了 Checkpoint 的原理,你知道可能是檢查點間隔設置不當。
技術選型沒有標準答案,重點是根據團隊能力、業務需求、時間壓力找到最適合的平衡點。

Day 20 預告:Flink 的崛起

既然我們認清了開源方案的必要性,下一章我們要深入了解流處理領域的王者:Apache Flink。

什麼是真正的流式處理?為什麼 Flink 能以 record-by-record processing 的理念脫穎而出,成為業界標準?

從 SimpleStream 的學習基礎,進入 Flink 的工業實踐,看看真正的生產級流處理是什麼樣子。
我們會快速的解釋 Flink 常見的組件與概念,然後進入筆者實務分享的部分,敬請期待。


上一篇
【知其然,更知其所以然】Day18:從 DataFrame 到支援 SQL 語法
系列文
「知其然,更知其所以然:什麼是 Real-time (Streaming) Pipeline?從造輪子到 Flink 與 RisingWave」19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言