Phần 5: Vận hành, checkpoint, và scaling Flink trong Spring Boot

Henry CollinsHenry Collins
8 min read

Dưới đây là Phần 5 của loạt bài “Chạy Apache Flink embedded trong Spring Boot” (bối cảnh e-commerce). Ở phần này, chúng ta sẽ tập trung vào vận hành (deployment), checkpoint, savepoint, và scaling. Bài viết sẽ được viết với giả định rằng bạn chưa từng sử dụng Flink trước đây, nên mình sẽ cố gắng giải thích đầy đủ các khái niệm cùng với hướng dẫn thực hành.


Khi bạn đã hoàn thiện pipeline (đọc dữ liệu, xử lý – join, ghi kết quả), bước vận hành là để:

  1. Đảm bảo job Flink chạy ổn địnhliên tục.

  2. Quản lý state trong trường hợp job bị dừng đột ngột (do sự cố) hoặc cần nâng cấp.

  3. Theo dõi hiệu năng, log, và tài nguyên để scale khi lưu lượng tăng/giảm.

Đây là những việc làm thường xuyên của một DevOps/SRE/Senior Developer trong bối cảnh real-time streaming.


2.1 Stateful streaming là gì?

Trong Flink, pipeline của bạn có thể giữ “state” – ví dụ: bộ đệm tạm, kết quả tính toán dở dang, hay “nhớ” các record đã tới trước đó. Dạng stateful này cho phép:

  • Windowed operations (tính toán theo cửa sổ thời gian).

  • Aggregation, JOIN phức tạp (đi qua nhiều record).

  • Exactly-once semantics khi dùng với Kafka + checkpoint.

Nếu job chỉ “đọc – transform – ghi” một cách đơn giản, có thể ít state. Nhưng ngay cả interval join (như phần 4) cũng có state tạm để ghép cặp (order – shipping). Vì thế, bảo vệ state khỏi mất mát khi job bị crash hoặc muốn nâng cấp là cực kỳ quan trọng.

2.2 Checkpoint

Checkpoint là cơ chế Flink tự động snapshot state của job tại các thời điểm định kỳ (theo interval). Mục đích:

  • Khi job bị crash, ta có thể khôi phục (restore) từ checkpoint gần nhất → không mất progress.

  • Checkpoint diễn ra thường xuyên (ví dụ mỗi 60 giây, 300 giây, …).

Thao tác:

  1. Mỗi khi đến checkpoint interval (ví dụ 60s), Flink yêu cầu tất cả operator (bao gồm source, transformation, sink) flush state** ra nơi lưu trữ (memory, file, S3,...).

  2. Kafka (nếu được cấu hình) sẽ chèn offset vào checkpoint → Khi restore, job biết “đọc tiếp” từ offset nào để không trùng hoặc mất dữ liệu.

2.3 Savepoint

Savepoint là một snapshot có chủ đích (manual). Thường dùng để:

  • Nâng cấp job hoặc deploy phiên bản mới mà vẫn giữ state cũ.

  • Di chuyển job sang một cluster khác (hoặc môi trường khác).

Khác checkpoint (tự động), savepoint được tạo thủ công bằng lệnh (Flink CLI hoặc API). Savepoint thường không bị xóa tự động như checkpoint, ta cất giữ nó an toàn (S3, HDFS, …) để khôi phục sau.

Trong mô hình embedded:

  • Bạn không có Flink CLI “chuẩn” như kiểu flink savepoint <jobId> ....

  • Bạn có thể gọi Flink REST API hoặc Java API (từ code) để tạo savepoint, nhưng cấu hình sẽ phức tạp hơn.

  • Thông thường, mô hình embedded áp dụng checkpoint “đơn giản” để tránh mất data, còn savepoint nâng cao ít được dùng (trừ khi bạn xây hẳn logic custom).


3. Thiết lập checkpoint trong Spring Boot (embedded)

3.1 Cấu hình checkpoint

Như đã đề cập ở Phần 2, bạn có thể cấu hình trong FlinkConfig (lớp @Configuration):

