เก็บค่าลง flash ทุกวินาที จำเป็นแค่ไหน

อุปกรณ์ที่จำค่าหลังปิดไฟได้ใช้งานสะดวกกว่าต้องตั้งใหม่ทุกครั้ง ไม่ว่าจะเป็นค่ารอบอ่านเซนเซอร์ ชื่อจุดติดตั้ง หรือระดับที่ผู้ใช้เลือกไว้ เราจึงมักเริ่มจากบันทึกทันทีเมื่อมีค่าเปลี่ยน เพื่อให้มั่นใจว่าจะไม่ลืม
แต่พอข้อมูลเริ่มเปลี่ยนถี่ขึ้น เช่น แถบเลื่อนที่ส่งค่าระหว่างลาก หรือค่าที่อ่านทุกวินาที การบันทึกทุกครั้งอาจไม่ได้ช่วยงานเท่ากันทั้งหมด บางค่าเป็นเพียงสถานะชั่วคราว ขณะที่บางค่าเป็นสิ่งที่ผู้ใช้ตั้งใจให้จำจริงๆ
ก่อนวางคำสั่งเขียน flash ลงในทุกเส้นทาง แอดอยากชวนแยกข้อมูลสองกลุ่มนี้ก่อนครับ เพราะจังหวะที่เหมาะกับการทำงานใน RAM อาจไม่ใช่จังหวะที่ควรบันทึกถาวร และการเก็บข้อมูลได้ยังต้องมีวิธีตรวจว่าเก็บสำเร็จด้วย
ค่าไหนจำเป็นหลังเปิดเครื่องใหม่
เริ่มจากรายการที่ระบบต้องใช้เพื่อกลับมาทำงาน เช่น ค่าตั้งเครือข่ายหรือการตั้งค่าที่ผู้ใช้ยืนยันไว้ ส่วนค่าที่สร้างใหม่ได้จากการอ่านครั้งถัดไป หรือสถานะว่าปุ่มกำลังถูกกดอยู่ อาจไม่จำเป็นต้องเขียนถาวรทุกครั้ง
ข้อมูลต่อเนื่องอย่างประวัติอุณหภูมิก็ควรมีแผนจัดเก็บของมันเอง ไม่ปนกับค่าตั้งค่าเพียงเพราะทั้งสองอย่างเป็นตัวเลข NVS ถูกออกแบบเป็นที่เก็บแบบ key-value และมีลักษณะงานที่เหมาะสม หากต้องเก็บข้อมูลจำนวนมากต่อเนื่องควรประเมินรูปแบบอื่นตามขนาดและรอบเขียนด้วย

เมื่อแยกได้แล้ว ให้กำหนดสิ่งที่ระบบยอมเสียได้หลังไฟดับ เช่น ค่าที่ผู้ใช้ยังลากไม่เสร็จอาจยอมกลับไปค่าที่บันทึกก่อนหน้าได้ แต่ค่าที่หน้าจอบอกว่าบันทึกแล้วควรมีหลักฐานจากขั้นเก็บจริง ความต้องการนี้จะเป็นฐานให้เลือกรอบเขียน ไม่ใช่เลือกจากความกลัวว่า flash จะพังเพียงอย่างเดียว
รวมการเปลี่ยนถี่ให้เป็นการตั้งค่าที่ตั้งใจ
ถ้าผู้ใช้ปรับระดับผ่านแถบเลื่อน เราอาจใช้ค่าปัจจุบันใน RAM เพื่อให้ตอบสนองทันที แล้วบันทึกเมื่อกดตกลงหรือเมื่อหยุดเปลี่ยนตามช่วงที่ออกแบบไว้ วิธีนี้แยกความลื่นของการควบคุมออกจากการเขียนถาวรได้
แต่หากเลือกบันทึกหลังเงียบไปช่วงหนึ่ง ก็ควรคิดถึงกรณีมีการเปลี่ยนต่อเนื่องด้วย เพราะตัวตั้งเวลาที่เลื่อนออกทุกครั้งอาจไม่เคยถึงจุดบันทึกเลย อาจต้องมีขอบเขตเวลาสูงสุดหรือเงื่อนไขอื่นตามสิ่งที่งานยอมรับ ไม่ใช่เลื่อนต่อได้ไม่มีที่สิ้นสุด
อีกวิธีที่ช่วยลดงานไม่จำเป็นคือเทียบกับค่าที่บันทึกสำเร็จล่าสุด หากได้ค่าเดิมอยู่แล้วก็ไม่ต้องออกคำสั่งเขียนใหม่ทุกครั้ง แต่ต้องแยกตัวแปรให้ชัดว่าค่าปัจจุบันกับค่าถาวรต่างกันอยู่หรือไม่ อย่าอัปเดตว่าบันทึกแล้วก่อนรู้ผลการทำงานจริง

