ข้ามไปเนื้อหาหลัก

หยุดดีบัก Spark บนเครื่องจริง: ทำไม Docker ถึงดีกว่า

ปัญหาดีพิวเดนซี PySpark ในเดือนตุลาคมทำระบบล่ม 4 ชั่วโมง เสียค่าคลาวด์ 12,000 ดอลลาร์ ทำไมคุณควรย้ายมาใช้คอนเทนเนอร์แทนเครื่องโฮสต์

เรียบเรียงโดย AI
Inewgen
15 Sep 2026ที่มา: Dev.to4 นาทีอ่าน (0 ครั้ง)
แชร์
หยุดดีบัก Spark บนเครื่องจริง: ทำไม Docker ถึงดีกว่า

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง

ขนาดตัวอักษร
  • การอัปเดต dependency ของ PySpark ทำระบบล่ม 4 ชั่วโมง เสียเงิน 12,000 ดอลลาร์
  • แนวทาง Host-Native ทำให้เกิดปัญหาเวอร์ชันไม่ตรงกับคลัสเตอร์และ Global Namespace
  • การใช้ Docker และ Docker Compose ช่วยจำลองสภาพแวดล้อมให้เหมือน EMR หรือ Databricks

เมื่อเดือนตุลาคมที่ผ่านมา การอัปเดต dependency เพียงเล็กน้อยในงาน PySpark ทำให้ระบบต้องหยุดทำงานนานถึง 4 ชั่วโมง และสูญเสียค่าใช้จ่ายด้านคลาวด์คอมพิวต์ไปประมาณ 12,000 ดอลลาร์ นักพัฒนาคนหนึ่งได้ทดสอบฟังก์ชัน User Defined Function (UDF) ใหม่ในเครื่องคอมพิวเตอร์ส่วนตัวโดยใช้ delta-spark เวอร์ชันเก่ากว่าที่รันบน EMR คลัสเตอร์จริง ในเครื่องโลคัลการซีเรียลไลฟ์ทำงานได้ปกติ แต่บนระบบโปรดักชัน ความแตกต่างของเวอร์ชัน Scala และ Java ในรันไทม์เบื้องหลังกลับทำให้เกิดข้อผิดพลาด java.io.NotSerializableException ซึ่งจะแสดงขึ้นมาก็ต่อเมื่อปริมาณข้อมูลถึงขีดจำกัดชัฟเฟิลที่กำหนดไว้เท่านั้น

เราต้องใช้เวลาหลายชั่วโมงในการไล่ดูล็อกและจ้องมองสแต็กทレースที่เข้าใจยากในขณะที่พอีปไลน์เกิดอาการแบ็กล็อก ผมจึงสาบานไว้ตรงนั้นเลยว่า หากสภาพแวดล้อมเครื่องของนักพัฒนาคนไหนไม่เหมือนกับคลัสเตอร์เป๊ะๆ จะไม่มีทางยอมให้ส่งโค้ดขึ้นระบบเด็ดขาด

4 ชม.เวลาดาวน์ไทม์จาก dependency
$12,000ค่าใช้จ่ายคลาวด์ที่เสียไป

คุณกำลังตัดสินใจระหว่างสองเส้นทาง คือการจมปลักอยู่ในนรกเครื่องฉันพิเศษที่ต้องคอยจัดการเวอร์ชัน Java, Scala และ Python บนเครื่อง หรือจะกัดฟันยอมคอนเทนเนอร์ไรซ์สภาพแวดล้อมการพัฒนา คุณอาจคิดว่าวิธีหลังนั้นเกินความจำเป็นและมีภาระในการตั้งค่ามากเกินไป แต่คุณคิดผิด ทางเลือกสำหรับนักพัฒนา Spark และ Delta Lake มีอยู่ 2 ทางหลัก ดังนี้

  • แนวทาง Host-Native: ติดตั้ง openjdk@11, python 3.9, spark 3.3.2 และ delta-spark 2.2.0 บนเครื่อง macOS หรือ Ubuntu โดยตรง ใช้ pyenv และ sdkman เพื่อเลียนแบบคลัสเตอร์
  • แนวทาง Containerized Replica: สร้าง Dockerfile ที่สะท้อนอิมเมจฐาน (เช่น amazoncorretto:11) และเมานต์โค้ดเข้าไป พร้อมใช้ docker-compose รัน MinIO เป็นที่เก็บข้อมูล S3 สำหรับ Delta tables

