เหตุผลดีๆ ที่ควรทำ Multiple Realtime Database เพื่อทำลายทุกข้อจำกัดที่มี

Thanongkiat Tamtai
Firebase Thailand
Published in
4 min readDec 21, 2017
https://cdn-images-1.medium.com/max/1024/1*9VGGmxx76xYfDCiP0_oEoA.png

หากคุณใช้ Firebase Realtime Database ในระดับ Production เคยได้ลองคิดดูบ้างไหมว่า เจ้าตัว Service ที่เราใช้งานอยู่อย่าง Firebase Realtime Database จะรองรับข้อจำกัดต่างๆ ในการใช้งานได้มากน้อยขนาดไหน ? ที่เขาบอกว่า Scalable ได้เนี้ย มันจะขยายไปให้เราถึง Infinity เลยไหม ? ทำไปทำมาในอนาคตจะต้องมาออกแบบโครงสร้างของ Database ใหม่เพราะมันเกินข้อจำกัดของ Service นี้หรือเปล่า ? ถ้าคุณยังมีปัญหากับคำถามเหล่านี้ เรายังมีคำตอบให้คุณ !

https://firebase.google.com/support/releases

เมื่อวันที่ 10 พฤศจิกายน 2560 ทาง Firebase ก็ได้ประกาศ Feature ให้ Firebase Realtime Database สามารถรองรับการทำ Multiple Database Instances ได้เป็นที่เรียบร้อย ซึ่งจะสามารถใช้ได้ใน Blaze Plan (ต้องเป็นแพ็คเก็จแบบเสียเงิน) เท่านั้น โดยจุดประสงค์หลักของ Feature นี้ก็คือ ทำให้เราสามารถลบข้อจำกัดต่างๆ ของ Single Database ไปได้ (เมื่อ Database เดียวมันเหงา ก็ต้องใช้หลายๆ Database ช่วยกัน)

มาดูข้อจำกัดถ้ายังใช้ Single Database

https://firebase.google.com/pricing

สิ่งที่เราเห็นกันอยู่โต้งๆ ตอนเลือก Package นั้นก็คือ Simultaneous connections (การเชื่อมต่อพร้อมกัน) ซึ่งข้อจำกัดสูงสุดของแต่ละ Package คือ Free อยู่ที่ 100 Connections , Flame อยู่ที่ 100K (1 แสน) Connections และ Blaze อยู่ที่ 100K เหมือนกัน แต่ว่าเป็น 100K ต่อ 1 Database นั้นก็แปลว่า หากเราแบ่งส่วนการใช้งานดีๆ มันก็จะรองรับได้มากเท่าที่เราต้องการได้แน่นอน และเจ้า Connection เนี้ยก็ไม่ได้หมายถึง จำนวนผู้ใช้ที่รองรับได้มากที่สุดของแอพพลิเคชั่นเรานะ แต่มันคือการที่ผู้ใช้เข้ามาใช้ Service ของ Realtime Database เช่น เขียน , อ่าน , ลบ หรือ แก้ไข ซึ่ง 1 Connection ก็จะมีการนับอย่างเช่น มือถือ 1 เครื่อง , อุปกรณ์ IoT 1 ชิ้น หรือ Web Browser 1 Tab (ตัวเปลืองเลย) แต่ว่าข้อจำกัดก็ยังไม่หมดเพียงเท่านี้ ยังมี ขีดจำกัดในการทำ Write Operation ได้ 1,000 write operations/second , Simultaneous responses send (การตอบสนองพร้อมกัน) ของการทำ Broadcast และ Read operations รวมทั้งถ้าเรา Push notifications ที่ใช้ข้อมูลจาก Realtime Database ก็จะจำกัดอยู่ที่ประมาณ 1 แสน Operations/Second , Cloud Functions Triggered ที่จะรองรับ 1 Write Operation อยู่ที่ 1000 Functions / Database และยังมีข้อจำกัดอื่นๆ อีกหลายอย่าง เช่น การซ้อนระดับชั้นของข้อมูลอยู่ที่ 32 ชั้น หรือ ขนาดของข้อมูล Read operations อยู่ที่ 256 MB และ Write Operation ที่ 16 MB หากต้องการรายละเอียดทั้งหมดสามารถเข้าไปดูได้ที่ Firebase Docs

เหตุผลที่ควรทำ Multiple Database Instances

มาถึงเหตุผลที่เราควรแบ่ง Database ออกเป็นส่วนย่อยๆ กันบ้าง

Sharding strategies

สามารถแบ่งตามแผนกลยุทธ์ให้กับ Database ของเราได้ โดยจะมีเทคนิคคร่าวๆ อยู่ 3 ข้อ

  • The Master Shard

เป็นการแบ่ง Database ของเราตามการใช้งานของผู้ใช้ ส่วนไหนที่มีการใช้งานมากๆ ก็จะแบ่งไปอีก Instances โดยเราจะทำการสร้าง Map Data กับ Instances ซึ่งเราอาจจะไม่ต้องให้มันแยกข้อมูลตามการ Map ทุกครั้ง แต่สามารถเขียนโปรแกรมตรวจสอบให้แยกเฉพาะตอนที่มีการใช้งานมากๆ