ในระบบที่มีหลาย task ควรมีเจ้าของการบันทึกหรือมีการประสานที่เหมาะสมด้วย เพื่อให้ค่าที่จะเก็บเป็นชุดเดียวกัน ไม่ให้ช่วงที่กำลังสร้างข้อมูลสำหรับบันทึกมีอีกงานแก้บางช่องจนเกิดชุดค่าที่ไม่เคยเป็นสถานะที่ผู้ใช้ยืนยันจริง
คำสั่งเขียนกับคำว่าสำเร็จต้องตรงกัน
เมื่อใช้ NVS ผ่าน ESP-IDF ควรตรวจผลของการเปิด อ่าน ตั้งค่า และ commit ตามสัญญาของ API ไม่คิดว่าการเรียกฟังก์ชันผ่านมาถึงบรรทัดสุดท้ายหมายถึงข้อมูลอยู่ถาวรแล้ว ส่วน wrapper ของ framework อื่นก็ต้องอ่านว่ามันจัดการขั้นใดให้บ้าง
หาก commit ไม่สำเร็จ ควรเก็บสถานะว่ายังมีค่าที่ต้องบันทึกและรายงานตามความเหมาะสม ไม่บอกผู้ใช้ว่างานเสร็จแล้วเพียงเพราะอุปกรณ์ยังใช้งานค่าปัจจุบันจาก RAM ได้ เพราะเมื่อปิดเครื่อง ความต่างนี้จะปรากฏในรูปที่คนใช้คาดไม่ถึง
การเก็บหลาย key ก็ไม่ควรถูกสมมติว่าเป็นธุรกรรมชุดเดียวแบบฐานข้อมูลทุกกรณี ถ้าค่าหลายช่องต้องสอดคล้องกัน ต้องออกแบบรูปแบบข้อมูล การระบุรุ่น และวิธีตรวจความครบตามข้อกำหนดของแอป โดยตรวจพฤติกรรมที่ framework รับรองจริงก่อน
ตัวอย่างเช่น การเก็บชุดตั้งค่าที่มีเลขรุ่นและตรวจขอบเขตทุกฟิลด์ตอนอ่านกลับ จะช่วยให้รู้ว่าข้อมูลตรงกับสิ่งที่แอปคาดหรือไม่ แต่การมีเลขรุ่นไม่ได้ทำให้กระบวนการย้ายข้อมูลปลอดภัยเอง เรายังต้องมีทางรับมือเมื่อข้อมูลบางส่วนใช้ต่อไม่ได้
เมื่อพื้นที่มีปัญหา อย่ารีบล้างทุกอย่าง
พื้นที่เต็ม ข้อมูลไม่ตรงชนิด หรือการเปลี่ยนผัง partition เป็นเหตุที่ต้องตรวจจากรหัสผิดพลาดและประวัติรุ่น หากตัวอย่างเริ่มต้นเลือก erase เพื่อให้ทดลองต่อได้ เราก็ไม่ควรนำพฤติกรรมนั้นมาใช้กับอุปกรณ์ติดตั้งจริงโดยไม่คิดว่าข้อมูลใดจะหายตามไป
ค่าตั้งเครือข่ายอาจอยู่ในส่วนที่เกี่ยวข้องกับการเข้าถึงอุปกรณ์ด้วย หากล้างโดยอัตโนมัติแล้วไม่มีทางตั้งใหม่ที่เหมาะสม บอร์ดอาจบูตได้แต่หายจากระบบจัดการ จึงควรแยกขั้นกู้ข้อมูลกับขั้นคืนค่าโรงงาน และทำให้ผู้ดูแลรู้ว่ากำลังเลือกผลแบบใด
ในกรณีย้าย schema ควรเก็บวิธีเปลี่ยนจากรุ่นเดิมไว้พร้อมเฟิร์มแวร์ และทดสอบกับข้อมูลที่ใช้งานมาจริง ไม่ตรวจเพียงกรณี flash ว่าง เพราะรอบอัปเดตเป็นจังหวะที่ค่ารุ่นเก่ามาเจอโค้ดใหม่พอดี
ความทนทานต้องประเมินจากภาระของงาน
NVS มีกลไกจัดการการเขียนของมัน แต่ไม่ได้แปลว่าการเขียนทุกความถี่ไม่มีต้นทุน เราควรดูชนิด flash การแบ่งพื้นที่ ปริมาณข้อมูล และจำนวนครั้งที่ระบบสร้างงานเขียนจริง ก่อนประเมินความเหมาะสมระยะยาว
หากยังไม่มีข้อมูลเหล่านี้ ไม่ควรคำนวณอายุเป็นปีจากตัวเลขทั่วไปแล้วใช้รับรองทั้งอุปกรณ์ วิธีเริ่มต้นที่ตรงกว่าคือเก็บจำนวนคำขอเขียน จำนวนที่บันทึกสำเร็จ และเหตุที่เกิด retry ระหว่างงานทดสอบ เพื่อให้เห็นว่าการออกแบบกำลังสร้างภาระเท่าไร
การทดสอบควรรวมการปิดเปิดและการเริ่มใหม่ตามขั้นที่กำหนดบนอุปกรณ์ที่กู้ได้ แล้วอ่านค่ากลับมาตรวจทั้งชุด ไม่ดูเพียงว่าตัวเลขบนจอยังเหมือนเดิมระหว่างเครื่องเปิด เพราะค่าที่แสดงอาจยังเป็นสำเนาใน RAM อยู่
สรุป
ก่อนเก็บค่าลง flash ถี่ๆ ให้แยกค่าตั้งค่าถาวรออกจากสถานะชั่วคราวและข้อมูลต่อเนื่อง แล้วเลือกรอบบันทึกตามสิ่งที่ยอมเสียได้จริง เมื่อแยกค่าปัจจุบัน ค่าที่ยังรอเก็บ และผล commit สำเร็จออกจากกัน เราจะลดงานเขียนที่ไม่จำเป็นและอธิบายพฤติกรรมหลังไฟดับได้ชัดขึ้น โดยไม่ให้คำว่าจำค่าได้เป็นเพียงสิ่งที่เห็นตอนเครื่องยังเปิดครับ