การทำความเข้าใจความต่างระหว่าง Host-Native และ Containerization ถือเป็นหัวใจสำคัญในวิศวกรรมข้อมูลสมัยใหม่ ปัญหาความเข้ากันได้ของเวอร์ชันไลบรารีระดับต่ำอย่าง Py4J หรือ Java Runtime มักไม่แสดงอาการในช่วงเทสต์โลคัลเนื่องจากข้อมูลมีขนาดเล็ก แต่จะระเบิดขึ้นเมื่อเจอข้อมูลมหาศาลบนระบบจริง การใช้ Docker จึงเป็นการตัดไฟตั้งแต่ต้นลมเรื่องความต่างของสภาพแวดล้อม

docker container terminal code workspace

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง

ไม่อยากพลาดข่าวใหม่?

สมัครรับสรุปข่าวสารใหม่ทางอีเมล ไม่บ่อยจนรำคาญ

โฆษณา

ในแนวทาง Host-Native ภาระการจัดการระบบจะมองไม่เห็นจนกว่าจะสายเกินไป คุณต้องเสียเวลา 30 นาทีทุกๆ ไม่กี่สัปดาห์เพื่อซิงค์เวอร์ชันในเครื่อง และสุดท้ายจะเจอปัญหาความไม่เข้ากันระหว่างแพ็กเกจ pyspark ในเครื่องกับสภาพแวดล้อม spark-submit จนเกิดความผิดพลาดแบบไม่แน่นอน ส่วนแนวทางคอนเทนเนอร์ ภาระจะไปกองอยู่ข้างหน้าตอนเริ่มต้น คุณใช้เวลาสองชั่วโมงเขียน Dockerfile ครั้งเดียว กำหนดค่า SPARK_HOME, HADOOP_CONF_DIR และ AWS_ACCESS_KEY_ID สำหรับ MinIOโลคัล จากนั้นเมื่อรัน docker-compose up คุณจะมั่นใจได้ว่าถ้ารันบนเครื่องตัวเองได้ มันก็จะรันบน EMR หรือ Databricks ได้เช่นกัน

หลายคนแย้งว่า Docker ทำให้วงจรการพัฒนาช้าลง ซึ่งมักจะเป็นการทำที่ผิดวิธี การสร้างอิมเมจ Docker ขนาด 2GB นั้นใช้เวลาจริง แต่คุณไม่ต้องสร้างอิมเมจใหม่ทุกครั้งที่แก้โค้ด 1 บรรทัด คุณสามารถเขียนไฟล์ docker-compose.yml ที่เมานต์ไดเรกทอรีซอร์สโค้ดเป็นโวลุมได้ เมื่อกดบันทึกใน IDE การเปลี่ยนแปลงจะสะท้อนเข้าไปในคอนเทนเนอร์ทันที

"If you're working on production financial or healthcare data, 'it works on my machine' is a fireable offense. Containerize it, or keep paying the bill when your pipeline dies at 3 AM."

ผู้เขียนบทความบน Dev.to

คำแนะนำของผมคือให้ใช้ Dockerfile แบบหลายขั้นตอน (multi-stage) ในขั้นตอนแรกให้ติดตั้ง dependency สำหรับบิลด์ และในขั้นตอนสุดท้ายให้ใช้ JRE แบบเพรียวบาง เช่น eclipse-temurin:11-jre-focal เพื่อควบคุมขนาดอิมเมจ ตั้งค่าตัวแปร DELTA_SPARK_VERSION และ SPARK_VERSION เป็นอาร์กิวเมนต์บิลด์ (ARG) เมื่อทีมแพลตฟอร์มอัปเดตคลัสเตอร์โปรดักชัน คุณก็แค่เปลี่ยนสองบรรทัดในไฟล์ .env แล้วรัน docker-compose build --no-cache ก็เสร็จสิ้น

ที่มา: Dev.to

ความคิดเห็น

แสดงความคิดเห็น
0/2000

พบข้อมูลผิดพลาดในบทความนี้? แจ้งปัญหาบทความนี้