</>Học Dev
Bài học

Tuần 4 - Ngày 2: Glue Job Tuning và tối ưu hiệu năng

Tuần 4 – Ngày 2

Mục tiêu học tập

  • Chẩn đoán job chậm/OOM bằng metrics và Spark UI
  • Biết các đòn bẩy tuning: worker type/số lượng, partition, small files, skew
  • Xử lý small files và tối ưu ghi
  • Nắm checklist tối ưu chi phí Glue

1. Quan sát trước, tối ưu sau

Công cụ chẩn đoán

  • Job metrics (--enable-metrics): CPU/memory per executor, bytes read/written, data shuffle
  • Spark UI (--enable-spark-ui + S3 event logs): xem stage/task, thời gian, shuffle, skew — công cụ chính để tìm bottleneck
  • Continuous logging vào CloudWatch Logs
  • Glue job run insights: gợi ý lỗi và tuning tự động trong error message

Các triệu chứng kinh điển

Triệu chứngNguyên nhân thường gặpHướng xử lý
Job OOM (OutOfMemoryError) driverLiệt kê quá nhiều file nhỏ / collect về driverGom file, bỏ collect, dùng useS3ListImplementation
OOM executorPartition quá lớn, skew, cache thừaRepartition, salt key, tăng worker size (G.2X+)
1 task chạy mãi, còn lại xong sớmData skew (khóa lệch)Salt key, broadcast join bảng nhỏ, AQE (Spark 3 tự xử phần lớn)
Job chậm khi đọcHàng triệu small files; JSON/CSV chưa nén cộtCompaction; convert Parquet; push_down_predicate
Job chậm khi ghiQuá nhiều partition output nhỏrepartition/coalesce trước khi ghi

2. Đòn bẩy tuning chính

Chọn worker và số lượng

  • Tăng số worker khi job bị giới hạn song song (nhiều partition chờ xử lý)
  • Tăng cỡ worker (G.1X → G.2X/G.4X/G.8X) khi từng task cần nhiều memory (join lớn, aggregation nặng)
  • Auto Scaling (--enable-auto-scaling): Glue tự thêm/bớt executor theo giai đoạn job — tránh trả tiền worker ngồi không

Số partition Spark

  • Quy tắc thô: partition ~ 2-3× tổng số core; mỗi partition ~128MB dữ liệu
  • spark.sql.shuffle.partitions (mặc định 200) — chỉnh theo khối lượng shuffle
  • AQE (Adaptive Query Execution) — Spark 3 (Glue 3.0+) tự gộp partition nhỏ sau shuffle, tự xử skew join phần lớn trường hợp

Small files problem

Hàng triệu file KB trên S3 → driver liệt kê lâu, mỗi file một task bé, overhead khổng lồ:

  • Nguồn: gom từ upstream (Firehose buffer lớn hơn, Kinesis agg)
  • Trong job: đọc với groupFiles: inPartition + groupSize (gom nhiều file nhỏ vào một task đọc)
  • Định kỳ: compaction job (đọc → repartition → ghi lại file ~128MB-1GB); với Iceberg dùng OPTIMIZE ... REWRITE DATA (Athena) hoặc compaction tự động của S3 Tables

Join tuning

  • Broadcast join: bảng nhỏ (< vài trăm MB) phát cho mọi executor — tránh shuffle bảng lớn
  • Lọc sớm (predicate pushdown, chọn cột) trước khi join
  • Skew: salt key hoặc để AQE xử

3. Tối ưu chi phí Glue (checklist)

  1. Đúng loại job: Python shell cho việc nhỏ; Spark cho dữ liệu lớn
  2. Flex execution cho batch không SLA (-~34%)
  3. Auto Scaling thay vì fix max worker
  4. Bookmark + push_down_predicate: xử lý đúng phần dữ liệu cần
  5. Giảm dữ liệu đọc: Parquet + partition + compaction
  6. Đặt timeout hợp lý (mặc định 48h — job treo là đốt tiền)
  7. Interactive sessions cho dev (tính theo phút, idle timeout) thay vì chạy cả job để test
  8. Glue version mới nhất (5.0 nhanh hơn → ít DPU-hour hơn)

4. Ví dụ tình huống tổng hợp

