มาทำ Mongo Replica Set เพื่อชีวิตที่ปลอดภัยกันเถอะ
ต่อจากบทความเดิมในการทำ MongoDB แบบ Replica Set ได้ที่นี่
เกริ่นก่อนเริ่มนะครับเนื่องจากบทความเก่ามีการ ทำ MongoDB แบบ Replica Set แต่ไม่ได้อธิบายอะไรมากนักบทความนี้เลยจะมาขยายความและประโยชน์ในการทำ Replica Set ฉบับการทำใน MongoDB โดยผมจะทำให้อยู่คนละ Server กันเพื่ออีกตัวพังอีกตัวยังคงอยู่
Replica Set ใน MongoDB คือกลุ่มของเซิร์ฟเวอร์ฐานข้อมูลที่ใช้คัดลอกข้อมูลกันและกันเพื่อเพิ่มความทนทานและความพร้อมในการให้บริการของระบบฐานข้อมูล
ยกตัวอย่างเช่น:
- ตั้งเซิร์ฟเวอร์ฐานข้อมูลมา 3 เครื่อง: เครื่อง A, B, และ C
- เครื่อง A ถูกตั้งเป็น Primary, และเครื่อง B กับ C ถูกตั้งเป็น Secondary
หลักการทำงานคือ:
- เราจะเขียนข้อมูลลงใน Primary เท่านั้น ซึ่งก็คือเครื่อง A
- เครื่อง A จะมีหน้าที่คัดลอก (replicate) ข้อมูลไปยังเครื่อง B และ C ที่เป็น Secondary
- ทำให้เครื่อง A, B, และ C มีข้อมูลที่เท่ากัน
ประโยชน์หลัก:
- เมื่อเซิร์ฟเวอร์ A (Primary) ล่ม, เราสามารถปรับเครื่อง B หรือ C ให้เป็น Primary แทน
- ลดปัญหาการ Downtime ได้มาก เนื่องจากเรามีสำเนาของข้อมูลในเครื่อง Secondary
นอกจากนี้:
- เราสามารถใช้เครื่อง A สำหรับการเขียนข้อมูล (Write Database)
- และใช้เครื่อง B และ C สำหรับการอ่านข้อมูล (Read Database)
- ซึ่งจะช่วยลดปัญหาคอขวดและเพิ่มประสิทธิภาพในการอ่านและเขียนข้อมูล
สิ่งที่ต้องเตรียม
- เครื่อง Server 2 เครื่อง
- เปิด Port ให้พร้อมสำหรับ Mongodb
- ลง Docker และ Docker-compose ให้เรียบร้อย
มาทำกันเลยดีกว่าครับเพื่อให้ได้เห็นภาพที่ชัดยิ่งขึ้น
ผมจะเอา Docker-compose ที่เหมือนกันเปะไปไว้คนละ Server เพื่อสร้าง Mongo DB 2ตัว เกริ่นหัวเรื่องผม ยกตัวอย่าง A B และ C แต่ทำจริงผมจะทำแค่ 2 เครื่องคือ A และ B
และผมจะเตรียม File init-mongo.js เพื่อให้สิท rootuser ให้เรียบร้อยตั้งแต่เริ่ม Run Docker
openssl rand -base64 756 >./mongo-keyfile
chmod 400 ./mongo-keyfile
จากนั้นผมจะ random เพื่อสร้าง mongo-keyfile ขึ้นมา
*หมายเหตุ random มาแค่เครื่องเดียวนะ แล้ว Copy จากเครื่องที่จะให้เป็น Primary ไปใส่ที่เครื่อง Secondary ถ้า Key ไม่ตรงกันมันจะคุยกันไม่ได้เป็นเรื่องของความ Secuerity
docker exec -it id sh
ทำการ SH เข้าไปใน Container mongodb
mongosh "mongodb://rootuser:rootpass@localhost:27017/admin"
คำสั่งนี้เริ่มต้นการเชื่อมต่อกับ MongoDB ที่ทำงานอยู่บน localhost
จากนั้นก็ทำการ Initiate โดย Add Primary และ Secondary
*หมายเหตุ ขั้นนี้ทำเฉพาะเครื่อง Primary นะ เครื่อง Secondary Run Docker ขึ้นเป็นอันจบไปแล้ว
rs.add("SecondaryInstanceIP:27017")
การใช้ rs.add()
เพื่อเพิ่ม Secondary ภายหลักก็ได้เมื่อเราอยากมีเครื่องเพื่อสำรองข้อมูลเพิ่มเราก็สามารถ Add ไปได้ที่ Server ที่เป็น Primary ได้เลย
cfg = rs.conf()
cfg.members[0].priority = 3
cfg.members[1].priority = 2
cfg.members[1].priority = 1
rs.reconfig(cfg, {force: true});
ต้อง Set Priority ให้มันด้วยไม่งั้นมันจะไม่ปรับ primary ให้อัตโนมัติ
rs.status()
{
“optime” : { “ts”: Timestamp({ “t”: 1715845662, “i”: 1 }), “t”: Long(“2”) },
“optimeDate” : ISODate(“2024–05–16T07:47:42.000Z”),
“lastAppliedWallTime” : ISODate(“2024–05–16T07:47:42.716Z”),
“lastDurableWallTime” : ISODate(“2024–05–16T07:47:42.716Z”),
…
“syncSourceHost” : “PrimaryInstanceIP:27017”,
}
จากนั้นลองเช็ค Status ดูให้ดูที่ตัว lastAppliedWallTime และ lastDurableWallTime ถ้าทั้งของ Primary และ Secondary เท่ากันแล้วแสดงว่า Sync ข้อมูลหากันหมดแล้ว
mongodb://rootuser:rootpass@PrimaryInstanceIP:27017,SecondaryInstanceIP:27017/?replicaSet=rs0&readPreference=secondaryPreferred
ผมทำการ Config URL Mongo แบบนี้เพื่อที่จะให้:
- การเขียน (write) ทั้งหมดจะถูกส่งไปยัง Primary (PrimaryInstanceIP:27017)
- การอ่าน (read) จะพยายามอ่านจาก Secondary (SecondaryInstanceIP:27017) ก่อน แต่ถ้า Secondary ไม่พร้อมใช้งานก็จะอ่านจาก Primary
- ถ้า Primary ล่มจะเปลี่ยนตัว Secondary มาเป็น Primary แทนเลย
เป็นยังไงกันบ้างครับหลังอ่านจนจบมาถึงตรงนี้ เท่านี้เราก็จะได้ MongoDB ที่ได้ทั้งความเสถียร และ การสำรองข้อมูลแบบ Realtime ได้ทั้งความ Security และ ลดปัญหาการ Downtime เมื่อเกิดปัญหา และยังสามารถเลือกเครื่อง Server ให้ MongoDB แต่ละตัวด้วยมือตัวเองอีกด้วย