{
"chatrooms": {
"general": "room-db-general",
"randomchat": "room-db-randomchat",
"sweetgifs": "room-db-sweetgifs"
}
}
  • Bucketing

เป็นการแบ่ง Database ของเราตามประเภทของข้อมูล เช่น Users Database , Messages Database , Receipts Database

  • Per customer

เป็นการแบ่ง Database ของเราตามจำนวนของลูกค้า เช่น ข้อมูลของลูกค้าบริษัท A จะมี Database Instances ของตัวเอง และจะไม่เกี่ยวข้องกับข้อมูลของลูกค้าบริษัท B กรณีเกิด Overload กับ Instance ของบริษัท A จะไม่มีผลต่อ Instance ของบริษัท B หรือ เราจะใช้ Firebase Remote Config เข้ามาช่วยในการแบ่ง Database Instance ตามพื้นที่การใช้งานของผู้ใช้ เช่น ผู้ใช้จากประเทศไทยจะใช้ Instance หนึ่ง และผู้ใช้จากประเทศอื่นก็จะใช้อีก Instance หนึ่ง

Security

สามารถสร้างกฏของ Database ได้หลายแบบ โดยกฏของ Database แต่ละ Instance จะไม่เกี่ยวข้องกันและก็ไม่สามารถอ้างอิงหากันได้ใน Simulation เช่น ลูกค้าบริษัท A อยากจะอนุญาติให้พนักงานทุกคนสามารถเข้าถึงข้อมูลบัญชีรายรับ-รายจ่าย แต่บริษัท B อยากจะอนุญาติให้เฉพาะพนักงานฝ่ายบัญชีหรือพนักงานระดับหัวหน้าขึ้นไปเท่านั้น โดยข้อมูลทั้งหมดมีโครงสร้างของข้อมูลเหมือนกัน หรือ จะเป็นกรณีที่เรามีแอพพลิเคชั่นแบบเสียเงินซื้อและฟรีดาวน์โหลด ในกรณีที่เสียเงินซื้อเราจะอนุญาติให้ผู้ใช้สามารถปรับแต่งค่าต่างๆได้ตามใจชอบ แต่ถ้าเป็นฟรีดาวน์โหลดจะอนุญาติให้ผู้ใช้สามารถปรับแต่งค่าต่างๆได้แค่ฟังก์ชั่น A B C เท่านั้น โดยทั้งสองแอพพิลเคชั่นเราก็สามารถออกแบบโครงสร้างของ Database ที่เหมือนกันเพียงครั้งเดียว แต่ใช้การสร้าง Multiple Database Instances และ Security Rule เข้ามาช่วยในการทำงานได้

Cloud Functions

สามารถสร้างการ Triggers ของข้อมูลอย่างเดียวกันในแต่ละ Database ได้ เช่น ปกติถ้าเราต้องการจัดข้อมูลเนื้อหาของ Blog เมื่อผู้ใช้เกิดการเขียนข้อมูลลง Database เราจะให้ Cloud Function ทำการ Trigger ตัดคำหยาบ แต่หากเป็นอีก Instance ของผู้ใช้ในประเทศอื่น เราจะให้ Cloud Function ทำการ Trigger ตัดคำหยาบ และทำการแปลภาษาด้วย Google Cloud Translate API ด้วย

การทดลองสิ่งใหม่ๆ

หากเราอยากที่จะทดสอบการเขียนข้อมูลลงไปใน Database แต่ก็กลัวจะไปกระทบกับข้อมูลที่มีอยู่ ถึงจะมี Back Up ก็จริงอยู่ แต่เป็นการ Back Up วันละครั้ง ซึ่งหากผู้ใช้ของเรามีการใช้งานตลอดเวลา เช่น เกม , เว็บจองตั๋วเครื่องบิน หรือ แอพขายของต่างๆ มันคงจะเกิดเรื่องใหญ่แน่ๆ หากเราทำข้อมูลสูญหาย ซึ่งวิธีการของที่บางคนทำอยู่นั้นก็คือ

  • Download ข้อมูลเป็น JSON มาเก็บไว้ในเครื่อง
  • ไปสร้าง Project ใหม่
  • เปลี่ยนชื่อ Path เช่น จาก Users เป็น User1 , User2

