ปัญหาหลักใน Elasticsearch คือ การเปลี่ยนแปลง type mapping ของข้อมูล
ซึ่งการทำงานภายในนั้นพบว่า ถ้ามีการเปลี่ยนแปลงแล้ว มันจะทำการ reindex ข้อมูล
และถ้าลงรายละเอียด พบว่า การ reindex นั้น ใช้ทรัพยากรของเครื่องสูงมากๆ
ยิ่งข้อมูลมีขนาดใหญ่ ยิ่งใช้เวลาในการ reindex มากขึ้นเท่านั้น
รวมทั้งจะต้องทำการปิดระบบอีกด้วย (Downtime)
ดังนั้น มาดูว่าจะทำอย่างไร เพื่อทำการแก้ไข mapping โดยไม่ต้องปิดระบบกัน
วิธีการแรก ง่ายสุดๆ คือการใช้ Dynamic index
โดยค่า default ของ Elasticsearch จะเปิดความสามารถนี้อยู่แล้ว
มันคือ เมื่อเราส่งข้อมูลมาเก็บที่ Elasticsearch จะทำการสร้าง type mapping ให้อัตโนมัติ
ดังตัวอย่าง
เมื่อทำการ index เรียบร้อยแล้ว
Elasticsearch จะทำการสร้าง type mapping แบบ dynamic ขึ้นมา
สามารถดู type mapping ที่สร้างขึ้นมา ด้วยคำสั่งดังนี้
ลองจินตนาการดูว่า ในโลกการทำงานจริงๆ นั้น
มีข้อมูลจำนวนมาก ยิ่งเป็นพวก Big data ยิ่งมีปัญหาเยอะ
เพราะว่า โครงสร้างข้อมูลสามารถมีได้หลากหลายรูปแบบ
อาจจะทำให้รูปแบบข้อมูลที่เข้ามามันแปลกๆ ไปได้ เช่น
- เปลี่ยนจาก author ไปเป็น Author
- เปลี่ยนจาก title ไปเป็น Title
ตัวอย่างเช่น
ผลที่ได้ Elasticsearch จะทำการแก้ไข type mapping ให้ โดยทำการเพิ่ม field ใหม่เข้าไป 2 ตัวดังนี้
มาถึงตรงนี้ จะเห็นว่า type mapping มันเปลี่ยนไปเรื่อยๆ
ผมคิดว่า วิธีการนี้คงไม่ใช่สิ่งที่เราต้องการ !!!
ดังนั้น สิ่งที่เราต้องการก็คือ การกำหนด type mapping ไว้ก่อน ไม่ให้เปลี่ยนแบบนี้
จากที่ผ่านมาพบว่า Type mapping ที่กำหนดไว้ตั้งแต่เริ่ม มักจะถูกแก้ไขเปลี่ยนแปลงเสมอ
ปัญหาจึงเกิดขึ้นมานั่นคือ แล้วเราจะแก้ไขอย่างไรล่ะ ?
ความรู้พื้นฐานที่ควรรู้เกี่ยวกับการจัดการ index ของ Elasticsearch คือ
มันจะใช้ Lucene index ถ้าเราทำการเพิ่ม field ใหม่เข้าไปแล้ว
ข้อมูลที่เคย index ไว้แล้วจะไม่ถูกแก้ไข หรือ reindex นะ
ดังนั้น ส่งผลให้ไม่สามารถค้นหาข้อมูลเดิมเจอนะ !!
ทำให้วิธีที่ง่ายที่สุดสำหรับแก้ไขปัญหานี้คือ
- สร้าง index ใหม่ และทำการสร้าง type mapping ใหม่
- ทำการย้ายข้อมูลจาก index เดิมมายัง index ใหม่
- ทำการลบ index เดิม
วิธีการนี้ มักจะทำงานได้ดีบน development server
แต่เมื่อนำไปทำบน production server แล้ว มักจะใช้เวลานานมาก
ซึ่งจำเป็นต้องปิดระบบ มันส่งผลกระทบต่อผู้ใช้งานอย่างแรง
แล้วมันมีวิธีการที่ไม่ต้องปิดระบบไหมล่ะ (Zero Downtime) ?
โชคดีว่าที่ Elasticsearch blog เขียนเรื่องนี้ไว้ให้ด้วย
ใช้วิธีการ Alias เพื่อทำการ reindex มีขั้นตอนดังนี้
- ทำการสร้าง alias สำหรับ index ของ type mapping เก่า
- เปลี่ยนให้ระบบงานของเรา ไปชี้ที่ alias แทนการชี้ไปยัง index ตรงๆ
- ทำการสร้าง index ใหม่ เพื่อทำการแก้ไข type mapping
- ทำการย้ายข้อมูลจาก index เก่า มายัง index ใหม่
- ทำการย้าย alias จาก index เก่า ไปยัง index ใหม่
- ทำการลบ index เก่า ซะ
ลองมาทำตามขั้นตอนกันหน่อยสิ
1. ทำการสร้าง Alias ชื่อว่า xxxxx ไปยัง index ชื่อว่า demo ก่อน ดังนี้
2. สร้าง index ใหม่ ชื่อว่า new_demo โดยทำการกำหนด type mapping ดังนี้
3. ทำการย้ายข้อมูลจาก index ชื่อว่า demo ไปยัง new demo
ในขั้นตอนนี้มันคือ การย้ายข้อมูลปกติดีๆ นี่เอง
ซึ่งมันไม่กระการใช้งานของผู้ใช้งาน ซึ่งยังใช้ข้อมูลจาก index ชื่อว่า demo อยู่นะ
ตรงนี้ต้องเขียนระบบการย้ายขึ้นมา
4. เมื่อย้ายข้อมูลเรียบร้อยแล้ว ให้ทำการแก้ไข Alias เพื่อให้ชี้ไปยัง index ใหม่ชื่อว่า new_demo
ดังนี้
5. ทำการลบ index ชื่อว่า demo ซะ
curl -XDELETE localhost:9200/demo
แต่ในการทำงานจริงๆ นั้นมันจะมีปัญหาอื่นๆ อีก
เช่นการใช้งานบน Cluster ถ้ามีการเพิ่มหรือเขียนข้อมูลอยู่ตลอดเวลา
เมื่อเราทำการแก้ไขด้วยวิธีการแบบ Zero downtime
จะจัดการอย่างไรดีล่ะ ?
วิธีการที่แนะนำคือ
วิธีการแรก ทำการเขียนข้อมูลลงทั้งสอง index
ต่อมาคือ การเขียนข้อมูลลง index ใหม่ แต่เวลาอ่าน จะอ่านจากทั้งสอง index
ซึ่งวิธีการต่างๆ เหล่านี้ ไม่มีสิ่งที่ดีที่สุด
มีเพียงสิ่งที่เหมาะกับคุณ หรือ ระบบงานของคุณเท่านั้น
และยังมีวิธีการอื่นอีกนะครับ
สิ่งที่ต้องจำไว้อยู่เสมอ สำหรับ Elasticsearch ก็คือ
Update = Delete + Reindex
ดังนั้นการแก้ไขค่าต่างๆ ใน Elasticsearch มันมี cost เสมอครับ
Reference Website
http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
https://blog.codecentric.de/en/2014/09/elasticsearch-zero-downtime-reindexing-problems-solutions/