@Bean
public StreamExecutionEnvironment streamExecutionEnvironment() {
    final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    // Kích hoạt checkpoint, ví dụ mỗi 60 giây
    env.enableCheckpointing(60_000);

    // Chỉ định nơi lưu checkpoint (cục bộ hoặc S3/HDFS)
    // Ở dev, ta dùng file://, production có thể dùng s3://
    env.getCheckpointConfig().setCheckpointStorage("file:///tmp/flink-checkpoints");

    // Tùy chọn: set mode EXACTLY_ONCE, AT_LEAST_ONCE
    // env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);

    // Tùy chọn: min pause between checkpoints, ... 
    // env.getCheckpointConfig().setMinPauseBetweenCheckpoints(30000);  // 30 giây
    // env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);       // 1 checkpoint 1 lúc

    return env;
}

Giải thích:

  • setCheckpointStorage("file:///tmp/flink-checkpoints"): Tạm để local. Trong môi trường production, bạn dùng S3 ("s3://my-bucket/flink-checkpoints") hoặc HDFS.

  • env.enableCheckpointing(60000): Kích hoạt checkpoint, 1 phút/lần.

3.2 Kiểm tra checkpoint

Khi job chạy, Flink sẽ định kỳ ghi ra checkpoint. Nếu job crash, khi job restart, Flink sẽ đọc checkpoint để restore state. Ở mô hình embedded:

  • Nếu bạn stop rồi start lại Spring Boot mà không thay đổi code, env vẫn trỏ về cùng checkpoint storage, Flink có thể tự khôi phục.

  • Nếu code thay đổi (chẳng hạn schema state thay đổi), đôi khi Flink không restore được – cần “migrate state” phức tạp hơn.


4. Docker và Kubernetes – Triển khai mô hình embedded

Thông thường, bạn đóng gói Spring Boot thành 1 “fat JAR” (hoặc “uber JAR”), rồi viết Dockerfile:

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app

COPY target/spring-flink-embedded-0.0.1-SNAPSHOT.jar app.jar

CMD ["java", "-jar", "app.jar"]
  • Build image: docker build -t myorg/spring-flink-embedded .

  • Chạy container: docker run -p 8080:8080 myorg/spring-flink-embedded

Lúc này, Flink (embedded) + Kafka connectors + MongoDB connectors đều nằm trong file JAR. Job sẽ tự chạy khi container start.

4.2 Chạy trên Kubernetes

  • Tạo file Deployment cho container, struct tương tự:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-flink-embedded-deployment
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: spring-flink-embedded
        template:
          metadata:
            labels:
              app: spring-flink-embedded
          spec:
            containers:
            - name: spring-flink
              image: myorg/spring-flink-embedded:latest
              ports:
              - containerPort: 8080
    
  • Triển khai: kubectl apply -f deployment.yaml.

  • Mô hình này vẫn là “đơn replica” (1 pod). Nếu scale lên replicas: 2, mỗi pod đều chạy cùng 1 job => Dữ liệu bị xử lý “trùng” hoặc “đụng” state.

  • Cảnh báo: Ở mô hình cluster Flink “chuẩn”, bạn có JobManager, TaskManagers, scale-out mượt mà. Ở đây, mỗi podmột Flink local → state + offsets + checkpoint riêng biệt. Dễ dẫn đến race condition hoặc duplicate dữ liệu.


5. Scaling trong mô hình embedded

5.1 Vấn đề “mỗi replica một job”

Khi bạn scale Spring Boot, container/pod thứ 2 lên, pipeline Flink cũng khởi chạy → cùng đọc topic Kafka, xử lý trùng. Muốn tránh trùng, bạn cần:

  • Dùng partition + Kafka Consumer Group – Mỗi instance “giữ” 1 subset partition.

  • Đồng bộ state: Mô hình embedded không có JobManager chung → không đơn giản.

Kết luận: Mô hình embedded không lý tưởng để scale kiểu distributed streaming cỡ lớn. Nó phù hợp:

  • Pipeline xử lý nhỏ/gọn.

  • Tải (throughput) thấp-vừa.

  • Muốn nhanh gọn, POC.

Nếu bạn cần handle hàng triệu record/giây, scale out, high availability, … → Chuyển sang Flink cluster chính thức.


6. Giám sát & quản trị job

6.1 Xem log, metrics

  • Log: Spring Boot + Flink đều ghi chung 1 log container. Tìm message “checkpoint completed” hay “watermark advanced”…

  • Metrics: Flink cung cấp metric (numRecordsIn, numRecordsOut, checkpoint size, …). Mặc định embedded không có UI như Flink cluster. Bạn có thể cấu hình env.getConfig().setAutoWatermarkInterval(...) hay plugin metrics (Prometheus, JMX).

