การแคชข้อมูลนั้นเป็นหนึ่งในวิธีช่วยลดโหลดของเว็บได้อย่างมีประสิทธิภาพ เวิร์ดเพรสเองแม้จะมีปลั๊กอินสำหรับจัดการแคชอยู่มากมายหลายตัว เช่น WP Super Cache หรือ WP Fastest Cache แต่การแคชข้อมูลต่างๆ ด้วยตัวเองก็ยังคงเป็นหนึ่งในวิธีการปรับปรุงประสิทธิภาพที่ได้ผลอยู่ดี
จริงๆ เวิร์ดเพรสมีวิธีการแคชข้อมูลอยู่หลายวิธีมาก และแต่ละวิธีก็เหมาะกับต่างสถานการณ์กันไป ซึ่งวันนี้เราจะมาพูดถึงเรื่องการแคชระดับ Global (เรียกใช้จากที่ไหนก็ได้) ผ่าน Transient Cache และ WP Option ซึ่งทั้งสองแบบจะเป็นการแคชข้อมูลเอาไว้ในฐานข้อมูล
อ้าว อย่างนี้มันก็ไม่ได้ช่วยลดจำนวนคิวรี่สิ?
ถูกต้องครับ แคชเหล่านี้ยังคงต้องคิวรี่ออกมาอยู่ดี แต่การดึงแคชเหล่านี้ออกมาจะสามารถทำได้เร็วมากเพราะเป็นแค่การ SELECT
ข้อมูลออกมาตรงๆ ไม่มีการ JOIN
ตารางใดๆ ให้เปลืองเม็มโมรี่ทั้งสิ้น ทั้งนี้แคชทั้งสองแบบนั้นจะมีจุดต่างให้เลือกใช้ตามสถานการณ์กันอยู่ครับ
Transient Cache
ความหมายตรงตัวของมันเลยก็คือเป็นการแคชแบบชั่วคราว Transient Cache จะเปิดให้ผู้ใช้ตั้งเวลาได้ด้วยว่าแคชนี้จะมีอายุนานเท่าไหร่ ซึ่งจะเหมาะกับการแคชข้อมูลที่มีการอัพเดทอยู่เสมอๆ เช่นการดึงข้อมูลจาก API เป็นต้น (เป็นกรณีที่ผมเจอบ่อยที่สุด) กล่าวคือ Transient Cache เหมาะกับการแคชข้อมูลที่ต้องคำนึงถึงอายุของข้อมูลด้วย
การใช้งาน Transient Cache นั้นตรงไปตรงมามากๆ นั้นคือดึงแคชออกมาผ่านฟังก์ชัน get_transient( "<ชื่อแคช ตั้งว่าอะไรก็ได้>" );
จากนั้นตรวจสอบว่าแคชหมดอายุหรือยัง ถ้าหมดแล้ว (ค่าเป็น FALSE) ก็สั่งดึงข้อมูลใหม่แล้วเซฟทับลงไปพร้อมกับปรับอายุแคชเสียใหม่ผ่านฟังก์ชัน set_transient("<ชื่อแคช ตั้งว่าอะไรก็ได้>", $<ข้อมูล>, $<อายุแคช เป็นวินาที>);
<?php if(false === ($data = get_transient( "transient_name" ))) { // transient already expired or no transient // re-cache data to transient $data = get_stuff_here(); // Fetch data from external API set_transient( "transient_name", $data, $expiration_in_second ); // $data will be serialized, } var_dump($data) // use $data
ในการทำงานปกติของ Transient Cache นั้น เมื่อเราสั่ง get_transient()
จะมีการตรวจสอบก่อนว่าแคชนั้นหมดอายุหรือยัง ถ้าแคชนั้นหมดอายุแล้วก็จะทำการลบออกจากฐานข้อมูลโดยอัตโนมัติเพื่อป้องกันฐานข้อมูลบวม
ทั้งนี้ยังมีบางกรณีเช่นเราปิดปลั๊กอินหรือเปลี่ยนธีมไปแล้ว แล้วปลั๊กอินหรือธีมนั้นๆ ไม่ได้มีการตามลบ Transient ที่ตัวเองสร้างเองไว้ ทำให้ Transient เหล่านี้ยังค้างอยู่ในฐานข้อมูล และเราต้องตามลบเอง (WordPress ไม่มี scheduled task ที่คอยตามลบ transient เหล่านี้โดยอัตโนมัติ)
ข้อควรระวังของการตรวจสอบว่าแคชหมดอายุหรือไม่
จากตัวอย่างข้างบน การตรวจสอบว่าแคชหมดอายุหรือไม่จะต้องใช้ identical comparison เท่านั้น (ใช้เครื่องหมายเท่ากับสามตัว) เพราะว่า get_transient()
นั้นมีโอกาสที่จะคืนค่าอื่นๆ ที่สามารถ evaluate ออกมาเท่ากับ false ได้ เช่น int 0
, string empty
, array empty
, และอื่นๆ อีกมากมาย
WP Option
อย่าให้คำว่า Option มาหลอกเราว่าต้องเก็บเฉพาะการตั้งค่าเท่านั้น ซึ่งในความเป็นจริงเหล่าออพชันนี้สามารถเอามาใช้สำหรับแคชข้อมูลได้ด้วย ซึ่งการแคชข้อมูลลงออพชันนี้จะเหมาะกับการแคชข้อมูลที่ไม่มีอายุของข้อมูล ซึ่งจะมีทำการแคชใหม่เมื่อเกิดเหตุการอะไรสักอย่างหนึ่งขึ้นมา ตัวอย่างเช่นเราทำฟิลเตอร์ตัวหนึ่งไว้ และค่าในฟิลเตอร์นี้จะมาจากข้อมูลใน Custom field ในกรณีแบบนี้เราก็จะฮุคเข้าไปในแอคชัน save_post เพื่อให้ทำการแคชข้อมูลใหม่ทุกครั้งที่มีการบันทึกโพสต์ลงฐานข้อมูล
การใช้งานจริงๆ ของการแคชลงออพชันจะดูยุ่งยากนิดหน่อย เพราะอย่างที่กล่าวไปคือการแคชด้วยวิธีนี้มักจะผูกอยู่กับฮุคใดฮุคหนึ่ง ดังนั้นในตัวอย่างนี้เราจะสมมุติว่าเราจะแคชข้อมูลใหม่ทุกครั้งที่ทำการบันทึกโพสต์ โดยเราจะเขียนฟังก์ชันขึ้นมาฟังก์ชันหนึ่ง และฮุคเข้าไปในแอคชัน save_post
<?php function wp63_post_cache($post_id){ $data = my_cache_function($post_id); // ฟังก์ชันสำหรับแคชข้อมูล ในกรณีนี้เราส่ง $post_id เข้าไปด้วย $autoload = true; // true|false ให้โหลดอัตโนมัติหรือไม่ update_option("<ชื่อออพชัน>", "<ข้อมูล>", $autoload); } add_action("save_post", "wp63_post_cache", 10, 1);
ฟังก์ชัน update_option();
นั้นเป็นการบันทึกค่าลงในออพชันที่ต้องการ (ตั้งชื่อออพชันว่าอะไรก็ได้) และพารามิเตอร์ตัวที่สามหรือ $autoload นั้นเป็นการบอกกับเวิร์ดเพรสว่าจะให้โหลดค่านี้ออกมาอัตโนมัติทุกครั้งที่เวิร์ดเพรสทำงานหรือไม่ ซึ่งถ้าค่านี้ไม่ได้ใช้ทุกหน้าหรือเกือบทุกหน้า แนะนำว่าให้ตั้ง $autoload เป็น false เอาไว้ เพื่อประหยัดแรมในการคิวรี่
ในการเรียกใช้งานนั้น ก็จะใช้ฟังก์ชัน get_option();
ในการเรียกใช้ตามปกติดังนี้
<?php $data = get_option("<ชื่อออพชัน>", "<ค่าเริ่มต้น>"); var_dump($data); ?>
จะสังเกตว่า get_option();
นั้นจะมีการรับพารามิเตอร์ตัวที่สองด้วย ซึ่งพารามิเตอร์ตัวนี้จะเป็นค่าที่ปริยายที่จะใช้งานหากไม่เจอข้อมูลออพชันนี้ในฐานข้อมูล
ข้อมูลที่แคชลงทั้งใน Transient และ Option นั้นจะถูก Serialize เก็บเอาไว้ (ทั้งสองอย่างเก็ยลงตาราง wp_options เหมือนกัน) ดังนั้นหมายความว่าเราสามารถแคชอาเรย์หรือออพเจ็กท์เก็บเอาไว้ได้ด้วย
เล่นท่ายากด้วย cron กับ WP Option เพื่อเลี่ยงปัญหาประสิทธิภาพ
ในการใช้ Transient Cache จะพบว่าหากผู้ใช้เข้าใช้งานหน้านั้นๆ เป็น “คนแรก” หลังจากที่แคชหมดอายุ โค้ดของเราก็จะสั่งให้ทำการแคชข้อมูลใหม่อีกรอบ ณ ตอนนั้นในทันที และด้วยธรรมชาติของ PHP ที่เป็นภาษาแบบ blocking IO ที่จะต้องรอคำสั่งก่อนหน้านี้ประมวลผลเสร็จก่อนจึงจะประมวลผลคำสั่งต่อไป ก็อาจจะทำให้ในบางกรณีที่ผู้ใช้คนนั้นๆ จะพบกับความอืดจากการแคชข้อมูลก็ได้
ให้นึกภาพตามนี้นะครับ สมมุติเราแคชข้อมูลจาก API แห่งหนึ่งลง Transient แล้วบังเอิญว่าวันนั้น API Server เกิดปัญหา ทำให้ response time สูงมาก อาจจะใช้เวลา 2-3 วินาทีกว่าจะตอบ request ของเราได้ ดังนั้นเมื่อแคชหมดอายุแล้วผู้ใช้คนแรกเข้ามา ผู้ใช้คนนี้จะต้องรอระบบแคชข้อมูลก่อน ซึ่งจะกลายเป็นหน้าขาวหมุนติ้วๆ อยู่ 2-3 วินาทีเป็นอย่างต่ำ
วิธีแก้ปัญหานี้อาจจะดูยุ่งยากสักหน่อย นั่นคือเราจะเลี่ยงไปใช้แคชผ่าน WP Option แทน และเราต้องทำ AJAX Endpoint เพิ่มขึ้นมา (หรือจะใช้ REST Endpoint ก็ได้ แล้วแต่สะดวก) จากนั้นตั้งเวลา cron หรือเว็บปิงต่างๆ ให้เข้ามาเปิด endpoint นั้นเป็นระยะๆ ซึ่งเจ้า endpoint ตัวนี้จะไปสั่งแคชข้อมูลอีกต่อหนึ่ง
สำหรับใครที่ยังทำ AJAX Endpoint หรือ REST Endpoint ไม่เป็น ก็คอยติดตามอ่านบทความจาก WP63 ของเรากันได้ครับ
Leave a Reply