คำถามสัมภาษณ์ PySpark
โดย Aaron Cao · อัปเดตเมื่อ

การสัมภาษณ์ PySpark เน้นไปที่ execution model และ performance เป็นหลัก คุณควรอธิบายความแตกต่างระหว่าง transformation กับ action ระบุได้ว่าการทำงานใดที่ทำให้เกิด shuffle เลือกใช้ broadcast join ได้อย่างเหมาะสม วินิจฉัย data skew ได้ อธิบายเหตุผลของการทำ caching และบอกได้ว่าจะปรับจูน job ที่หน่วยความจำหมดอย่างไร
ผู้สัมภาษณ์ถามอะไรเกี่ยวกับ execution model บ้าง
ต่อให้คุณเขียนโค้ด PySpark ที่ทำงานได้จริง ก็ยังอาจสะดุดกับคำถามกลุ่มนี้ เพราะคำถามเหล่านี้ถามถึงสิ่งที่เอนจินทำ ไม่ใช่สิ่งที่โค้ดของคุณเขียนไว้ ผู้สัมภาษณ์มักเริ่มด้วยคำถามกลุ่มนี้เพราะมันแยกคนที่เคยปรับจูน job มาแล้วออกจากคนที่เพิ่งรันแค่ครั้งเดียวได้ชัดเจน ส่วนนี้ครอบคลุมคำถามเกี่ยวกับ execution model และสิ่งที่คำตอบฉบับสมบูรณ์ควรมี
- Transformation กับ action ต่างกันอย่างไร Transformation จะสร้าง plan และคืนค่า DataFrame ใหม่แบบ lazy ส่วน action อย่าง
count,collectหรือการเขียนข้อมูลจะเป็นตัวสั่งให้เกิดการประมวลผลจริง จะไม่มีอะไรถูกคำนวณจนกว่า action จะร้องขอผลลัพธ์ - ทำไม lazy evaluation ถึงมีประโยชน์ Optimizer จะเห็นลำดับการทำงานทั้งหมดก่อนที่จะรันจริง จึงสามารถจัดลำดับ filter ใหม่ ตัดคอลัมน์ที่ไม่จำเป็นออก และรวมขั้นตอนต่าง ๆ เข้าด้วยกันได้
- Narrow transformation หรือ wide transformation การทำงานแบบ narrow อย่าง
filterและselectจะทำให้แต่ละ output partition ขึ้นอยู่กับ input partition เพียงหนึ่งเดียว ส่วนการทำงานแบบ wide อย่างgroupBy,joinและdistinctจะกระจายข้อมูลใหม่ข้าม partition ซึ่งนั่นคือ shuffle - Shuffle คืออะไรและสำคัญอย่างไร ข้อมูลจะเดินทางผ่านเครือข่ายและถูกเขียนลงดิสก์ ทำให้เกิดขอบเขตของ stage ขึ้น โดยปกติแล้วนี่คือส่วนที่มีต้นทุนสูงที่สุดในการทำงานของ job
- อธิบาย job, stage และ task Action จะเป็นตัวเริ่ม job ขอบเขตของ shuffle จะแบ่ง job ออกเป็น stage และแต่ละ stage จะรันหนึ่ง task ต่อหนึ่ง partition
- RDD, DataFrame หรือ Dataset ควรเลือกใช้ DataFrame เป็นหลัก เพราะได้รับประโยชน์จาก Catalyst optimizer และการประมวลผลแบบ columnar RDD ยังคงมีประโยชน์เมื่อต้องการควบคุมระดับ low-level ส่วน Dataset ที่มี type เป็นแนวคิดของ JVM ดังนั้นคำตอบที่ตรงไปตรงมาในฝั่ง Python คือมันไม่สามารถใช้ได้
พูดคำว่า shuffle และ stage ออกมาเมื่อมันควรอยู่ในคำตอบจริง ๆ ผู้สัมภาษณ์ใช้คำเหล่านี้เป็นทางลัดเพื่อดูว่าคุณเคยเปิดดู Spark UI จริงหรือไม่
ควรตอบคำถามเรื่อง performance อย่างไร
การสัมภาษณ์ PySpark ระดับ senior ส่วนใหญ่คือการสัมภาษณ์เรื่อง performance โดยแท้จริง คำถามมักมาในรูปแบบสถานการณ์มากกว่าคำจำกัดความ
- Join ทำงานช้า คุณจะตรวจสอบอะไรก่อน ตรวจสอบขนาดข้อมูลทั้งสองฝั่งก่อน ถ้าฝั่งใดฝั่งหนึ่งใส่ลงใน memory ของ executor ได้ ให้ broadcast แล้วข้าม shuffle ไปเลย ถ้าไม่พอดี ให้ดู partitioning และ skew ก่อนที่จะไปแตะขนาดของคลัสเตอร์
- Data skew คืออะไรและแก้ไขอย่างไร มีเพียงไม่กี่ key ที่ถือแถวข้อมูลส่วนใหญ่เอาไว้ จึงทำให้มี task หนึ่งที่รันนานกว่า task อื่น ๆ ที่เสร็จไปแล้ว วิธีแก้ไขได้แก่ การทำ salting ให้กับ hot key การ broadcast ฝั่งที่มีขนาดเล็กกว่า หรือการกรอง null ที่ถูก hash ไปตกอยู่จุดเดียวกันหมดออก สัญญาณในการวินิจฉัยคือความแตกต่างของระยะเวลาในการรัน task ที่เห็นได้ใน Spark UI
- ควรใช้ cache หรือ persist เมื่อไหร่ ควรใช้เมื่อ DataFrame ถูกนำกลับมาใช้ซ้ำในหลาย action และการคำนวณใหม่จะมีต้นทุนสูง การ cache สิ่งที่ใช้แค่ครั้งเดียวเป็นการสิ้นเปลือง memory และการ unpersist ให้ทันเวลาก็สำคัญใน job ที่รันนาน
- repartition หรือ coalesce repartition จะทำให้เกิด shuffle และสามารถเพิ่มหรือลดจำนวน partition ได้อย่างสม่ำเสมอ ส่วน coalesce จะรวม partition โดยไม่ต้องทำ shuffle เต็มรูปแบบ ซึ่งเป็นวิธีที่ประหยัดกว่าในการลดจำนวนไฟล์ผลลัพธ์
- ทำไมควรหลีกเลี่ยง Python UDF แถวข้อมูลต้องผ่านการ serialize ระหว่าง JVM กับโปรเซส Python และ optimizer มองไม่เห็นสิ่งที่อยู่ภายในฟังก์ชัน ควรเลือกใช้ฟังก์ชันในตัวก่อน และหันไปใช้ vectorized UDF ก็ต่อเมื่อไม่มีฟังก์ชันในตัวที่ทำงานแบบเดียวกันได้
- ทำไม
collectถึงอันตราย มันจะดึงผลลัพธ์ทั้งหมดมาไว้ที่ driver และอาจทำให้ memory ของ driver หมดได้ - Job ล้มเหลวเพราะ memory หมด คุณจะตรวจสอบตามลำดับใด ตรวจก่อนว่าเป็น driver หรือ executor จากนั้นดู skew ต่อด้วยขนาดของ partition และสุดท้ายคือการตั้งค่า memory การเพิ่ม memory เป็นขั้นตอนแรกคือคำตอบที่บ่งบอกถึงประสบการณ์ที่ยังไม่มากพอ
มี data engineer คนหนึ่งที่กำลังสัมภาษณ์เข้าทีม platform ถูกถามว่าทำไม job ที่รันตอนกลางคืนซึ่งทำงานมาแล้วหนึ่งปีถึงใช้เวลาสี่ชั่วโมงขึ้นมาทันที คำตอบที่ทำให้ผ่านไม่ใช่การเปลี่ยนค่า configuration แต่เป็นเพราะพาร์ตเนอร์ต้นทางรายหนึ่งเริ่มส่งค่า null มาใน join key ทำให้ทุกแถวที่เป็น null ถูก hash ไปอยู่ที่ partition เดียวกันหมด ผู้สัมภาษณ์ให้คะแนนกับลำดับการคิดแบบนี้คือดูข้อมูลก่อนดูคลัสเตอร์
คลังคำถามที่เกี่ยวข้องแยกตามตำแหน่งงานอยู่ที่ คำถามสัมภาษณ์แยกตามตำแหน่งงาน
มีคำถามเชิงปฏิบัติและเรื่องการจัดการข้อมูลอะไรบ้าง
คำถามที่เหลือจะตรวจสอบว่าคุณเคยทำ pipeline ขึ้นใช้งานจริงหรือไม่ ไม่ใช่แค่ทำ tutorial จบเท่านั้น
- อ่านข้อมูลอย่างมีประสิทธิภาพได้อย่างไร ใช้ฟอร์แมตแบบ columnar อย่าง Parquet, ทำ partition pruning บนคอลัมน์ที่ใช้ filter และ predicate pushdown อธิบายได้ว่าทำไมการอ่านข้อมูลจำนวนไบต์ให้น้อยลงถึงคุ้มค่ากว่าการไปปรับปรุงขั้นตอนที่เกิดขึ้นภายหลัง
- ทำไมควรกำหนด schema เองแทนการปล่อยให้ระบบเดา การให้ระบบเดา schema ต้องเสียเวลาสแกนข้อมูลเพิ่มอีกรอบ และอาจเดาชนิดข้อมูลไม่ตรงกันในแต่ละครั้งที่รัน
- จัดการกับ null และข้อมูลซ้ำอย่างไร ฟังก์ชันที่เกี่ยวข้อง พร้อมกับประเด็นที่ว่า join key ที่มี null เยอะจะทำให้เกิด skew
- Window function ใช้ทำอะไร ใช้สำหรับการจัดอันดับ, การคำนวณผลรวมสะสม และการตัดข้อมูลซ้ำให้เหลือแถวล่าสุดต่อหนึ่ง key ซึ่งเป็นงานที่พบได้บ่อยมากใน pipeline
- เขียนผลลัพธ์ออกมาโดยไม่ให้ได้ไฟล์เล็ก ๆ เป็นพัน ๆ ไฟล์ได้อย่างไร ทำ coalesce หรือ repartition ก่อนเขียนข้อมูล และแบ่ง partition ผลลัพธ์ตามคอลัมน์ที่มี cardinality เหมาะสม
- ทดสอบโค้ด PySpark อย่างไร ใช้ session ท้องถิ่นขนาดเล็กร่วมกับ fixture DataFrame และแยก business logic ออกมาเป็นฟังก์ชันที่รับและคืนค่า DataFrame
- ส่งและตั้งค่า job อย่างไร จำนวน executor, จำนวน core และ memory พร้อมเหตุผลว่าทำไมทั้ง executor ขนาดเล็กที่มากเกินไปและ executor ขนาดใหญ่ที่น้อยเกินไปต่างก็สิ้นเปลืองทรัพยากรเหมือนกัน
ควรฝึกซ้อมอย่างไรก่อนสัมภาษณ์
คำตอบเรื่อง PySpark มักล้มเหลวตอนพูดออกมาจริงในแบบที่สังเกตได้ชัด ผู้สมัครรู้ว่า shuffle มีต้นทุนสูง แต่บอกไม่ได้ว่าการทำงานใดที่ทำให้เกิด shuffle คำตอบจึงกลายเป็นแค่รายการคำคุณศัพท์ การอ่านคลังคำถามทำให้เกิดความรู้สึกคุ้นเคย และความคุ้นเคยนั้นไม่เหมือนกับการอธิบายให้คนที่กำลังรออยู่ฟัง
เลือก pipeline หนึ่งที่คุณเคยสร้างขึ้นมา แล้วเล่าให้ฟังตั้งแต่ต้นจนจบ ทั้งขั้นตอนการอ่านข้อมูล transformation ทุกขั้นตอน ขอบเขตของ stage อยู่ตรงไหน และสิ่งแรกที่คุณจะตรวจสอบถ้ามันช้าลง พูดออกมาดัง ๆ จนกว่าคุณจะไม่ต้องเริ่มพูดใหม่อีก การฝึกตอบคำถามเหล่านี้กับ AI interviewer ที่ถามคำถามต่อเนื่องนั้นใกล้เคียงกับการสัมภาษณ์จริงมากกว่าการอ่านโน้ตซ้ำ ๆ และนั่นคือเหตุผลที่โหมด mock interview ถูกสร้างขึ้นมา
Aaron Cao ผู้ก่อตั้ง SubcueAI สร้างการฝึกซ้อมโดยเน้นไปที่ช่องว่างในการพูดตรงนี้ แทนที่จะเน้นแค่การเพิ่มจำนวนคำถาม ในการสัมภาษณ์จริง แอปเดสก์ท็อปและ Side Panel ของส่วนขยายเบราว์เซอร์สามารถแสดงโครงสร้างขึ้นมาได้ในขณะที่ผู้สัมภาษณ์กำลังพูดอยู่ ซึ่งช่วยได้มากที่สุดกับเนื้อหาที่คุณฝึกซ้อมมาแล้ว การตั้งค่าใช้เวลาเพียงไม่กี่นาทีและมีรายละเอียดอยู่ในหน้า tutorial