Job Glue 10 G.1X chạy 3h, đọc 2M file JSON nhỏ (tổng 200GB) từ S3, join với bảng tham chiếu 50MB, ghi Parquet. Tối ưu?

Lời giải mẫu:

  1. Convert/gom nguồn: Firehose buffer to hơn hoặc compaction trước — hoặc đọc với groupFiles
  2. push_down_predicate nếu chỉ cần một phần partition
  3. Broadcast join bảng 50MB
  4. Ghi: coalesce về số file hợp lý (~200GB/512MB ≈ 400 file)
  5. Bật Auto Scaling + cân nhắc Flex nếu nightly batch → Thời gian giảm, DPU-hour giảm — cùng lúc "faster" và "cheaper".

Câu hỏi ôn tập

  1. Job fail Driver OutOfMemory khi đọc bucket chứa 5 triệu file nhỏ. Vì sao driver (không phải executor) chết, và xử lý?

    Xem đáp án

    Driver chịu trách nhiệm liệt kê file và lập kế hoạch task — 5 triệu object tạo metadata khổng lồ trong bộ nhớ driver. Xử lý: gom small files (compaction), đọc với groupFiles: inPartition/groupSize để Glue gom file khi plan, bật useS3ListImplementation để liệt kê theo lô, và giải quyết gốc rễ ở upstream (buffer Firehose lớn hơn).

  2. Một stage có 200 task: 199 task xong trong 1 phút, 1 task chạy 50 phút. Chuyện gì và cách xử lý?

    Xem đáp án

    Data skew: một khóa join/groupBy chiếm phần lớn dữ liệu dồn vào 1 partition. Xử lý: (1) AQE của Spark 3 (Glue 3.0+) bật sẵn xử skew join tự động phần lớn ca; (2) salt key — thêm hậu tố ngẫu nhiên chia khóa nóng thành nhiều khóa con; (3) broadcast join nếu một bảng nhỏ; (4) lọc bỏ khóa rác (null, default) gây skew trước khi join.

  3. Khi nào tăng số worker và khi nào đổi sang worker to hơn (G.2X/G.4X)?

    Xem đáp án

    Tăng số worker khi job song song hoá được nhưng thiếu slot (nhiều partition xếp hàng, CPU các executor bận đều). Worker to hơn khi từng task thiếu memory (OOM executor, spill to disk nhiều) — join/aggregation giữ nhiều dữ liệu trong RAM. Nhìn metrics: executor memory usage cao + spill → to hơn; CPU đều và queue dài → nhiều hơn.

  4. Cách gom small files khi GHI output trong Spark/Glue? So sánh repartition và coalesce.

    Xem đáp án

    Trước khi ghi, giảm số partition: coalesce(n) — gộp partition không shuffle, rẻ, chỉ giảm được số partition; repartition(n) — shuffle toàn bộ, đắt hơn nhưng chia lại đều (và tăng được số partition, partition theo cột). Ghi bảng partition theo cột: repartition(col) giúp mỗi partition output ra ít file to thay vì mỗi task ghi một mảnh vào mọi partition.

  5. Nêu 4 cách giảm chi phí một Glue job nightly đang chạy 20 DPU × 2h.

    Xem đáp án

    (1) Flex execution — nightly không SLA, giảm ~34% đơn giá; (2) Auto Scaling — job có giai đoạn nhẹ thì không giữ đủ 20 worker; (3) giảm dữ liệu xử lý: bookmark (incremental) + push_down_predicate + nguồn Parquet; (4) tuning để chạy nhanh hơn (broadcast join, gom small files) — DPU-hour = worker × giờ, nhanh hơn là rẻ hơn. Thêm: nâng Glue version mới, đặt timeout ngắn.

Bài tập thực hành

  • Bật --enable-spark-ui cho một job, mở Spark UI xem các stage và shuffle read/write
  • Thí nghiệm: job đọc 1000 file 100KB vs 10 file 10MB — so thời gian
  • Viết compaction job: đọc prefix nhiều file nhỏ → coalesce → ghi lại file ~256MB
  • Đọc Best practices for performance tuning AWS Glue for Apache Spark jobs

Tài liệu tham khảo chính thức


Tiếp theo: EMR và EMR Serverless