ซึ่งวิธีการข้างต้นก็จะทำให้เกิดความยุ่งยากในการพัฒนาทั้งสิ้น เมื่อ Download มาเก็บไว้ แต่ทำพัง ทำหาย ซึ่ง Database มีอัตราการ เขียน/อ่าน สูงมาก เมื่อ Upload กลับเข้าไปก็ไม่ใช่ข้อมูลล่าสุดแล้ว หรือ การไปสร้างโปรเจคใหม่ ก็จะไปสร้างข้อมูลใหม่เพียงแค่ Realtime Database หากเราต้องการใช้ร่วมกับ Firebase Authentication หรือ Firebase Cloud Function หรือ Firebase Hosting ข้อมูลเหล่านี้จะไม่ได้ตามไปด้วย ก็ต้องเสียเวลา Deploy อะไรต่างๆใหม่ทั้งหมด หรือการเปลี่ยนชื่อ Path แต่เขียนใน Database เดิม ก็จะมีความเสี่ยงที่จะเกิดการเปลี่ยนชื่อผิดไปเหมือนกับของจริง ซึ่งอาจจะเกิดการ Overload ของ Database , การ Monitor สถิติต่างๆ ก็จะไม่แม่นยำและยังต้องมาเปลี่ยนชื่อกลับอีก

แค่คิดตามก็เหนื่อยแล้วใช่ไหมครับ ? วิธีแก้ง่ายๆ ก็เพียงทำ Multiple Database Instances เท่านั้นเอง

ข้อพึงคำนึง

หากเราจะแบ่งทำ Multiple Database Instances ก็มีข้อที่เราควรคำนึงขึ้นอยู่บ้างเหมือนกัน

  • การสอบถามข้อมูล (Query) จะทำได้ภายใน Instance ตนเองเท่านั้นและไม่สนับสนุนการสอบถามข้อมูลผ่าน Instance
  • ไม่มีการคัดลอกหรือแบ่งปันข้อมูลระหว่าง Instance ได้
  • แต่ละแอพพลิเคชั่นจะสามารถเชื่อมต่อได้เพียง 1 Instance ต่อ ช่วงเวลาใดเวลาหนึ่ง

วิธีการสร้าง Multiple Database Instances

ก่อนอื่นอย่าลืมไปเลือก Packet ของ Project เราเป็น Blaze Plan ก่อน

ขั้นตอนแรกให้เข้าไปที่ Firebase Console จากนั้นสังเกตุ Navigation bar ทางด้านซ้าย เมนู Developer > Database > Realtime Database > Data > จากนั้นกดปุ่มเมนูดังรูป เลือก Crate new database

ซึ่งหากเข้า Downgrade จาก Blaze plan มา Flame หรือ Spark plan Instances อื่นๆ จะไม่สามารถใช้งานได้ แต่จะไม่ถูกลบ หากเราอยากจะกลับไปใช้งานให้กลับไปเลือกเป็น Blaze plan ก่อน

การเชื่อมต่อ Multiple Database Instances

ในการเชื่อมต่อให้เราระบุ URL ของ Instance อื่นลงไปในการ Initialize โดยในตัวอย่างเป็นการเชื่อมต่อของ Javascript SDK ซึ่งใน Platform อื่นก็จะมีวิธีการทำคล้ายๆกัน

// Get the default database instance for an app
var database = firebase.database();

// Get a secondary database instance by URL
var database = firebase.database('https://testapp-1234.firebaseio.com');

หากเราไม่ได้ระบุ URL ลงไปก็จะเป็น Default Database Instance

การเชื่อมต่อ Multiple Database Instances กับ Cloud Functions

const functions = require('firebase-functions');
const firebase = require('firebase-admin');

firebase.initializeApp(functions.config().firebase);

exports.copymsg = functions.database.instance('room-db-randomchat').ref('/messages').onWrite(event => {
const { data } = event;
const notificationDb = firebase.database(<your-full-db-url>);
return notificationDb.ref(`notifications/${data.key}`).set(data.val());
});

ในการเชื่อมต่อกับ Cloud Functions ก็จะคล้ายๆ กับคำสั่งใน SDK อื่น คือการระบุ Instance Name ลงไปใน .instance() ซึ่งหากเราไม่มี Method นี้ ก็จะเป็นการเชื่อมต่อกับ Default Database Instance

const functions = require('firebase-functions');
const firebase = require('firebase-admin');

firebase.initializeApp(functions.config().firebase);

// triggers off your default database
exports.sanitize = functions.database.ref('/messages').onWrite(event => {
// sanitize message here
});

ฝากทิ้งท้าย

ก็ไม่มีอะไรจะแนะนำไปมากกว่าคำว่า “ทำเถอะนะ” ถ้าคุณคิดว่าในอนาคตแอพพลิเคชั่นของคุณจะมีการเติบโตไปมากกว่านี้ หากใครยังไม่ได้ทำยังพยายาม Migration ตั้งแต่ยังเนิ่นๆ หรือหากใครที่กำลังเริ่ม Project ใหม่ หากออกแบบไว้ตอนตั้งแต่เริ่มทำ อนาคตก็จะสบายตัวไม่ต้องค่อยมา Optimized ในภายหลัง สุดท้ายนี้ก็ฝากกด Clap เพื่อเป็นกำลังใจให้ผู้เขียน และ กดติดตาม เพื่อรับการแจ้งเตือนเมื่อมีบทความใหม่ด้วยนะครับผม :)

--

--

Thanongkiat Tamtai
Firebase Thailand

CTO @ Flagfrog # Full-stack Developer # Everything i can do , but it maybe not cool