6.2 Dừng job, nâng cấp version

  • env.execute() (hoặc stmtSet.execute()) ở chế độ streaming sẽ block vô thời hạn.

  • Muốn dừng job, bạn phải kill Spring Boot.

  • Nâng cấp version:

    1. Tạo savepoint (nếu có logic custom).

    2. Triển khai version mới.

    3. Khôi phục state từ savepoint.

Trong thực tế, mô hình embedded thường “stop – start” mất state (trừ phi cài checkpoint + job restore). Tính “rolling upgrade” của Flink cluster không áp dụng 1:1 được ở đây.


7. Một số best practices cho mô hình embedded

  1. Quản lý version library: Dễ bị xung đột giữa dependency Spring Boot – Flink – Kafka. Hãy lock version cẩn thận.

  2. Giữ pipeline đơn giản: Tránh “quá nhiều stateful operations” hay “phân mảnh partition phức tạp”.

  3. Thử Flink cluster khi scale > 2-3 pods hoặc khi throughput lớn.

  4. Checkpoint ra một storage chung (S3, NFS) để có thể restore khi job restart.

  5. Giám sát cẩn thận memory usage, GC logs. Flink + Spring Boot chung 1 JVM → Dễ OOM nếu data spike.


  1. Lưu lượng rất cao (hàng trăm nghìn – hàng triệu msg/s).

  2. Yêu cầu HA (high availability) – job không bao giờ dừng khi node crash.

  3. Cần dễ dàng scale-out “theo chiều ngang” (thêm TaskManagers).

  4. Muốn dùng giao diện Flink UI, Flink CLI, REST API “chính thống” để quản trị, xem checkpoint/savepoint, v.v.

  5. Pipeline nhiều operator stateful, join phức tạp, … => Mô hình embedded dễ “rắc rối”.

Tóm lại, embedded Flink + Spring Boot phù hợp cho:

  • POC, demo, dự án nhỏ.

  • Xử lý real-time cơ bản, throughput thấp hoặc trung bình.

  • Muốn viết code nhanh, gói gọn, thay vì quản lý cả một Flink cluster.

Nếu yêu cầu khắt khe hơn, bạn nên chuyển sang Flink cluster (Standalone, Kubernetes Operator, Yarn, …).


9. Tóm tắt “bức tranh” 5 phần

Qua 5 phần của loạt bài, ta đã đi từ:

  1. Phần 1: Giới thiệu bối cảnh e-commerce, các topic Kafka (order_events, shipping_events), và việc chọn “embedded Flink trong Spring Boot”.

  2. Phần 2: Cấu hình dự án Spring Boot, thêm dependency, khởi tạo StreamExecutionEnvironment làm Bean, tổ chức code.

  3. Phần 3: Đọc dữ liệu từ Kafka, parse JSON, chuyển thành Table.

  4. Phần 4: JOIN hai bảng theo order_id, dùng interval join và ghi kết quả sang MongoDB (chế độ upsert).

  5. Phần 5: Quản lý checkpoint, savepoint, xem xét Docker/Kubernetes deployment, scaling, và best practices để vận hành job Flink embedded.

Kết luận: Bạn đã nắm được toàn bộ quy trình phát triển một job Flink “nhúng” trong Spring Boot – từ thiết lập môi trường, viết code pipeline, tới chạy & vận hành cơ bản. Đây là nền tảng để bạn có thể tự tinh chỉnh hoặc mở rộng logic (thêm window, agregation phức tạp, filter data, …). Và quan trọng nhất, bạn hiểu ưu – nhược điểm của mô hình embedded, để quyết định khi nào nên chuyển sang Flink cluster.


Lời cuối

Hy vọng loạt bài này giúp bạn:

  • Tiếp cận Apache Flink một cách trực quan qua ví dụ e-commerce.

  • Thấy được cách “embed” Flink trong Spring Boot, tận dụng thế mạnh DI, config, REST endpoints.

  • Nắm rõ checkpoint, savepoint, scaling, cùng những lưu ý khi deploy production.

Chúc bạn thành công trong việc xây dựng và vận hành các pipeline streaming real-time với Apache Flink (dù là embedded hay cluster)!

0
Subscribe to my newsletter

Read articles from Henry Collins directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Henry Collins
Henry Collins