มารู้จัก Citus กันเถอะ (ตอนที่ 1)
สำหรับคนที่ใช้ Relational Database เป็นประจำ (เช่น MySQL, PostgreSQL) ปัญหาใหญ่ๆ อย่างนึงที่คุณจะพบก็คือ การทำ Scaling
กล่าวคือ เมื่อถึงจุดนึงที่ Database ของคุณเป็นคอขวด (Bottle-neck) ของระบบโดยรวม… สิ่งเดียวที่คุณทำได้คือ การเพิ่ม Spec ให้กับตัว Database Server ซึ่งเราเรียกการ Scaling แบบนี้ว่า Vertical Scaling
ข้อเสียของการทำ Vertical Scaling นั่นก็คือ ตัว Database Server จะต้องมี Downtime อย่างแน่นอน…เพราะเราไม่สามารถเพิ่ม CPU, RAM หรือ Harddisk ในขณะที่เปิดเครื่องได้
แต่ที่จริงแล้ว เรายังมีการทำ Scaling อีกแบบนึง ที่เรียกว่า Horizontal Scaling
การทำ Horizontal Scaling นี้ อาจไม่จำเป็นต้องดับเครื่องเลย… เพราะหลักการคือการ Add Node เข้าไปใน Cluster แล้วสั่งการให้ Cluster นั้นรู้จักกับ Node ตัวใหม่… เพื่อจะได้จ่ายงาน กระจายภาระมายังที่เครื่องต่างๆ ได้อย่างถูกต้อง
ในบทความนี้… ผมจะพูดถึง Citus ซึ่งเป็น Extension ตัวหนึ่งของ PostgreSQL สำหรับการทำ Horizontal Scaling ครับ
Citus คืออะไร
Citus เป็น PostgreSQL Extension แบบ Opensource เพื่อช่วยให้การทำ Scaling ใน PostgreSQL เป็นเรื่องง่าย โดยใช้หลักการทำ Sharding และ Replication เข้ามาช่วย
ใน Document ของ Citus นั้น จะบอก Common Use Cases หลักๆ เป็นสองงาน ก็คือ
- Multi-tenants Applications: ส่วนใหญ่แอปประเภทนี้คือ แอปที่ทำงานแบบ SaaS (Software-as-a-Service) ซึ่งเราจะมีลูกค้าหลายๆ คนใช้งานระบบของเรา ยกตัวอย่างเช่น wordpress.com ที่ลูกค้าแต่ละคนสามารถ สร้างเว็บไซต์ของตัวเองบนระบบ Wordpress ได้ครับ
- Real-Time Dashboards: แอปพลิเคชั่นที่เน้นการคำนวนข้อมูล (Analytics) แสดงออกมาเป็น Dashboard งานพวกนี้ จะต้องอาศัยการคำนวนแบบ Parallelization ซึ่งการมีหลาย Node ของ Citus จะช่วยเพิ่มประสิทธิภาพการทำงานครับ
Reference: https://docs.citusdata.com/en/v7.1/portals/use_cases.html
หลักการทำงานของ Citus
โครงสร้างของ Citus จะมี Node 2 แบบ ที่เรียกว่า
- Coordinator Node: จะเป็น Node หลักที่ Application ต่อเข้ามา ที่ Node นี้, ตัว Citus จะเก็บข้อมูล Metadata ต่างๆ ที่ระบุว่า ข้อมูลจริงๆ แล้ว เก็บไว้ที่ Worker Node ตัวไหน และสั่ง Query ต่อไปอีกทีนึง
- Worker Nodes: เป็น Node ที่ใช้ประมวลผล และเก็บข้อมูลเป็นหลัก ซึ่ง Worker Node แต่ละตัวจะเก็บข้อมูลไม่เหมือนกัน ขึ้นอยู่กับการจัดการ Sharding และ Replication
จากรูปประกอบด้านบน เราจะเห็นได้ว่า ข้อมูลจะกระจายเป็น Shard ไปอยู่ตาม Data node หรือ Worker node ต่างๆ
และเมื่อเรา Query ข้อมูล, ตัว Coordinator ก็จะส่ง Query ดังกล่าว ไปที่ Node ตัวที่มีข้อมูล
Sharding คืออะไร
อย่างที่เห็นภาพประกอบด้านบนไปนั้น ตาราง “table” จะถูกซอยแบ่งออกไปเป็น 1001, 1002, 1003, 1004… เราเรียก table ที่ซอยแล้วเหล่านี้ว่า Shards ซึ่งในแต่ละตารางที่เราซอยมานี้ จะมี Shard Key เป็นตัวกำหนดว่า ข้อมูล Record นี้ อยู่ Shard ไหน
ยกตัวอย่างการซอยตาราง (หรือที่เรียกภาษา citus ว่า การ create_distributed_table)
ด้านบนนี้เป็นคำสั่งเพื่อซอยตาราง table ออกไปเป็น shard ตาม worker ต่างๆ โดยกำหนดฟิลด์ “id” ให้เป็น shard key
เมื่อเรา Run คำสั่งด้านบนเสร็จแล้ว, ที่ตัว Citus Coordinator Node ก้จะเก็บ Metadata ไว้ว่า ค่า Hash ของ Shard Key นั้น ควรจะเก็บข้อมูลไว้ที่ Shard No อะไร, Worker Node
อยากลอง Setup Citus Cluster ต้องทำอย่างไร
หากคุณอยากลอง Setup Citus Cluster, ผมแนะนำให้ทดลองใช้ Google Cloud Platform และสร้าง Server ขึ้นมาสัก 3 ตัว (Coordinator 1 เครื่อง และ Worker Nodes 2 เครื่อง)
หลังจากนั้น ให้ลองทำตาม Tutorial นี้ครับ https://docs.citusdata.com/en/v7.1/installation/production_rhel.html
หรือหากคุณถนัด Ansible, สามารถทดลองใช้ Ansible Playbook ที่ผมเขียนเองได้เลย https://github.com/chaintng/ansible-citus ซึ่งใน Playbook นี้ จะสามารถติดตั้ง repmgr และ pgbouncer ไว้ให้ด้วยครับ (จะกล่าวขึ้น repmgr และ pgbouncer ในโอกาสต่อไป)
ข้อจำกัดของ Citus (Community Edition)
Citus ที่เป็นเวอร์ชั่น Opensource หรือ Community Edition ยังมีข้อจำกัดบางประการอยู่ ที่อาจเป็นอุปสรรคต่อการใช้งานจริงใน Production ดังนี้
- การ Rebalance Shard, กล่าวคือ เมื่อเราทำการ Add Node เข้าไปใหม่ ตัว Citus เองแม้จะรู้จัก Node นั้นแล้ว แต่ Shard ก็ยังไม่ถูก Rebalance มาที่ Node ใหม่ จำเป็นต้องสั่งการด้วยฟังก์ชั่น rebalance_table_shards() ซึ่งตอนนี้ มีเฉพาะใน Citus Enterprise Version เท่านั้นครับ
- Tenants Isolation, เนื่องจากการกระจาย Shard ในเวอร์ชั่น Community เป็นการใช้ค่า Hash, หากเมื่อไหร่ที่ Shard นั้นมีการใช้งานเพิ่มมากขึ้นกว่า Shard อื่นๆ เป็นพิเศษ เราจำเป็นต้อง Dedicate Resource ให้กับ Shard นั้นโดยเฉพาะ เพื่อไม่ให้เป็นการแย่ง Resource จาก Shard อื่นๆ ที่ไม่เกเร ซึ่งการใช้งานนี้ จำเป็นต้องเรียกคำสั่ง isolate_tenant_to_new_shard() ที่มีอยู่ในเวอร์ชั่น Enterprise เท่านั้น
ข้อมูลเพิ่มเติม
- Documentation [https://docs.citusdata.com/en/v7.1/index.html]
- Five sharding data models and which is right [https://www.citusdata.com/blog/2017/08/28/five-data-models-for-sharding/]