JasperReports สัตว์ประหลาดใต้พรม: แค่กดดาวน์โหลด PDF รายงาน ทำไม Server ดับไปทั้งเครื่อง?
⏱️ ใช้เวลาอ่านประมาณ: 4 นาที 30 วินาที
บ่ายวันสิ้นเดือน... ฝ่ายบัญชีกดปุ่ม "พิมพ์รายงานสรุปยอดขายประจำปี (PDF)"
ผ่านไป 15 วินาที หน้าเว็บยังนิ่งสนิท... ผ่านไป 30 วินาที พัดลมเครื่องเซิร์ฟเวอร์เริ่มหมุนดังสนั่น... และวินาทีที่ 45 ทั้งระบบล่มสลาย บริการอื่นตายเรียบ ลูกค้าทั่วประเทศใช้งานแอปไม่ได้!
เกิดอะไรขึ้น? ทำไมแค่สั่งเรนเดอร์เอกสารหน้ากระดาษ A4 ไม่กี่หน้า ถึงมีพลังทำลายล้างสูงกว่าโดนยิง DDoS Attack ซะอีก?
📄 เจ้าพ่อรายงานยุคหินที่ทุกคนหนีไม่พ้น
ในโลกของ Enterprise ซอฟต์แวร์ ถ้าโจทย์คือการออกใบแจ้งหนี้ สลิปเงินเดือน หรือรายงานตารางช่องไฟเป๊ะๆ แบบพิมพ์ลงกระดาษ A4 ไม่มีใครสู้ความเก๋าของ JasperReports ได้
เราใช้โปรแกรม Jaspersoft Studio ลากเส้น ตีกรอบ ออกแบบไฟล์
.jrxml กันอย่างเมามัน... แต่สิ่งที่ไม่ค่อยมีใครรู้คือ
กลไกการคำนวณเบื้องหลังมันไม่ได้เบาอย่างที่ตาเห็น
เวลา JasperReports จะสร้าง PDF ขึ้นมา 1 หน้า มันต้องทำสิ่งเหล่านี้ใน JVM Heap:
- สร้างโครงสร้าง Pixel-perfect Object Graph: เส้นทุกเส้น ข้อความทุกตัว กรอบทุกอัน ถูกแปลงเป็น Java Object ลอยอยู่ในหน่วยความจำ
- คำนวณ Font Metrics และพิกัด X/Y ในระดับจุด (Points)
- ประเมินสูตรตัวแปร รวมยอดสะสม (Variables & Aggregations) บรรทัดต่อบรรทัด
💣 กับดักหมื่นแถว: JasperPrint ยักษ์ใน Heap
ปัญหาไม่ได้เกิดตอนเทสต์ด้วยข้อมูล 10 แถว แต่เกิดตอน Production มีข้อมูล 100,000 แถว
JasperPrint print = JasperFillManager.fillReport(report, params, dataSource);
JasperExportManager.exportReportToPdf(print);
คำสั่ง fillReport ปกติจะถือข้อมูลของ
"ทั้งรายงานทุกหน้า" ค้างไว้ใน RAM
พร้อมกันทั้งหมดก่อนจะเริ่มแปลงเป็น PDF!
รายงานยอดขายหนา 800 หน้า จึงไม่ได้กินแรมแค่ขนาดไฟล์ตัวหนังสือ
แต่ถูกขยายร่างกลายเป็น Object ต้นไม้มหาศาลขนาด
1.5 GB ในหน่วยความจำ... ทันใดนั้น Garbage Collector
ก็ตกใจ วิ่งกวาดทั้งระบบจนเกิดปรากฏการณ์
Stop-the-World แล้วตบท้ายด้วย
OutOfMemoryError อย่างงดงาม
🛟 ท่ารอดตาย: Virtualizer ผ่อนส่งลง Disk
ทีมผู้สร้าง Jasper รู้ปัญหานี้ดี เลยใส่กลไกช่วยชีวิตที่ชื่อว่า
Virtualizer มาให้ (เช่น
JRSwapFileVirtualizer หรือ
JRFileVirtualizer)
"หลักการคือ: เก็บหน้าเอกสารไว้ใน RAM แค่ 50 หน้าพอ! หน้าไหนที่เรนเดอร์จัดหน้าเสร็จแล้ว ให้เตะ (Swap) ลงไปพักไว้เป็นไฟล์ชั่วคราวบน Harddisk ชั่วคราว พอจะรวมร่างเล่มจริงค่อยไปหยิบกลับมา"
ผลคือ จากรายงานที่เคยกิน RAM พุ่งทะลุเพดานจน Server ล่ม จะถูกคุมเพดานแรมไว้ให้นิ่งสนิท ไม่เกิน 100MB ตลอดการทำงาน แม้รายงานจะหนาเป็นพันหน้าก็ตาม!
💡 5-Min Takeaway
"งานแปลงเอกสารคือตัวกิน RAM ที่แฝงตัวเงียบที่สุดในระบบ Enterprise" อย่าประมาทด้วยการเทสต์แค่ข้อมูลไม่กี่แถวในเครื่อง Local สำหรับงานทำ Report ที่ไม่รู้ขอบเขตข้อมูลแน่นอน การตั้งค่า Virtualizer หรือแบ่ง Chunk ข้อมูลลง Disk คือเกราะป้องกันชีวิตเดียวที่จะทำให้เซิร์ฟเวอร์ไม่ตายในวันสิ้นเดือน